* src/vm/jit/codegen-common.cpp (codegen_emit): New generic version of the
[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, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25 #include "config.h"
26
27 #include <assert.h>
28 #include <stdint.h>
29
30 #include "vm/jit/s390/codegen.h"
31 #include "vm/jit/s390/emit.h"
32 #include "vm/jit/s390/md-abi.h"
33
34 #include "mm/memory.hpp"
35
36 #include "threads/lock.hpp"
37
38 #include "vm/jit/builtin.hpp"
39 #include "vm/global.h"
40 #include "vm/types.h"
41 #include "vm/options.h"
42
43 #include "vm/jit/abi.h"
44 #include "vm/jit/abi-asm.h"
45 #include "vm/jit/asmpart.h"
46 #include "vm/jit/codegen-common.hpp"
47 #include "vm/jit/emit-common.hpp"
48 #include "vm/jit/jit.hpp"
49 #include "vm/jit/patcher-common.hpp"
50 #include "vm/jit/replace.hpp"
51 #include "vm/jit/trace.hpp"
52 #include "vm/jit/trap.hpp"
53
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
219 /**
220  * Emits code updating the condition register by comparing one integer
221  * register to an immediate integer value.
222  */
223 void emit_icmp_imm(codegendata* cd, int reg, int32_t value)
224 {
225         int32_t disp;
226
227         if (N_VALID_IMM(value)) {
228                 M_ICMP_IMM(reg, value);
229         } else {
230                 disp = dseg_add_s4(cd, iptr->sx.val.i);
231                 if (N_VALID_DSEG_DISP(disp)) {
232                         N_C(s1, N_DSEG_DISP(disp), RN, REG_PV);
233                 } else {
234                         assert(reg != REG_ITMP2);
235                         ICONST(REG_ITMP2, disp);
236                         N_C(s1, -N_PV_OFFSET, REG_ITMP2, REG_PV);
237                 }
238         }
239 }
240
241
242 /* emit_trap *******************************************************************
243
244    Emit a trap instruction and return the original machine code.
245
246 *******************************************************************************/
247
248 uint32_t emit_trap(codegendata *cd)
249 {
250         uint32_t mcode;
251
252         /* Get machine code which is patched back in later. The
253            trap is 2 bytes long. */
254
255         mcode = *((u2 *) cd->mcodeptr);
256
257         M_ILL(TRAP_PATCHER);
258
259         return mcode;
260 }
261
262
263 /**
264  * Generates synchronization code to enter a monitor.
265  */
266 #if defined(ENABLE_THREADS)
267 void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset)
268 {
269         int32_t p;
270         int32_t disp;
271
272         // Get required compiler data.
273         methodinfo*  m  = jd->m;
274         codegendata* cd = jd->cd;
275
276 #if !defined(NDEBUG)
277         if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) {
278                 M_ASUB_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP);
279
280                 for (p = 0; p < INT_ARG_CNT; p++)
281                         M_IST(abi_registers_integer_argument[p], REG_SP, p * 8);
282
283                 for (p = 0; p < FLT_ARG_CNT; p++)
284                         M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8);
285
286                 syncslot_offset += (INT_ARG_CNT + FLT_ARG_CNT) * 8;
287         }
288 #endif
289
290         /* decide which monitor enter function to call */
291
292         if (m->flags & ACC_STATIC) {
293                 disp = dseg_add_address(cd, &m->clazz->object.header);
294                 M_ALD_DSEG(REG_A0, disp);
295         }
296         else {
297                 M_TEST(REG_A0);
298                 M_BNE(SZ_BRC + SZ_ILL);
299                 M_ILL(TRAP_NullPointerException);
300         }
301
302         disp = dseg_add_functionptr(cd, LOCK_monitor_enter);
303         M_ALD_DSEG(REG_ITMP2, disp);
304
305         M_AST(REG_A0, REG_SP, syncslot_offset);
306
307         M_ASUB_IMM(96, REG_SP); 
308         M_CALL(REG_ITMP2);
309         M_AADD_IMM(96, REG_SP); 
310
311 #if !defined(NDEBUG)
312         if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) {
313                 for (p = 0; p < INT_ARG_CNT; p++)
314                         M_ILD(abi_registers_integer_argument[p], REG_SP, p * 8);
315
316                 for (p = 0; p < FLT_ARG_CNT; p++)
317                         M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8);
318
319                 M_AADD_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP);
320         }
321 #endif
322 }
323 #endif
324
325
326 /**
327  * Generates synchronization code to leave a monitor.
328  */
329 #if defined(ENABLE_THREADS)
330 void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset)
331 {
332         int32_t disp;
333
334         // Get required compiler data.
335         methodinfo*  m  = jd->m;
336         codegendata* cd = jd->cd;
337
338         /* we need to save the proper return value */
339
340         methoddesc* md = m->parseddesc;
341
342         switch (md->returntype.type) {
343         case TYPE_LNG:
344                 M_IST(REG_RESULT2, REG_SP, syncslot_offset + 8 + 4);
345                 /* fall through */
346         case TYPE_INT:
347         case TYPE_ADR:
348                 M_IST(REG_RESULT , REG_SP, syncslot_offset + 8);
349                 break;
350         case TYPE_FLT:
351                 M_FST(REG_FRESULT, REG_SP, syncslot_offset + 8);
352                 break;
353         case TYPE_DBL:
354                 M_DST(REG_FRESULT, REG_SP, syncslot_offset + 8);
355                 break;
356         }
357
358         M_ALD(REG_A0, REG_SP, syncslot_offset);
359
360         disp = dseg_add_functionptr(cd, LOCK_monitor_exit);
361         M_ALD_DSEG(REG_ITMP2, disp);
362
363         M_ASUB_IMM(96, REG_SP);
364         M_CALL(REG_ITMP2);
365         M_AADD_IMM(96, REG_SP);
366
367         /* and now restore the proper return value */
368
369         switch (md->returntype.type) {
370         case TYPE_LNG:
371                 M_ILD(REG_RESULT2, REG_SP, syncslot_offset + 8 + 4);
372                 /* fall through */
373         case TYPE_INT:
374         case TYPE_ADR:
375                 M_ILD(REG_RESULT , REG_SP, syncslot_offset + 8);
376                 break;
377         case TYPE_FLT:
378                 M_FLD(REG_FRESULT, REG_SP, syncslot_offset + 8);
379                 break;
380         case TYPE_DBL:
381                 M_DLD(REG_FRESULT, REG_SP, syncslot_offset + 8);
382                 break;
383         }
384 }
385 #endif
386
387
388 /**
389  * Emit profiling code for method frequency counting.
390  */
391 #if defined(ENABLE_PROFILING)
392 void emit_profile_method(codegendata* cd, codeinfo* code)
393 {
394         M_ALD_DSEG(REG_ITMP1, CodeinfoPointer);
395         ICONST(REG_ITMP2, 1);
396         N_AL(REG_ITMP2, OFFSET(codeinfo, frequency), RN, REG_ITMP1);
397         M_IST(REG_ITMP2, REG_ITMP1, OFFSET(codeinfo, frequency));
398 }
399 #endif
400
401
402 /**
403  * Emit profiling code for basicblock frequency counting.
404  */
405 #if defined(ENABLE_PROFILING)
406 void emit_profile_basicblock(codegendata* cd, codeinfo* code, basicblock* bptr)
407 {
408         M_ALD_DSEG(REG_ITMP1, CodeinfoPointer);
409         M_ALD(REG_ITMP1, REG_ITMP1, OFFSET(codeinfo, bbfrequency));
410         ICONST(REG_ITMP2, 1);
411         N_AL(REG_ITMP2, bptr->nr * 4, RN, REG_ITMP1);
412         M_IST(REG_ITMP2, REG_ITMP1, bptr->nr * 4);
413 }
414 #endif
415
416
417 /* emit_verbosecall_enter ******************************************************
418
419    Generates the code for the call trace.
420
421 *******************************************************************************/
422
423 #if !defined(NDEBUG)
424 void emit_verbosecall_enter(jitdata *jd)
425 {
426         methodinfo   *m;
427         codeinfo     *code;
428         codegendata  *cd;
429         methoddesc   *md;
430         s4            stackframesize;
431         s4            i, off, disp, s;
432
433         m    = jd->m;
434         code = jd->code;
435         cd   = jd->cd;
436
437         md   = m->parseddesc;
438
439         /* mark trace code */
440
441         M_NOP;
442
443         /* allocate stack frame */
444
445         stackframesize = 96 + (md->paramcount * 8);
446
447         /* for leaf methods we need to store unused argument and temporary registers */
448
449         if (code_is_leafmethod(code)) {
450                 stackframesize += (ARG_CNT + TMP_CNT) * 8;
451         }
452
453         /* allocate stack frame */
454
455         M_ASUB_IMM(stackframesize, REG_SP);
456
457         /* store argument registers in array */
458
459         off = 96;
460
461         for (i = 0; i < md->paramcount; i++) {
462                 if (! md->params[i].inmemory) {
463                         s = md->params[i].regoff;
464                         switch (md->paramtypes[i].type) {
465                                 case TYPE_INT:
466                                 case TYPE_ADR:
467                                         M_IST(s, REG_SP, off);
468                                         break;
469                                 case TYPE_LNG:
470                                         M_LST(s, REG_SP, off);
471                                         break;
472                                 case TYPE_FLT:
473                                         M_FST(s, REG_SP, off);
474                                         break;
475                                 case TYPE_DBL:
476                                         M_DST(s, REG_SP, off);
477                                         break;
478                         }
479                 }
480                 off += 8;
481         }
482
483         /* save unused (currently all) argument registers for leaf methods */
484         /* save temporary registers for leaf methods */
485
486         if (code_is_leafmethod(code)) {
487
488                 for (i = 0; i < INT_ARG_CNT; ++i, off += 8) {
489                         M_IST(abi_registers_integer_argument[i], REG_SP, off);
490                 }
491
492                 for (i = 0; i < FLT_ARG_CNT; ++i, off += 8) {
493                         M_DST(abi_registers_float_argument[i], REG_SP, off);
494                 }
495
496                 for (i = 0; i < INT_TMP_CNT; ++i, off += 8) {
497                         M_IST(abi_registers_integer_temporary[i], REG_SP, off);
498                 }
499
500                 for (i = 0; i < FLT_TMP_CNT; ++i, off += 8) {
501                         M_DST(abi_registers_float_temporary[i], REG_SP, off);
502                 }
503         }
504
505         /* load arguments for trace_java_call_enter */
506
507         /* methodinfo */
508
509         disp = dseg_add_address(cd, m);
510         M_ALD_DSEG(REG_A0, disp);       
511         /* pointer to argument registers array */
512         M_LDA(REG_A1, REG_SP, 96);
513         /* pointer to on stack arguments */
514         M_LDA(REG_A2, REG_SP, stackframesize + (cd->stackframesize * 8));
515
516         /* call trace_java_call_enter */
517
518         disp = dseg_add_functionptr(cd, trace_java_call_enter);
519         M_ALD_DSEG(REG_ITMP2, disp);
520         M_CALL(REG_ITMP2);
521
522         /* restore used argument registers */
523         /* for leaf methods restore all argument and temporary registers */
524
525         if (code_is_leafmethod(code)) {
526                 off = 96 + (8 * md->paramcount);
527
528                 for (i = 0; i < INT_ARG_CNT; ++i, off += 8) {
529                         M_ILD(abi_registers_integer_argument[i], REG_SP, off);
530                 }
531
532                 for (i = 0; i < FLT_ARG_CNT; ++i, off += 8) {
533                         M_DLD(abi_registers_float_argument[i], REG_SP, off);
534                 }
535
536                 for (i = 0; i < INT_TMP_CNT; ++i, off += 8) {
537                         M_ILD(abi_registers_integer_temporary[i], REG_SP, off);
538                 }
539
540                 for (i = 0; i < FLT_TMP_CNT; ++i, off += 8) {
541                         M_DLD(abi_registers_float_temporary[i], REG_SP, off);
542                 }
543         } else {
544                 off = 96;
545
546                 for (i = 0; i < md->paramcount; i++) {
547                         if (! md->params[i].inmemory) {
548                                 s = md->params[i].regoff;
549                                 switch (md->paramtypes[i].type) {
550                                         case TYPE_INT:
551                                         case TYPE_ADR:
552                                                 M_ILD(s, REG_SP, off);
553                                                 break;
554                                         case TYPE_LNG:
555                                                 M_LLD(s, REG_SP, off);
556                                                 break;
557                                         case TYPE_FLT:
558                                                 M_FLD(s, REG_SP, off);
559                                                 break;
560                                         case TYPE_DBL:
561                                                 M_DLD(s, REG_SP, off);
562                                                 break;
563                                 }
564                         }
565                         off += 8;
566                 }
567         }
568
569         /* remove stack frame */
570
571         M_AADD_IMM(stackframesize, REG_SP);
572
573         /* mark trace code */
574
575         M_NOP;
576
577 }
578 #endif /* !defined(NDEBUG) */
579
580
581 /* emit_verbosecall_exit *******************************************************
582
583    Generates the code for the call trace.
584
585 *******************************************************************************/
586
587 #if !defined(NDEBUG)
588 void emit_verbosecall_exit(jitdata *jd)
589 {
590         methodinfo   *m;
591         codegendata  *cd;
592         s4            disp;
593         s4            stackframesize;
594         s4            off;
595         s4            t;
596
597         m  = jd->m;
598         cd = jd->cd;
599         t = m->parseddesc->returntype.type;
600
601         /* mark trace code */
602
603         M_NOP;
604
605         /* allocate stackframe */
606
607         stackframesize = 96 + (1 * 8);
608         M_ASUB_IMM(stackframesize, REG_SP);
609
610         off = 96;
611
612         /* store return values in array */
613
614         if (IS_INT_LNG_TYPE(t)) {
615                 if (IS_2_WORD_TYPE(t)) {
616                         M_LST(REG_RESULT_PACKED, REG_SP, off);
617                 } else {
618                         M_IST(REG_RESULT, REG_SP, off);
619                 }
620         } else {
621                 M_DST(REG_FRESULT, REG_SP, off);
622         }
623
624         /* call trace_java_call_exit */
625
626         disp = dseg_add_address(cd, m);
627         M_ALD_DSEG(REG_A0, disp);
628         M_LDA(REG_A1, REG_SP, off);
629         disp = dseg_add_functionptr(cd, trace_java_call_exit);
630         M_ALD_DSEG(REG_ITMP2, disp);
631         M_CALL(REG_ITMP2);
632
633         /* restore return value */
634
635         if (IS_INT_LNG_TYPE(t)) {
636                 if (IS_2_WORD_TYPE(t)) {
637                         M_LLD(REG_RESULT_PACKED, REG_SP, off);
638                 } else {
639                         M_ILD(REG_RESULT, REG_SP, off);
640                 }
641         } else {
642                 M_DLD(REG_FRESULT, REG_SP, off);
643         }
644
645         /* remove stackframe */
646
647         M_AADD_IMM(stackframesize, REG_SP);
648
649         /* mark trace code */
650
651         M_NOP;
652 }
653 #endif /* !defined(NDEBUG) */
654
655
656 /* emit_load_high **************************************************************
657
658    Emits a possible load of the high 32-bits of an operand.
659
660 *******************************************************************************/
661
662 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
663 {
664         codegendata  *cd;
665         s4            disp;
666         s4            reg;
667
668         assert(src->type == TYPE_LNG);
669
670         /* get required compiler data */
671
672         cd = jd->cd;
673
674         if (IS_INMEMORY(src->flags)) {
675                 COUNT_SPILLS;
676
677                 disp = src->vv.regoff;
678
679                 M_ILD(tempreg, REG_SP, disp);
680
681                 reg = tempreg;
682         }
683         else
684                 reg = GET_HIGH_REG(src->vv.regoff);
685
686         return reg;
687 }
688
689 /* emit_load_low ***************************************************************
690
691    Emits a possible load of the low 32-bits of an operand.
692
693 *******************************************************************************/
694
695 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
696 {
697         codegendata  *cd;
698         s4            disp;
699         s4            reg;
700
701         assert(src->type == TYPE_LNG);
702
703         /* get required compiler data */
704
705         cd = jd->cd;
706
707         if (IS_INMEMORY(src->flags)) {
708                 COUNT_SPILLS;
709
710                 disp = src->vv.regoff;
711
712                 M_ILD(tempreg, REG_SP, disp + 4);
713
714                 reg = tempreg;
715         }
716         else
717                 reg = GET_LOW_REG(src->vv.regoff);
718
719         return reg;
720 }
721
722 s4 emit_load_s1_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
723         codegendata *cd = jd->cd;
724         s4 reg = emit_load_s1(jd, iptr, tempreg);
725         if (reg == notreg) {
726                 if (IS_FLT_DBL_TYPE(VAROP(iptr->s1)->type)) {
727                         M_FMOV(reg, tempreg);
728                 } else {
729                         M_MOV(reg, tempreg);
730                 }
731                 return tempreg;
732         } else {
733                 return reg;
734         }
735 }
736
737 s4 emit_load_s2_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
738         codegendata *cd = jd->cd;
739         s4 reg = emit_load_s2(jd, iptr, tempreg);
740         if (reg == notreg) {
741                 if (IS_FLT_DBL_TYPE(VAROP(iptr->sx.s23.s2)->type)) {
742                         M_FMOV(reg, tempreg);
743                 } else {
744                         M_MOV(reg, tempreg);
745                 }
746                 return tempreg;
747         } else {
748                 return reg;
749         }
750 }
751
752 void emit_copy_dst(jitdata *jd, instruction *iptr, s4 dtmpreg) {
753         codegendata *cd;
754         varinfo *dst;
755         cd = jd->cd;
756         dst = VAROP(iptr->dst);
757         if (! IS_INMEMORY(dst->flags)) {
758                 if (dst->vv.regoff != dtmpreg) {
759                         if (IS_FLT_DBL_TYPE(dst->type)) {
760                                 M_FLTMOVE(dtmpreg, dst->vv.regoff);
761                         } else if (IS_2_WORD_TYPE(dst->type)) {
762                                 M_LNGMOVE(dtmpreg, dst->vv.regoff);
763                         } else {
764                                 M_INTMOVE(dtmpreg, dst->vv.regoff);
765                         }
766                 }
767         }
768 }
769
770 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt) {
771
772         s4 branchdisp = disp;
773         s4 branchmpc;
774         u1 *ref;
775
776         if (N_VALID_BRANCH(branchdisp)) {
777
778                 /* valid displacement */
779
780                 switch (condition) {
781                         case BRANCH_EQ:
782                                 M_BEQ(branchdisp);
783                                 break;
784                         case BRANCH_NE:
785                                 M_BNE(branchdisp);
786                                 break;
787                         case BRANCH_LT:
788                                 M_BLT(branchdisp);
789                                 break;
790                         case BRANCH_GE:
791                                 M_BGE(branchdisp);
792                                 break;
793                         case BRANCH_GT:
794                                 M_BGT(branchdisp);
795                                 break;
796                         case BRANCH_LE:
797                                 M_BLE(branchdisp);
798                                 break;
799                         case BRANCH_UNCONDITIONAL:
800                                 M_BR(branchdisp);
801                                 break;
802                         default:
803                                 vm_abort("emit_branch: unknown condition %d", condition);
804                 }
805         } else {
806
807                 /* If LONGBRANCHES is not set, the flag and the error flag */
808
809                 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
810                         cd->flags |= (CODEGENDATA_FLAG_ERROR |
811                                 CODEGENDATA_FLAG_LONGBRANCHES);
812                 }
813
814                 /* If error flag is set, do nothing. The method has to be recompiled. */
815
816                 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd) && CODEGENDATA_HAS_FLAG_ERROR(cd)) {
817                         return;
818                 }
819
820                 /* Patch the displacement to branch over the actual branch manually
821                  * to not get yet more nops.
822                  */
823
824                 branchmpc = cd->mcodeptr - cd->mcodebase;
825                 ref = cd->mcodeptr;
826
827                 switch (condition) {
828                         case BRANCH_EQ:
829                                 M_BNE(0);
830                                 break;
831                         case BRANCH_NE:
832                                 M_BEQ(0);
833                                 break;
834                         case BRANCH_LT:
835                                 M_BGE(0);
836                                 break;
837                         case BRANCH_GE:
838                                 M_BLT(0);
839                                 break;
840                         case BRANCH_GT:
841                                 M_BLE(0);
842                                 break;
843                         case BRANCH_LE:
844                                 M_BGT(0);
845                                 break;
846                         case BRANCH_UNCONDITIONAL:
847                                 /* fall through, no displacement to patch */
848                                 ref = NULL;
849                                 break;
850                         default:
851                                 vm_abort("emit_branch: unknown condition %d", condition);
852                 }
853
854                 /* The actual long branch */
855
856                 disp = dseg_add_s4(cd, branchmpc + disp - N_PV_OFFSET);
857                 M_ILD_DSEG(REG_ITMP2, disp);
858                 M_AADD(REG_PV, REG_ITMP2);
859                 M_JMP(RN, REG_ITMP2);
860
861                 /* Patch back the displacement */
862
863                 N_BRC_BACK_PATCH(ref);
864         }
865 }
866
867 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
868 {
869         if (INSTRUCTION_MUST_CHECK(iptr)) {
870                 M_TEST(reg);
871                 M_BNE(SZ_BRC + SZ_ILL);
872                 M_ILL(TRAP_ArithmeticException);
873         }
874 }
875
876 /* emit_arrayindexoutofbounds_check ********************************************
877
878    Emit a ArrayIndexOutOfBoundsException check.
879
880 *******************************************************************************/
881
882 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
883 {
884         if (INSTRUCTION_MUST_CHECK(iptr)) {
885                 /* Size is s4, >= 0
886                  * Do unsigned comparison to catch negative indexes.
887                  */
888                 N_CL(s2, OFFSET(java_array_t, size), RN, s1);
889         M_BLT(SZ_BRC + SZ_ILL);
890                 M_ILL2(s2, TRAP_ArrayIndexOutOfBoundsException);
891         }
892 }
893
894
895 /* emit_arraystore_check *******************************************************
896
897    Emit an ArrayStoreException check.
898
899 *******************************************************************************/
900
901 void emit_arraystore_check(codegendata *cd, instruction *iptr)
902 {
903         if (INSTRUCTION_MUST_CHECK(iptr)) {
904                 M_TEST(REG_RESULT);
905                 M_BNE(SZ_BRC + SZ_ILL);
906                 M_ILL(TRAP_ArrayStoreException);
907         }
908 }
909
910
911 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1) {
912         if (INSTRUCTION_MUST_CHECK(iptr)) {
913                 if (reg != RN) {
914                         M_TEST(reg);
915                 }
916                 switch (condition) {
917                         case BRANCH_LE:
918                                 M_BGT(SZ_BRC + SZ_ILL);
919                                 break;
920                         case BRANCH_EQ:
921                                 M_BNE(SZ_BRC + SZ_ILL);
922                                 break;
923                         case BRANCH_GT:
924                                 M_BLE(SZ_BRC + SZ_ILL);
925                                 break;
926                         default:
927                                 vm_abort("emit_classcast_check: unknown condition %d", condition);
928                 }
929                 M_ILL2(s1, TRAP_ClassCastException);
930         }
931 }
932
933 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
934 {
935         if (INSTRUCTION_MUST_CHECK(iptr)) {
936                 M_TEST(reg);
937                 M_BNE(SZ_BRC + SZ_ILL);
938                 M_ILL(TRAP_NullPointerException);
939         }
940 }
941
942 void emit_exception_check(codegendata *cd, instruction *iptr)
943 {
944         if (INSTRUCTION_MUST_CHECK(iptr)) {
945                 M_TEST(REG_RESULT);
946                 M_BNE(SZ_BRC + SZ_ILL);
947                 M_ILL(TRAP_CHECK_EXCEPTION);
948         }
949 }
950
951 void emit_recompute_pv(codegendata *cd) {
952         s4 offset, offset_imm;
953
954         /*
955         N_BASR(REG_PV, RN);
956         disp = (s4) (cd->mcodeptr - cd->mcodebase);
957         M_ASUB_IMM32(disp, REG_ITMP1, REG_PV);
958         */
959
960         /* If the offset from the method start does not fit into an immediate
961          * value, we can't put it into the data segment!
962          */
963
964         /* Displacement from start of method to here */
965
966         offset = (s4) (cd->mcodeptr - cd->mcodebase);
967         offset_imm = -offset - SZ_BASR + N_PV_OFFSET;
968
969         if (N_VALID_IMM(offset_imm)) {
970                 /* Get program counter */
971                 N_BASR(REG_PV, RN);
972                 /* Substract displacement */
973                 M_AADD_IMM(offset_imm, REG_PV);
974         } else {
975                 /* Save program counter and jump over displacement in instruction flow */
976                 N_BRAS(REG_PV, SZ_BRAS + SZ_LONG);
977                 /* Place displacement here */
978                 /* REG_PV points now exactly to this position */
979                 N_LONG(-offset - SZ_BRAS + N_PV_OFFSET);
980                 /* Substract *(REG_PV) from REG_PV */
981                 N_A(REG_PV, 0, RN, REG_PV);
982         }
983 }
984
985 /* emit_trap_compiler **********************************************************
986
987    Emit a trap instruction which calls the JIT compiler.
988
989 *******************************************************************************/
990
991 void emit_trap_compiler(codegendata *cd)
992 {
993         M_ILL2(REG_METHODPTR, TRAP_COMPILER);
994 }
995
996 /*
997  * These are local overrides for various environment variables in Emacs.
998  * Please do not remove this and leave it at the end of the file, where
999  * Emacs will automagically detect them.
1000  * ---------------------------------------------------------------------
1001  * Local variables:
1002  * mode: c
1003  * indent-tabs-mode: t
1004  * c-basic-offset: 4
1005  * tab-width: 4
1006  * End:
1007  */