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