Merged with tip.
[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.h"
35
36 #include "threads/lock-common.h"
37
38 #include "vm/builtin.h"
39 #include "vm/exceptions.h"
40 #include "vm/global.h"
41 #include "vm/types.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.h"
47 #include "vm/jit/emit-common.h"
48 #include "vm/jit/jit.h"
49 #include "vm/jit/patcher-common.h"
50 #include "vm/jit/replace.h"
51 #include "vm/jit/trace.h"
52 #include "vm/jit/trap.h"
53
54 #include "vmcore/options.h"
55
56
57 /* emit_load *******************************************************************
58
59    Emits a possible load of an operand.
60
61 *******************************************************************************/
62
63 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
64 {
65         codegendata *cd;
66         s4           disp;
67         s4           reg;
68
69         /* get required compiler data */
70
71         cd = jd->cd;
72
73         if (IS_INMEMORY(src->flags)) {
74                 COUNT_SPILLS;
75
76                 disp = src->vv.regoff;
77
78                 if (IS_FLT_DBL_TYPE(src->type)) {
79                         if (IS_2_WORD_TYPE(src->type))
80                                 M_DLD(tempreg, REG_SP, disp);
81                         else
82                                 M_FLD(tempreg, REG_SP, disp);
83                 }
84                 else {
85                         if (IS_2_WORD_TYPE(src->type))
86                                 M_LLD(tempreg, REG_SP, disp);
87                         else
88                                 M_ILD(tempreg, REG_SP, disp);
89                 }
90
91                 reg = tempreg;
92         }
93         else
94                 reg = src->vv.regoff;
95
96         return reg;
97 }
98
99
100 /* emit_store ******************************************************************
101
102    This function generates the code to store the result of an
103    operation back into a spilled pseudo-variable.  If the
104    pseudo-variable has not been spilled in the first place, this
105    function will generate nothing.
106     
107 *******************************************************************************/
108
109 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
110 {
111         codegendata *cd;
112
113         /* get required compiler data */
114
115         cd = jd->cd;
116
117         if (IS_INMEMORY(dst->flags)) {
118                 COUNT_SPILLS;
119
120                 if (IS_FLT_DBL_TYPE(dst->type)) {
121                         if (IS_2_WORD_TYPE(dst->type))
122                                 M_DST(d, REG_SP, dst->vv.regoff);
123                         else
124                                 M_FST(d, REG_SP, dst->vv.regoff);
125                 }
126                 else {
127                         if (IS_2_WORD_TYPE(dst->type))
128                                 M_LST(d, REG_SP, dst->vv.regoff);
129                         else
130                                 M_IST(d, REG_SP, dst->vv.regoff);
131                 }
132         }
133 }
134
135
136 /* emit_copy *******************************************************************
137
138    Generates a register/memory to register/memory copy.
139
140 *******************************************************************************/
141
142 void emit_copy(jitdata *jd, instruction *iptr)
143 {
144         codegendata *cd;
145         varinfo     *src;
146         varinfo     *dst;
147         s4           s1, d;
148
149         /* get required compiler data */
150
151         cd = jd->cd;
152
153         /* get source and destination variables */
154
155         src = VAROP(iptr->s1);
156         dst = VAROP(iptr->dst);
157
158         if ((src->vv.regoff != dst->vv.regoff) ||
159                 ((src->flags ^ dst->flags) & INMEMORY)) {
160
161                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
162                         /* emit nothing, as the value won't be used anyway */
163                         return;
164                 }
165
166                 if (IS_INMEMORY(src->flags) && IS_INMEMORY(dst->flags)) {
167                         if (IS_2_WORD_TYPE(src->type)) {
168                                 N_MVC(dst->vv.regoff, 8, REG_SP, src->vv.regoff, REG_SP);
169                         } else {
170                                 N_MVC(dst->vv.regoff, 4, REG_SP, src->vv.regoff, REG_SP);
171                         }
172                 } else {
173
174                         /* If one of the variables resides in memory, we can eliminate
175                            the register move from/to the temporary register with the
176                            order of getting the destination register and the load. */
177
178                         if (IS_INMEMORY(src->flags)) {
179                                 if (IS_FLT_DBL_TYPE(dst->type)) {
180                                         d = codegen_reg_of_var(iptr->opc, dst, REG_FTMP1);
181                                 } else {
182                                         if (IS_2_WORD_TYPE(dst->type)) {
183                                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
184                                         } else {
185                                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
186                                         }
187                                 }
188                                 s1 = emit_load(jd, iptr, src, d);
189                         }
190                         else {
191                                 if (IS_FLT_DBL_TYPE(src->type)) {
192                                         s1 = emit_load(jd, iptr, src, REG_FTMP1);
193                                 } else {
194                                         if (IS_2_WORD_TYPE(src->type)) {
195                                                 s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
196                                         } else {
197                                                 s1 = emit_load(jd, iptr, src, REG_ITMP1);
198                                         }
199                                 }
200                                 d = codegen_reg_of_var(iptr->opc, dst, s1);
201                         }
202
203                         if (s1 != d) {
204                                 if (IS_FLT_DBL_TYPE(src->type)) {
205                                         M_FMOV(s1, d);
206                                 } else {
207                                         if (IS_2_WORD_TYPE(src->type)) {
208                                                 M_LNGMOVE(s1, d);
209                                         } else {
210                                                 M_MOV(s1, d);
211                                         }
212                                 }
213                         }
214
215                         emit_store(jd, iptr, dst, d);
216                 }
217         }
218 }
219
220 /* emit_trap *******************************************************************
221
222    Emit a trap instruction and return the original machine code.
223
224 *******************************************************************************/
225
226 uint32_t emit_trap(codegendata *cd)
227 {
228         uint32_t mcode;
229
230         /* Get machine code which is patched back in later. The
231            trap is 2 bytes long. */
232
233         mcode = *((u2 *) cd->mcodeptr);
234
235         M_ILL(TRAP_PATCHER);
236
237         return mcode;
238 }
239
240
241 /* emit_verbosecall_enter ******************************************************
242
243    Generates the code for the call trace.
244
245 *******************************************************************************/
246
247 #if !defined(NDEBUG)
248 void emit_verbosecall_enter(jitdata *jd)
249 {
250         methodinfo   *m;
251         codeinfo     *code;
252         codegendata  *cd;
253         methoddesc   *md;
254         s4            stackframesize;
255         s4            i, off, disp, s;
256
257         m    = jd->m;
258         code = jd->code;
259         cd   = jd->cd;
260
261         md   = m->parseddesc;
262
263         /* mark trace code */
264
265         M_NOP;
266
267         /* allocate stack frame */
268
269         stackframesize = 96 + (md->paramcount * 8);
270
271         /* for leaf methods we need to store unused argument and temporary registers */
272
273         if (code_is_leafmethod(code)) {
274                 stackframesize += (ARG_CNT + TMP_CNT) * 8;
275         }
276
277         /* allocate stack frame */
278
279         M_ASUB_IMM(stackframesize, REG_SP);
280
281         /* store argument registers in array */
282
283         off = 96;
284
285         for (i = 0; i < md->paramcount; i++) {
286                 if (! md->params[i].inmemory) {
287                         s = md->params[i].regoff;
288                         switch (md->paramtypes[i].type) {
289                                 case TYPE_INT:
290                                 case TYPE_ADR:
291                                         M_IST(s, REG_SP, off);
292                                         break;
293                                 case TYPE_LNG:
294                                         M_LST(s, REG_SP, off);
295                                         break;
296                                 case TYPE_FLT:
297                                         M_FST(s, REG_SP, off);
298                                         break;
299                                 case TYPE_DBL:
300                                         M_DST(s, REG_SP, off);
301                                         break;
302                         }
303                 }
304                 off += 8;
305         }
306
307         /* save unused (currently all) argument registers for leaf methods */
308         /* save temporary registers for leaf methods */
309
310         if (code_is_leafmethod(code)) {
311
312                 for (i = 0; i < INT_ARG_CNT; ++i, off += 8) {
313                         M_IST(abi_registers_integer_argument[i], REG_SP, off);
314                 }
315
316                 for (i = 0; i < FLT_ARG_CNT; ++i, off += 8) {
317                         M_DST(abi_registers_float_argument[i], REG_SP, off);
318                 }
319
320                 for (i = 0; i < INT_TMP_CNT; ++i, off += 8) {
321                         M_IST(abi_registers_integer_temporary[i], REG_SP, off);
322                 }
323
324                 for (i = 0; i < FLT_TMP_CNT; ++i, off += 8) {
325                         M_DST(abi_registers_float_temporary[i], REG_SP, off);
326                 }
327         }
328
329         /* load arguments for trace_java_call_enter */
330
331         /* methodinfo */
332
333         disp = dseg_add_address(cd, m);
334         M_ALD_DSEG(REG_A0, disp);       
335         /* pointer to argument registers array */
336         M_LDA(REG_A1, REG_SP, 96);
337         /* pointer to on stack arguments */
338         M_LDA(REG_A2, REG_SP, stackframesize + (cd->stackframesize * 8));
339
340         /* call trace_java_call_enter */
341
342         disp = dseg_add_functionptr(cd, trace_java_call_enter);
343         M_ALD_DSEG(REG_ITMP2, disp);
344         M_CALL(REG_ITMP2);
345
346         /* restore used argument registers */
347         /* for leaf methods restore all argument and temporary registers */
348
349         if (code_is_leafmethod(code)) {
350                 off = 96 + (8 * md->paramcount);
351
352                 for (i = 0; i < INT_ARG_CNT; ++i, off += 8) {
353                         M_ILD(abi_registers_integer_argument[i], REG_SP, off);
354                 }
355
356                 for (i = 0; i < FLT_ARG_CNT; ++i, off += 8) {
357                         M_DLD(abi_registers_float_argument[i], REG_SP, off);
358                 }
359
360                 for (i = 0; i < INT_TMP_CNT; ++i, off += 8) {
361                         M_ILD(abi_registers_integer_temporary[i], REG_SP, off);
362                 }
363
364                 for (i = 0; i < FLT_TMP_CNT; ++i, off += 8) {
365                         M_DLD(abi_registers_float_temporary[i], REG_SP, off);
366                 }
367         } else {
368                 off = 96;
369
370                 for (i = 0; i < md->paramcount; i++) {
371                         if (! md->params[i].inmemory) {
372                                 s = md->params[i].regoff;
373                                 switch (md->paramtypes[i].type) {
374                                         case TYPE_INT:
375                                         case TYPE_ADR:
376                                                 M_ILD(s, REG_SP, off);
377                                                 break;
378                                         case TYPE_LNG:
379                                                 M_LLD(s, REG_SP, off);
380                                                 break;
381                                         case TYPE_FLT:
382                                                 M_FLD(s, REG_SP, off);
383                                                 break;
384                                         case TYPE_DBL:
385                                                 M_DLD(s, REG_SP, off);
386                                                 break;
387                                 }
388                         }
389                         off += 8;
390                 }
391         }
392
393         /* remove stack frame */
394
395         M_AADD_IMM(stackframesize, REG_SP);
396
397         /* mark trace code */
398
399         M_NOP;
400
401 }
402 #endif /* !defined(NDEBUG) */
403
404
405 /* emit_verbosecall_exit *******************************************************
406
407    Generates the code for the call trace.
408
409 *******************************************************************************/
410
411 #if !defined(NDEBUG)
412 void emit_verbosecall_exit(jitdata *jd)
413 {
414         methodinfo   *m;
415         codegendata  *cd;
416         s4            disp;
417         s4            stackframesize;
418         s4            off;
419         s4            t;
420
421         m  = jd->m;
422         cd = jd->cd;
423         t = m->parseddesc->returntype.type;
424
425         /* mark trace code */
426
427         M_NOP;
428
429         /* allocate stackframe */
430
431         stackframesize = 96 + (1 * 8);
432         M_ASUB_IMM(stackframesize, REG_SP);
433
434         off = 96;
435
436         /* store return values in array */
437
438         if (IS_INT_LNG_TYPE(t)) {
439                 if (IS_2_WORD_TYPE(t)) {
440                         M_LST(REG_RESULT_PACKED, REG_SP, off);
441                 } else {
442                         M_IST(REG_RESULT, REG_SP, off);
443                 }
444         } else {
445                 M_DST(REG_FRESULT, REG_SP, off);
446         }
447
448         /* call trace_java_call_exit */
449
450         disp = dseg_add_address(cd, m);
451         M_ALD_DSEG(REG_A0, disp);
452         M_LDA(REG_A1, REG_SP, off);
453         disp = dseg_add_functionptr(cd, trace_java_call_exit);
454         M_ALD_DSEG(REG_ITMP2, disp);
455         M_CALL(REG_ITMP2);
456
457         /* restore return value */
458
459         if (IS_INT_LNG_TYPE(t)) {
460                 if (IS_2_WORD_TYPE(t)) {
461                         M_LLD(REG_RESULT_PACKED, REG_SP, off);
462                 } else {
463                         M_ILD(REG_RESULT, REG_SP, off);
464                 }
465         } else {
466                 M_DLD(REG_FRESULT, REG_SP, off);
467         }
468
469         /* remove stackframe */
470
471         M_AADD_IMM(stackframesize, REG_SP);
472
473         /* mark trace code */
474
475         M_NOP;
476 }
477 #endif /* !defined(NDEBUG) */
478
479
480 /* emit_load_high **************************************************************
481
482    Emits a possible load of the high 32-bits of an operand.
483
484 *******************************************************************************/
485
486 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
487 {
488         codegendata  *cd;
489         s4            disp;
490         s4            reg;
491
492         assert(src->type == TYPE_LNG);
493
494         /* get required compiler data */
495
496         cd = jd->cd;
497
498         if (IS_INMEMORY(src->flags)) {
499                 COUNT_SPILLS;
500
501                 disp = src->vv.regoff;
502
503                 M_ILD(tempreg, REG_SP, disp);
504
505                 reg = tempreg;
506         }
507         else
508                 reg = GET_HIGH_REG(src->vv.regoff);
509
510         return reg;
511 }
512
513 /* emit_load_low ***************************************************************
514
515    Emits a possible load of the low 32-bits of an operand.
516
517 *******************************************************************************/
518
519 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
520 {
521         codegendata  *cd;
522         s4            disp;
523         s4            reg;
524
525         assert(src->type == TYPE_LNG);
526
527         /* get required compiler data */
528
529         cd = jd->cd;
530
531         if (IS_INMEMORY(src->flags)) {
532                 COUNT_SPILLS;
533
534                 disp = src->vv.regoff;
535
536                 M_ILD(tempreg, REG_SP, disp + 4);
537
538                 reg = tempreg;
539         }
540         else
541                 reg = GET_LOW_REG(src->vv.regoff);
542
543         return reg;
544 }
545
546 s4 emit_load_s1_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
547         codegendata *cd = jd->cd;
548         s4 reg = emit_load_s1(jd, iptr, tempreg);
549         if (reg == notreg) {
550                 if (IS_FLT_DBL_TYPE(VAROP(iptr->s1)->type)) {
551                         M_FMOV(reg, tempreg);
552                 } else {
553                         M_MOV(reg, tempreg);
554                 }
555                 return tempreg;
556         } else {
557                 return reg;
558         }
559 }
560
561 s4 emit_load_s2_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
562         codegendata *cd = jd->cd;
563         s4 reg = emit_load_s2(jd, iptr, tempreg);
564         if (reg == notreg) {
565                 if (IS_FLT_DBL_TYPE(VAROP(iptr->sx.s23.s2)->type)) {
566                         M_FMOV(reg, tempreg);
567                 } else {
568                         M_MOV(reg, tempreg);
569                 }
570                 return tempreg;
571         } else {
572                 return reg;
573         }
574 }
575
576 void emit_copy_dst(jitdata *jd, instruction *iptr, s4 dtmpreg) {
577         codegendata *cd;
578         varinfo *dst;
579         cd = jd->cd;
580         dst = VAROP(iptr->dst);
581         if (! IS_INMEMORY(dst->flags)) {
582                 if (dst->vv.regoff != dtmpreg) {
583                         if (IS_FLT_DBL_TYPE(dst->type)) {
584                                 M_FLTMOVE(dtmpreg, dst->vv.regoff);
585                         } else if (IS_2_WORD_TYPE(dst->type)) {
586                                 M_LNGMOVE(dtmpreg, dst->vv.regoff);
587                         } else {
588                                 M_INTMOVE(dtmpreg, dst->vv.regoff);
589                         }
590                 }
591         }
592 }
593
594 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt) {
595
596         s4 branchdisp = disp;
597         s4 branchmpc;
598         u1 *ref;
599
600         if (N_VALID_BRANCH(branchdisp)) {
601
602                 /* valid displacement */
603
604                 switch (condition) {
605                         case BRANCH_EQ:
606                                 M_BEQ(branchdisp);
607                                 break;
608                         case BRANCH_NE:
609                                 M_BNE(branchdisp);
610                                 break;
611                         case BRANCH_LT:
612                                 M_BLT(branchdisp);
613                                 break;
614                         case BRANCH_GE:
615                                 M_BGE(branchdisp);
616                                 break;
617                         case BRANCH_GT:
618                                 M_BGT(branchdisp);
619                                 break;
620                         case BRANCH_LE:
621                                 M_BLE(branchdisp);
622                                 break;
623                         case BRANCH_UNCONDITIONAL:
624                                 M_BR(branchdisp);
625                                 break;
626                         default:
627                                 vm_abort("emit_branch: unknown condition %d", condition);
628                 }
629         } else {
630
631                 /* If LONGBRANCHES is not set, the flag and the error flag */
632
633                 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
634                         cd->flags |= (CODEGENDATA_FLAG_ERROR |
635                                 CODEGENDATA_FLAG_LONGBRANCHES);
636                 }
637
638                 /* If error flag is set, do nothing. The method has to be recompiled. */
639
640                 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd) && CODEGENDATA_HAS_FLAG_ERROR(cd)) {
641                         return;
642                 }
643
644                 /* Patch the displacement to branch over the actual branch manually
645                  * to not get yet more nops.
646                  */
647
648                 branchmpc = cd->mcodeptr - cd->mcodebase;
649                 ref = cd->mcodeptr;
650
651                 switch (condition) {
652                         case BRANCH_EQ:
653                                 M_BNE(0);
654                                 break;
655                         case BRANCH_NE:
656                                 M_BEQ(0);
657                                 break;
658                         case BRANCH_LT:
659                                 M_BGE(0);
660                                 break;
661                         case BRANCH_GE:
662                                 M_BLT(0);
663                                 break;
664                         case BRANCH_GT:
665                                 M_BLE(0);
666                                 break;
667                         case BRANCH_LE:
668                                 M_BGT(0);
669                                 break;
670                         case BRANCH_UNCONDITIONAL:
671                                 /* fall through, no displacement to patch */
672                                 ref = NULL;
673                                 break;
674                         default:
675                                 vm_abort("emit_branch: unknown condition %d", condition);
676                 }
677
678                 /* The actual long branch */
679
680                 disp = dseg_add_s4(cd, branchmpc + disp - N_PV_OFFSET);
681                 M_ILD_DSEG(REG_ITMP2, disp);
682                 M_AADD(REG_PV, REG_ITMP2);
683                 M_JMP(RN, REG_ITMP2);
684
685                 /* Patch back the displacement */
686
687                 N_BRC_BACK_PATCH(ref);
688         }
689 }
690
691 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
692 {
693         if (INSTRUCTION_MUST_CHECK(iptr)) {
694                 M_TEST(reg);
695                 M_BNE(SZ_BRC + SZ_ILL);
696                 M_ILL(TRAP_ArithmeticException);
697         }
698 }
699
700 /* emit_arrayindexoutofbounds_check ********************************************
701
702    Emit a ArrayIndexOutOfBoundsException check.
703
704 *******************************************************************************/
705
706 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
707 {
708         if (INSTRUCTION_MUST_CHECK(iptr)) {
709                 /* Size is s4, >= 0
710                  * Do unsigned comparison to catch negative indexes.
711                  */
712                 N_CL(s2, OFFSET(java_array_t, size), RN, s1);
713         M_BLT(SZ_BRC + SZ_ILL);
714                 M_ILL2(s2, TRAP_ArrayIndexOutOfBoundsException);
715         }
716 }
717
718
719 /* emit_arraystore_check *******************************************************
720
721    Emit an ArrayStoreException check.
722
723 *******************************************************************************/
724
725 void emit_arraystore_check(codegendata *cd, instruction *iptr)
726 {
727         if (INSTRUCTION_MUST_CHECK(iptr)) {
728                 M_TEST(REG_RESULT);
729                 M_BNE(SZ_BRC + SZ_ILL);
730                 M_ILL(TRAP_ArrayStoreException);
731         }
732 }
733
734
735 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1) {
736         if (INSTRUCTION_MUST_CHECK(iptr)) {
737                 if (reg != RN) {
738                         M_TEST(reg);
739                 }
740                 switch (condition) {
741                         case BRANCH_LE:
742                                 M_BGT(SZ_BRC + SZ_ILL);
743                                 break;
744                         case BRANCH_EQ:
745                                 M_BNE(SZ_BRC + SZ_ILL);
746                                 break;
747                         case BRANCH_GT:
748                                 M_BLE(SZ_BRC + SZ_ILL);
749                                 break;
750                         default:
751                                 vm_abort("emit_classcast_check: unknown condition %d", condition);
752                 }
753                 M_ILL2(s1, TRAP_ClassCastException);
754         }
755 }
756
757 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
758 {
759         if (INSTRUCTION_MUST_CHECK(iptr)) {
760                 M_TEST(reg);
761                 M_BNE(SZ_BRC + SZ_ILL);
762                 M_ILL(TRAP_NullPointerException);
763         }
764 }
765
766 void emit_exception_check(codegendata *cd, instruction *iptr)
767 {
768         if (INSTRUCTION_MUST_CHECK(iptr)) {
769                 M_TEST(REG_RESULT);
770                 M_BNE(SZ_BRC + SZ_ILL);
771                 M_ILL(TRAP_CHECK_EXCEPTION);
772         }
773 }
774
775 void emit_restore_pv(codegendata *cd) {
776         s4 offset, offset_imm;
777
778         /*
779         N_BASR(REG_PV, RN);
780         disp = (s4) (cd->mcodeptr - cd->mcodebase);
781         M_ASUB_IMM32(disp, REG_ITMP1, REG_PV);
782         */
783
784         /* If the offset from the method start does not fit into an immediate
785          * value, we can't put it into the data segment!
786          */
787
788         /* Displacement from start of method to here */
789
790         offset = (s4) (cd->mcodeptr - cd->mcodebase);
791         offset_imm = -offset - SZ_BASR + N_PV_OFFSET;
792
793         if (N_VALID_IMM(offset_imm)) {
794                 /* Get program counter */
795                 N_BASR(REG_PV, RN);
796                 /* Substract displacement */
797                 M_AADD_IMM(offset_imm, REG_PV);
798         } else {
799                 /* Save program counter and jump over displacement in instruction flow */
800                 N_BRAS(REG_PV, SZ_BRAS + SZ_LONG);
801                 /* Place displacement here */
802                 /* REG_PV points now exactly to this position */
803                 N_LONG(-offset - SZ_BRAS + N_PV_OFFSET);
804                 /* Substract *(REG_PV) from REG_PV */
805                 N_A(REG_PV, 0, RN, REG_PV);
806         }
807 }
808
809 /* emit_trap_compiler **********************************************************
810
811    Emit a trap instruction which calls the JIT compiler.
812
813 *******************************************************************************/
814
815 void emit_trap_compiler(codegendata *cd)
816 {
817         M_ILL2(REG_METHODPTR, TRAP_COMPILER);
818 }
819
820 /*
821  * These are local overrides for various environment variables in Emacs.
822  * Please do not remove this and leave it at the end of the file, where
823  * Emacs will automagically detect them.
824  * ---------------------------------------------------------------------
825  * Local variables:
826  * mode: c
827  * indent-tabs-mode: t
828  * c-basic-offset: 4
829  * tab-width: 4
830  * End:
831  */