* src/vm/jit/sparc64/solaris/md-os.c: Implemented hardware exception handling.
[cacao.git] / src / vm / jit / codegen-common.c
1 /* src/vm/jit/codegen-common.c - architecture independent code generator stuff
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    All functions assume the following code area / data area layout:
26
27    +-----------+
28    |           |
29    | code area | code area grows to higher addresses
30    |           |
31    +-----------+ <-- start of procedure
32    |           |
33    | data area | data area grows to lower addresses
34    |           |
35    +-----------+
36
37    The functions first write into a temporary code/data area allocated by
38    "codegen_init". "codegen_finish" copies the code and data area into permanent
39    memory. All functions writing values into the data area return the offset
40    relative the begin of the code area (start of procedure).    
41
42    $Id: codegen-common.c 8160 2007-06-28 01:52:19Z michi $
43
44 */
45
46
47 #include "config.h"
48
49 #include <assert.h>
50 #include <string.h>
51
52 #include "vm/types.h"
53
54 #if defined(ENABLE_JIT)
55 /* this is required PATCHER_CALL_SIZE */
56 # include "codegen.h"
57 #endif
58
59 #include "mm/memory.h"
60
61 #include "toolbox/avl.h"
62 #include "toolbox/list.h"
63 #include "toolbox/logging.h"
64
65 #include "native/jni.h"
66 #include "native/native.h"
67
68 #include "threads/threads-common.h"
69
70 #include "vm/exceptions.h"
71 #include "vm/stringlocal.h"
72
73 #include "vm/jit/abi.h"
74 #include "vm/jit/asmpart.h"
75 #include "vm/jit/codegen-common.h"
76
77 #if defined(ENABLE_DISASSEMBLER)
78 # include "vm/jit/disass.h"
79 #endif
80
81 #include "vm/jit/dseg.h"
82 #include "vm/jit/emit-common.h"
83 #include "vm/jit/jit.h"
84 #include "vm/jit/md.h"
85 #include "vm/jit/patcher-common.h"
86 #include "vm/jit/replace.h"
87 #if defined(ENABLE_SSA)
88 # include "vm/jit/optimizing/lsra.h"
89 # include "vm/jit/optimizing/ssa.h"
90 #endif
91 #include "vm/jit/stacktrace.h"
92
93 #if defined(ENABLE_INTRP)
94 #include "vm/jit/intrp/intrp.h"
95 #endif
96
97 #include "vmcore/method.h"
98 #include "vmcore/options.h"
99
100 # include "vmcore/statistics.h"
101
102 #if defined(ENABLE_VMLOG)
103 #include <vmlog_cacao.h>
104 #endif
105
106 #include "show.h"
107
108 /* in this tree we store all method addresses *********************************/
109
110 static avl_tree_t *methodtree = NULL;
111 static s4 methodtree_comparator(const void *treenode, const void *node);
112
113
114 /* codegen_init ****************************************************************
115
116    TODO
117
118 *******************************************************************************/
119
120 void codegen_init(void)
121 {
122         /* this tree is global, not method specific */
123
124         if (!methodtree) {
125 #if defined(ENABLE_JIT)
126                 methodtree_element *mte;
127 #endif
128
129                 methodtree = avl_create(&methodtree_comparator);
130
131 #if defined(ENABLE_JIT)
132                 /* insert asm_vm_call_method */
133
134                 mte = NEW(methodtree_element);
135
136                 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
137                 mte->endpc   = (u1 *) (ptrint) asm_vm_call_method_end;
138
139                 avl_insert(methodtree, mte);
140 #endif /* defined(ENABLE_JIT) */
141
142         }
143
144 }
145
146
147 /* codegen_setup ***************************************************************
148
149    Allocates and initialises code area, data area and references.
150
151 *******************************************************************************/
152
153 void codegen_setup(jitdata *jd)
154 {
155         methodinfo  *m;
156         codegendata *cd;
157
158         /* get required compiler data */
159
160         m  = jd->m;
161         cd = jd->cd;
162
163         /* initialize members */
164
165         cd->flags        = 0;
166
167         cd->mcodebase    = DMNEW(u1, MCODEINITSIZE);
168         cd->mcodeend     = cd->mcodebase + MCODEINITSIZE;
169         cd->mcodesize    = MCODEINITSIZE;
170
171         /* initialize mcode variables */
172
173         cd->mcodeptr     = cd->mcodebase;
174         cd->lastmcodeptr = cd->mcodebase;
175
176 #if defined(ENABLE_INTRP)
177         /* native dynamic superinstructions variables */
178
179         if (opt_intrp) {
180                 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
181                 cd->ncodesize = NCODEINITSIZE;
182
183                 /* initialize ncode variables */
184         
185                 cd->ncodeptr = cd->ncodebase;
186
187                 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
188                 cd->superstarts = NULL;
189         }
190 #endif
191
192         cd->dseg           = NULL;
193         cd->dseglen        = 0;
194
195         cd->jumpreferences = NULL;
196
197 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
198         cd->datareferences = NULL;
199 #endif
200
201 /*      cd->patchrefs      = list_create_dump(OFFSET(patchref, linkage)); */
202         cd->patchrefs      = NULL;
203         cd->brancheslabel  = list_create_dump(OFFSET(branch_label_ref_t, linkage));
204         cd->listcritical   = list_create_dump(OFFSET(critical_section_ref_t, linkage));
205
206         cd->linenumberreferences = NULL;
207         cd->linenumbertablesizepos = 0;
208         cd->linenumbertablestartpos = 0;
209         cd->linenumbertab = 0;
210 }
211
212
213 /* codegen_reset ***************************************************************
214
215    Resets the codegen data structure so we can recompile the method.
216
217 *******************************************************************************/
218
219 static void codegen_reset(jitdata *jd)
220 {
221         codeinfo    *code;
222         codegendata *cd;
223         basicblock  *bptr;
224
225         /* get required compiler data */
226
227         code = jd->code;
228         cd   = jd->cd;
229
230         /* reset error flag */
231
232         cd->flags          &= ~CODEGENDATA_FLAG_ERROR;
233
234         /* reset some members, we reuse the code memory already allocated
235            as this should have almost the correct size */
236
237         cd->mcodeptr        = cd->mcodebase;
238         cd->lastmcodeptr    = cd->mcodebase;
239
240         cd->dseg            = NULL;
241         cd->dseglen         = 0;
242
243         cd->jumpreferences  = NULL;
244
245 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
246         cd->datareferences  = NULL;
247 #endif
248
249 /*      cd->patchrefs       = list_create_dump(OFFSET(patchref, linkage)); */
250         cd->patchrefs       = NULL;
251         cd->brancheslabel   = list_create_dump(OFFSET(branch_label_ref_t, linkage));
252         cd->listcritical    = list_create_dump(OFFSET(critical_section_ref_t, linkage));
253
254         cd->linenumberreferences    = NULL;
255         cd->linenumbertablesizepos  = 0;
256         cd->linenumbertablestartpos = 0;
257         cd->linenumbertab           = 0;
258         
259         /* We need to clear the mpc and the branch references from all
260            basic blocks as they will definitely change. */
261
262         for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
263                 bptr->mpc        = -1;
264                 bptr->branchrefs = NULL;
265         }
266
267 #if defined(ENABLE_REPLACEMENT)
268         code->rplpoints     = NULL;
269         code->rplpointcount = 0;
270         code->regalloc      = NULL;
271         code->regalloccount = 0;
272         code->globalcount   = 0;
273 #endif
274 }
275
276
277 /* codegen_generate ************************************************************
278
279    Generates the code for the currently compiled method.
280
281 *******************************************************************************/
282
283 bool codegen_generate(jitdata *jd)
284 {
285         codegendata *cd;
286
287         /* get required compiler data */
288
289         cd = jd->cd;
290
291         /* call the machine-dependent code generation function */
292
293         if (!codegen_emit(jd))
294                 return false;
295
296         /* check for an error */
297
298         if (CODEGENDATA_HAS_FLAG_ERROR(cd)) {
299                 /* check for long-branches flag, if it is set we recompile the
300                    method */
301
302 #if !defined(NDEBUG)
303         if (compileverbose)
304             log_message_method("Re-generating code: ", jd->m);
305 #endif
306
307                 /* XXX maybe we should tag long-branches-methods for recompilation */
308
309                 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
310                         /* we have to reset the codegendata structure first */
311
312                         codegen_reset(jd);
313
314                         /* and restart the compiler run */
315
316                         if (!codegen_emit(jd))
317                                 return false;
318                 }
319                 else {
320                         vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags);
321                 }
322
323 #if !defined(NDEBUG)
324         if (compileverbose)
325             log_message_method("Re-generating code done: ", jd->m);
326 #endif
327         }
328
329         /* reallocate the memory and finish the code generation */
330
331         codegen_finish(jd);
332
333         /* everything's ok */
334
335         return true;
336 }
337
338
339 /* codegen_close ***************************************************************
340
341    TODO
342
343 *******************************************************************************/
344
345 void codegen_close(void)
346 {
347         /* TODO: release avl tree on i386 and x86_64 */
348 }
349
350
351 /* codegen_increase ************************************************************
352
353    Doubles code area.
354
355 *******************************************************************************/
356
357 void codegen_increase(codegendata *cd)
358 {
359         u1 *oldmcodebase;
360
361         /* save old mcodebase pointer */
362
363         oldmcodebase = cd->mcodebase;
364
365         /* reallocate to new, doubled memory */
366
367         cd->mcodebase = DMREALLOC(cd->mcodebase,
368                                                           u1,
369                                                           cd->mcodesize,
370                                                           cd->mcodesize * 2);
371         cd->mcodesize *= 2;
372         cd->mcodeend   = cd->mcodebase + cd->mcodesize;
373
374         /* set new mcodeptr */
375
376         cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
377
378 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(__M68K__) || defined(ENABLE_INTRP) \
379  || defined(__SPARC_64__)
380         /* adjust the pointer to the last patcher position */
381
382         if (cd->lastmcodeptr != NULL)
383                 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
384 #endif
385 }
386
387
388 /* codegen_ncode_increase ******************************************************
389
390    Doubles code area.
391
392 *******************************************************************************/
393
394 #if defined(ENABLE_INTRP)
395 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
396 {
397         u1 *oldncodebase;
398
399         /* save old ncodebase pointer */
400
401         oldncodebase = cd->ncodebase;
402
403         /* reallocate to new, doubled memory */
404
405         cd->ncodebase = DMREALLOC(cd->ncodebase,
406                                                           u1,
407                                                           cd->ncodesize,
408                                                           cd->ncodesize * 2);
409         cd->ncodesize *= 2;
410
411         /* return the new ncodeptr */
412
413         return (cd->ncodebase + (ncodeptr - oldncodebase));
414 }
415 #endif
416
417
418 /* codegen_add_branch_ref ******************************************************
419
420    Prepends an branch to the list.
421
422 *******************************************************************************/
423
424 void codegen_add_branch_ref(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options)
425 {
426         branchref *br;
427         s4         branchmpc;
428
429         STATISTICS(count_branches_unresolved++);
430
431         /* calculate the mpc of the branch instruction */
432
433         branchmpc = cd->mcodeptr - cd->mcodebase;
434
435         br = DNEW(branchref);
436
437         br->branchmpc = branchmpc;
438         br->condition = condition;
439         br->reg       = reg;
440         br->options   = options;
441         br->next      = target->branchrefs;
442
443         target->branchrefs = br;
444 }
445
446
447 /* codegen_resolve_branchrefs **************************************************
448
449    Resolves and patches the branch references of a given basic block.
450
451 *******************************************************************************/
452
453 void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr)
454 {
455         branchref *br;
456         u1        *mcodeptr;
457
458         /* Save the mcodeptr because in the branch emitting functions
459            we generate code somewhere inside already generated code,
460            but we're still in the actual code generation phase. */
461
462         mcodeptr = cd->mcodeptr;
463
464         /* just to make sure */
465
466         assert(bptr->mpc >= 0);
467
468         for (br = bptr->branchrefs; br != NULL; br = br->next) {
469                 /* temporary set the mcodeptr */
470
471                 cd->mcodeptr = cd->mcodebase + br->branchmpc;
472
473                 /* emit_bccz and emit_branch emit the correct code, even if we
474                    pass condition == BRANCH_UNCONDITIONAL or reg == -1. */
475
476                 emit_bccz(cd, bptr, br->condition, br->reg, br->options);
477         }
478
479         /* restore mcodeptr */
480
481         cd->mcodeptr = mcodeptr;
482 }
483
484
485 /* codegen_branch_label_add ****************************************************
486
487    Append an branch to the label-branch list.
488
489 *******************************************************************************/
490
491 void codegen_branch_label_add(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options)
492 {
493         list_t             *list;
494         branch_label_ref_t *br;
495         s4                  mpc;
496
497         /* get the label list */
498
499         list = cd->brancheslabel;
500         
501         /* calculate the current mpc */
502
503         mpc = cd->mcodeptr - cd->mcodebase;
504
505         br = DNEW(branch_label_ref_t);
506
507         br->mpc       = mpc;
508         br->label     = label;
509         br->condition = condition;
510         br->reg       = reg;
511         br->options   = options;
512
513         /* add the branch to the list */
514
515         list_add_last_unsynced(list, br);
516 }
517
518
519 /* codegen_add_patch_ref *******************************************************
520
521    Appends a new patcher reference to the list of patching positions.
522
523 *******************************************************************************/
524
525 void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
526                                                    s4 disp)
527 {
528         patchref *pr;
529         s4        branchmpc;
530
531         branchmpc = cd->mcodeptr - cd->mcodebase;
532
533         pr = DNEW(patchref);
534
535         pr->branchpos = branchmpc;
536         pr->disp      = disp;
537         pr->patcher   = patcher;
538         pr->ref       = ref;
539
540 /*      list_add_first(cd->patchrefs, pr); */
541         pr->next      = cd->patchrefs;
542         cd->patchrefs = pr;
543
544         /* Generate NOPs for opt_shownops. */
545
546         if (opt_shownops)
547                 PATCHER_NOPS;
548
549         /* If the codegen provides a PACHER_LONGBRANCHES_NOPS macro, honour it. */
550
551 #if defined(PATCHER_LONGBRANCHES_NOPS)
552         if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
553                 PATCHER_LONGBRANCHES_NOPS;
554         }
555 #endif
556
557 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__M68K__) || defined(__MIPS__) \
558  || defined(__SPARC_64__) || defined(__X86_64__))
559
560         /* On some architectures the patcher stub call instruction might
561            be longer than the actual instruction generated.  On this
562            architectures we store the last patcher call position and after
563            the basic block code generation is completed, we check the
564            range and maybe generate some nop's. */
565         /* The nops are generated in codegen_emit in each codegen */
566
567         cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
568 #endif
569 }
570
571
572 /* codegen_critical_section_new ************************************************
573
574    Allocates a new critical-section reference and adds it to the
575    critical-section list.
576
577 *******************************************************************************/
578
579 #if defined(ENABLE_THREADS)
580 void codegen_critical_section_new(codegendata *cd)
581 {
582         list_t                 *list;
583         critical_section_ref_t *csr;
584         s4                      mpc;
585
586         /* get the critical section list */
587
588         list = cd->listcritical;
589         
590         /* calculate the current mpc */
591
592         mpc = cd->mcodeptr - cd->mcodebase;
593
594         csr = DNEW(critical_section_ref_t);
595
596         /* We only can set restart right now, as start and end are set by
597            the following, corresponding functions. */
598
599         csr->start   = -1;
600         csr->end     = -1;
601         csr->restart = mpc;
602
603         /* add the branch to the list */
604
605         list_add_last_unsynced(list, csr);
606 }
607 #endif
608
609
610 /* codegen_critical_section_start **********************************************
611
612    Set the start-point of the current critical section (which is the
613    last element of the list).
614
615 *******************************************************************************/
616
617 #if defined(ENABLE_THREADS)
618 void codegen_critical_section_start(codegendata *cd)
619 {
620         list_t                 *list;
621         critical_section_ref_t *csr;
622         s4                      mpc;
623
624         /* get the critical section list */
625
626         list = cd->listcritical;
627         
628         /* calculate the current mpc */
629
630         mpc = cd->mcodeptr - cd->mcodebase;
631
632         /* get the current critical section */
633
634         csr = list_last_unsynced(list);
635
636         /* set the start point */
637
638         assert(csr->start == -1);
639
640         csr->start = mpc;
641 }
642 #endif
643
644
645 /* codegen_critical_section_end ************************************************
646
647    Set the end-point of the current critical section (which is the
648    last element of the list).
649
650 *******************************************************************************/
651
652 #if defined(ENABLE_THREADS)
653 void codegen_critical_section_end(codegendata *cd)
654 {
655         list_t                 *list;
656         critical_section_ref_t *csr;
657         s4                      mpc;
658
659         /* get the critical section list */
660
661         list = cd->listcritical;
662         
663         /* calculate the current mpc */
664
665         mpc = cd->mcodeptr - cd->mcodebase;
666
667         /* get the current critical section */
668
669         csr = list_last_unsynced(list);
670
671         /* set the end point */
672
673         assert(csr->end == -1);
674
675         csr->end = mpc;
676 }
677 #endif
678
679
680 /* codegen_critical_section_finish *********************************************
681
682    Finish the critical sections, create the critical section nodes for
683    the AVL tree and insert them into the tree.
684
685 *******************************************************************************/
686
687 #if defined(ENABLE_THREADS)
688 static void codegen_critical_section_finish(jitdata *jd)
689 {
690         codeinfo    *code;
691         codegendata *cd;
692         list_t                  *list;
693         critical_section_ref_t  *csr;
694         critical_section_node_t *csn;
695
696         /* get required compiler data */
697
698         code = jd->code;
699         cd   = jd->cd;
700
701         /* get the critical section list */
702
703         list = cd->listcritical;
704
705         /* iterate over all critical sections */
706
707         for (csr = list_first_unsynced(list); csr != NULL;
708                  csr = list_next_unsynced(list, csr)) {
709                 /* check if all points are set */
710
711                 assert(csr->start   != -1);
712                 assert(csr->end     != -1);
713                 assert(csr->restart != -1);
714
715                 /* allocate tree node */
716
717                 csn = NEW(critical_section_node_t);
718
719                 csn->start   = code->entrypoint + csr->start;
720                 csn->end     = code->entrypoint + csr->end;
721                 csn->restart = code->entrypoint + csr->restart;
722
723                 /* insert into the tree */
724
725                 critical_section_register(csn);
726         }
727 }
728 #endif
729
730
731 /* methodtree_comparator *******************************************************
732
733    Comparator function used for the AVL tree of methods.
734
735    ARGUMENTS:
736       treenode....the node from the tree
737       node........the node to compare to the tree-node
738
739 *******************************************************************************/
740
741 static s4 methodtree_comparator(const void *treenode, const void *node)
742 {
743         methodtree_element *mte;
744         methodtree_element *mtepc;
745
746         mte   = (methodtree_element *) treenode;
747         mtepc = (methodtree_element *) node;
748
749         /* compare both startpc and endpc of pc, even if they have the same value,
750            otherwise the avl_probe sometimes thinks the element is already in the
751            tree */
752
753 #ifdef __S390__
754         /* On S390 addresses are 31 bit. Compare only 31 bits of value.
755          */
756 #       define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
757 #else
758 #       define ADDR_MASK(a) (a)
759 #endif
760
761         if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
762                 ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
763                 ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
764                 ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
765                 return 0;
766
767         } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
768                 return -1;
769
770         } else {
771                 return 1;
772         }
773
774 #       undef ADDR_MASK
775 }
776
777
778 /* codegen_insertmethod ********************************************************
779
780    Insert the machine code range of a method into the AVL tree of methods.
781
782 *******************************************************************************/
783
784 void codegen_insertmethod(u1 *startpc, u1 *endpc)
785 {
786         methodtree_element *mte;
787
788         /* allocate new method entry */
789
790         mte = NEW(methodtree_element);
791
792         mte->startpc = startpc;
793         mte->endpc   = endpc;
794
795         /* this function does not return an error, but asserts for
796            duplicate entries */
797
798         avl_insert(methodtree, mte);
799 }
800
801
802 /* codegen_get_pv_from_pc ******************************************************
803
804    Find the PV for the given PC by searching in the AVL tree of
805    methods.
806
807 *******************************************************************************/
808
809 u1 *codegen_get_pv_from_pc(u1 *pc)
810 {
811         methodtree_element  mtepc;
812         methodtree_element *mte;
813
814         /* allocation of the search structure on the stack is much faster */
815
816         mtepc.startpc = pc;
817         mtepc.endpc   = pc;
818
819         mte = avl_find(methodtree, &mtepc);
820
821         if (mte == NULL) {
822                 /* No method was found.  Let's dump a stacktrace. */
823
824 #if defined(ENABLE_VMLOG)
825                 vmlog_cacao_signl("SIGSEGV");
826 #endif
827
828                 log_println("We received a SIGSEGV and tried to handle it, but we were");
829                 log_println("unable to find a Java method at:");
830                 log_println("");
831 #if SIZEOF_VOID_P == 8
832                 log_println("PC=0x%016lx", pc);
833 #else
834                 log_println("PC=0x%08x", pc);
835 #endif
836                 log_println("");
837                 assert(0);
838                 log_println("Dumping the current stacktrace:");
839
840 #if defined(ENABLE_THREADS)
841                 /* XXX michi: This should be available even without threads! */
842                 threads_print_stacktrace();
843 #endif
844
845                 vm_abort("Exiting...");
846         }
847
848         return mte->startpc;
849 }
850
851
852 /* codegen_get_pv_from_pc_nocheck **********************************************
853
854    Find the PV for the given PC by searching in the AVL tree of
855    methods.  This method does not check the return value and is used
856    by the profiler.
857
858 *******************************************************************************/
859
860 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
861 {
862         methodtree_element  mtepc;
863         methodtree_element *mte;
864
865         /* allocation of the search structure on the stack is much faster */
866
867         mtepc.startpc = pc;
868         mtepc.endpc   = pc;
869
870         mte = avl_find(methodtree, &mtepc);
871
872         if (mte == NULL)
873                 return NULL;
874         else
875                 return mte->startpc;
876 }
877
878
879 /* codegen_set_replacement_point_notrap ****************************************
880
881    Record the position of a non-trappable replacement point.
882
883 *******************************************************************************/
884
885 #if defined(ENABLE_REPLACEMENT)
886 #if !defined(NDEBUG)
887 void codegen_set_replacement_point_notrap(codegendata *cd, s4 type)
888 #else
889 void codegen_set_replacement_point_notrap(codegendata *cd)
890 #endif
891 {
892         assert(cd->replacementpoint);
893         assert(cd->replacementpoint->type == type);
894         assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP);
895
896         cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
897
898         cd->replacementpoint++;
899 }
900 #endif /* defined(ENABLE_REPLACEMENT) */
901
902
903 /* codegen_set_replacement_point ***********************************************
904
905    Record the position of a trappable replacement point.
906
907 *******************************************************************************/
908
909 #if defined(ENABLE_REPLACEMENT)
910 #if !defined(NDEBUG)
911 void codegen_set_replacement_point(codegendata *cd, s4 type)
912 #else
913 void codegen_set_replacement_point(codegendata *cd)
914 #endif
915 {
916         assert(cd->replacementpoint);
917         assert(cd->replacementpoint->type == type);
918         assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP));
919
920         cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase);
921
922         cd->replacementpoint++;
923
924         /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */
925
926         cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
927 }
928 #endif /* defined(ENABLE_REPLACEMENT) */
929
930
931 /* codegen_finish **************************************************************
932
933    Finishes the code generation. A new memory, large enough for both
934    data and code, is allocated and data and code are copied together
935    to their final layout, unresolved jumps are resolved, ...
936
937 *******************************************************************************/
938
939 void codegen_finish(jitdata *jd)
940 {
941         codeinfo    *code;
942         codegendata *cd;
943         s4           mcodelen;
944 #if defined(ENABLE_INTRP)
945         s4           ncodelen;
946 #endif
947         s4           alignedmcodelen;
948         jumpref     *jr;
949         patchref_t  *pr;
950         u1          *epoint;
951         s4           alignedlen;
952
953         /* get required compiler data */
954
955         code = jd->code;
956         cd   = jd->cd;
957
958         /* prevent compiler warning */
959
960 #if defined(ENABLE_INTRP)
961         ncodelen = 0;
962 #endif
963
964         /* calculate the code length */
965
966         mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
967
968 #if defined(ENABLE_STATISTICS)
969         if (opt_stat) {
970                 count_code_len += mcodelen;
971                 count_data_len += cd->dseglen;
972         }
973 #endif
974
975         alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
976
977 #if defined(ENABLE_INTRP)
978         if (opt_intrp)
979                 ncodelen = cd->ncodeptr - cd->ncodebase;
980         else {
981                 ncodelen = 0; /* avoid compiler warning */
982         }
983 #endif
984
985         cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN);
986         alignedlen = alignedmcodelen + cd->dseglen;
987
988 #if defined(ENABLE_INTRP)
989         if (opt_intrp) {
990                 alignedlen += ncodelen;
991         }
992 #endif
993
994         /* allocate new memory */
995
996         code->mcodelength = mcodelen + cd->dseglen;
997         code->mcode       = CNEW(u1, alignedlen);
998
999         /* set the entrypoint of the method */
1000         
1001         assert(code->entrypoint == NULL);
1002         code->entrypoint = epoint = (code->mcode + cd->dseglen);
1003
1004         /* fill the data segment (code->entrypoint must already be set!) */
1005
1006         dseg_finish(jd);
1007
1008         /* copy code to the new location */
1009
1010         MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
1011
1012 #if defined(ENABLE_INTRP)
1013         /* relocate native dynamic superinstruction code (if any) */
1014
1015         if (opt_intrp) {
1016                 cd->mcodebase = code->entrypoint;
1017
1018                 if (ncodelen > 0) {
1019                         u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
1020
1021                         MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
1022
1023                         /* flush the instruction and data caches */
1024
1025                         md_cacheflush(ncodebase, ncodelen);
1026
1027                         /* set some cd variables for dynamic_super_rerwite */
1028
1029                         cd->ncodebase = ncodebase;
1030
1031                 } else {
1032                         cd->ncodebase = NULL;
1033                 }
1034
1035                 dynamic_super_rewrite(cd);
1036         }
1037 #endif
1038
1039         /* jump table resolving */
1040
1041         for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
1042                 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
1043                         (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
1044
1045         /* line number table resolving */
1046         {
1047                 linenumberref *lr;
1048                 ptrint lrtlen = 0;
1049                 ptrint target;
1050
1051                 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
1052                         lrtlen++;
1053                         target = lr->targetmpc;
1054                         /* if the entry contains an mcode pointer (normal case), resolve it */
1055                         /* (see doc/inlining_stacktrace.txt for details)                    */
1056                         if (lr->linenumber >= -2) {
1057                             target += (ptrint) epoint;
1058                         }
1059                         *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) = 
1060                                 (functionptr) target;
1061                 }
1062                 
1063                 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
1064                         (functionptr) ((ptrint) epoint + cd->linenumbertab);
1065
1066                 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
1067         }
1068
1069         /* patcher resolving */
1070
1071         pr = list_first_unsynced(code->patchers);
1072         while (pr) {
1073                 pr->mpc += (ptrint) epoint;
1074                 pr->datap = (ptrint) (pr->disp + epoint);
1075                 pr = list_next_unsynced(code->patchers, pr);
1076         }
1077
1078 #if defined(ENABLE_REPLACEMENT)
1079         /* replacement point resolving */
1080         {
1081                 int i;
1082                 rplpoint *rp;
1083
1084                 code->replacementstubs += (ptrint) epoint;
1085
1086                 rp = code->rplpoints;
1087                 for (i=0; i<code->rplpointcount; ++i, ++rp) {
1088                         rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
1089                 }
1090         }
1091 #endif /* defined(ENABLE_REPLACEMENT) */
1092
1093         /* add method into methodtree to find the entrypoint */
1094
1095         codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
1096
1097 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
1098         /* resolve data segment references */
1099
1100         dseg_resolve_datareferences(jd);
1101 #endif
1102
1103 #if defined(ENABLE_THREADS)
1104         /* create cirtical sections */
1105
1106         codegen_critical_section_finish(jd);
1107 #endif
1108
1109         /* flush the instruction and data caches */
1110
1111         md_cacheflush(code->mcode, code->mcodelength);
1112 }
1113
1114
1115 /* codegen_generate_stub_compiler **********************************************
1116
1117    Wrapper for codegen_emit_stub_compiler.
1118
1119    Returns:
1120        pointer to the compiler stub code.
1121
1122 *******************************************************************************/
1123
1124 u1 *codegen_generate_stub_compiler(methodinfo *m)
1125 {
1126         jitdata     *jd;
1127         codegendata *cd;
1128         ptrint      *d;                     /* pointer to data memory             */
1129         u1          *c;                     /* pointer to code memory             */
1130         s4           dumpsize;
1131
1132         /* mark dump memory */
1133
1134         dumpsize = dump_size();
1135
1136         /* allocate required data structures */
1137
1138         jd = DNEW(jitdata);
1139
1140         jd->m     = m;
1141         jd->cd    = DNEW(codegendata);
1142         jd->flags = 0;
1143
1144         /* get required compiler data */
1145
1146         cd = jd->cd;
1147
1148         /* allocate code memory */
1149
1150         c = CNEW(u1, 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE);
1151
1152         /* set pointers correctly */
1153
1154         d = (ptrint *) c;
1155
1156         cd->mcodebase = c;
1157
1158         c = c + 3 * SIZEOF_VOID_P;
1159         cd->mcodeptr = c;
1160
1161         /* NOTE: The codeinfo pointer is actually a pointer to the
1162            methodinfo (this fakes a codeinfo structure). */
1163
1164         d[0] = (ptrint) asm_call_jit_compiler;
1165         d[1] = (ptrint) m;
1166         d[2] = (ptrint) &d[1];                                    /* fake code->m */
1167
1168         /* call the emit function */
1169
1170         codegen_emit_stub_compiler(jd);
1171
1172 #if defined(ENABLE_STATISTICS)
1173         if (opt_stat)
1174                 count_cstub_len += 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE;
1175 #endif
1176
1177         /* flush caches */
1178
1179         md_cacheflush(cd->mcodebase, 3 * SIZEOF_VOID_P + COMPILERSTUB_CODESIZE);
1180
1181         /* release dump memory */
1182
1183         dump_release(dumpsize);
1184
1185         /* return native stub code */
1186
1187         return c;
1188 }
1189
1190
1191 /* codegen_generate_stub_native ************************************************
1192
1193    Wrapper for codegen_emit_stub_native.
1194
1195    Returns:
1196        the codeinfo representing the stub code.
1197
1198 *******************************************************************************/
1199
1200 codeinfo *codegen_generate_stub_native(methodinfo *m, functionptr f)
1201 {
1202         jitdata     *jd;
1203         codeinfo    *code;
1204         s4           dumpsize;
1205         methoddesc  *md;
1206         methoddesc  *nmd;       
1207         s4           nativeparams;
1208
1209         /* mark dump memory */
1210
1211         dumpsize = dump_size();
1212
1213         jd = DNEW(jitdata);
1214
1215         jd->m     = m;
1216         jd->cd    = DNEW(codegendata);
1217         jd->rd    = DNEW(registerdata);
1218         jd->flags = 0;
1219
1220         /* Allocate codeinfo memory from the heap as we need to keep them. */
1221
1222         jd->code  = code_codeinfo_new(m); /* XXX check allocation */
1223
1224         /* get required compiler data */
1225
1226         code = jd->code;
1227
1228         /* set the flags for the current JIT run */
1229
1230 #if defined(ENABLE_PROFILING)
1231         if (opt_prof)
1232                 jd->flags |= JITDATA_FLAG_INSTRUMENT;
1233 #endif
1234
1235         if (opt_verbosecall)
1236                 jd->flags |= JITDATA_FLAG_VERBOSECALL;
1237
1238         /* setup code generation stuff */
1239
1240 #if defined(ENABLE_JIT)
1241 # if defined(ENABLE_INTRP)
1242         if (!opt_intrp)
1243 # endif
1244                 reg_setup(jd);
1245 #endif
1246
1247         codegen_setup(jd);
1248
1249         /* create new method descriptor with additional native parameters */
1250
1251         md = m->parseddesc;
1252         nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
1253         
1254         nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
1255                                                            md->paramcount * sizeof(typedesc) +
1256                                                            nativeparams * sizeof(typedesc));
1257
1258         nmd->paramcount = md->paramcount + nativeparams;
1259
1260         nmd->params = DMNEW(paramdesc, nmd->paramcount);
1261
1262         nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer            */
1263
1264         if (m->flags & ACC_STATIC)
1265                 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer              */
1266
1267         MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
1268                   md->paramcount);
1269
1270 #if defined(ENABLE_JIT)
1271 # if defined(ENABLE_INTRP)
1272         if (!opt_intrp)
1273 # endif
1274                 /* pre-allocate the arguments for the native ABI */
1275
1276                 md_param_alloc_native(nmd);
1277 #endif
1278
1279         /* generate the code */
1280
1281 #if defined(ENABLE_JIT)
1282 # if defined(ENABLE_INTRP)
1283         if (opt_intrp)
1284                 intrp_createnativestub(f, jd, nmd);
1285         else
1286 # endif
1287                 codegen_emit_stub_native(jd, nmd, f);
1288 #else
1289         intrp_createnativestub(f, jd, nmd);
1290 #endif
1291
1292         /* reallocate the memory and finish the code generation */
1293
1294         codegen_finish(jd);
1295
1296 #if defined(ENABLE_STATISTICS)
1297         /* must be done after codegen_finish() */
1298
1299         if (opt_stat)
1300                 size_stub_native += code->mcodelength;
1301 #endif
1302
1303 #if !defined(NDEBUG)
1304         /* disassemble native stub */
1305
1306         if (opt_shownativestub) {
1307 #if defined(ENABLE_DEBUG_FILTER)
1308                 if (m->filtermatches & SHOW_FILTER_FLAG_SHOW_METHOD)
1309 #endif
1310                 {
1311 #if defined(ENABLE_DISASSEMBLER)
1312                         codegen_disassemble_nativestub(m,
1313                                                                                    (u1 *) (ptrint) code->entrypoint,
1314                                                                                    (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
1315 #endif
1316
1317                         /* show data segment */
1318
1319                         if (opt_showddatasegment)
1320                                 dseg_display(jd);
1321                 }
1322         }
1323 #endif /* !defined(NDEBUG) */
1324
1325         /* release memory */
1326
1327         dump_release(dumpsize);
1328
1329         /* return native stub code */
1330
1331         return code;
1332 }
1333
1334
1335 /* codegen_disassemble_nativestub **********************************************
1336
1337    Disassembles the generated native stub.
1338
1339 *******************************************************************************/
1340
1341 #if defined(ENABLE_DISASSEMBLER)
1342 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
1343 {
1344         printf("Native stub: ");
1345         utf_fprint_printable_ascii_classname(stdout, m->class->name);
1346         printf(".");
1347         utf_fprint_printable_ascii(stdout, m->name);
1348         utf_fprint_printable_ascii(stdout, m->descriptor);
1349         printf("\n\nLength: %d\n\n", (s4) (end - start));
1350
1351         DISASSEMBLE(start, end);
1352 }
1353 #endif
1354
1355
1356 /* codegen_start_native_call ***************************************************
1357
1358    Prepares the stuff required for a native (JNI) function call:
1359
1360    - adds a stackframe info structure to the chain, for stacktraces
1361    - prepares the local references table on the stack
1362
1363    The layout of the native stub stackframe should look like this:
1364
1365    +---------------------------+ <- SP (of parent Java function)
1366    | return address            |
1367    +---------------------------+
1368    |                           |
1369    | stackframe info structure |
1370    |                           |
1371    +---------------------------+
1372    |                           |
1373    | local references table    |
1374    |                           |
1375    +---------------------------+
1376    |                           |
1377    | arguments (if any)        |
1378    |                           |
1379    +---------------------------+ <- SP (native stub)
1380
1381 *******************************************************************************/
1382
1383 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
1384 {
1385         stackframeinfo *sfi;
1386         localref_table *lrt;
1387
1388         STATISTICS(count_calls_java_to_native++);
1389
1390         /* get data structures from stack */
1391
1392         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1393         lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
1394                                                           sizeof(localref_table));
1395
1396         /* add a stackframeinfo to the chain */
1397
1398         stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
1399
1400 #if defined(ENABLE_JNI)
1401         /* add current JNI local references table to this thread */
1402
1403         lrt->capacity    = LOCALREFTABLE_CAPACITY;
1404         lrt->used        = 0;
1405         lrt->localframes = 1;
1406         lrt->prev        = LOCALREFTABLE;
1407
1408         /* clear the references array (memset is faster the a for-loop) */
1409
1410         MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
1411
1412         LOCALREFTABLE = lrt;
1413 #endif
1414 }
1415
1416
1417 /* codegen_finish_native_call **************************************************
1418
1419    Removes the stuff required for a native (JNI) function call.
1420    Additionally it checks for an exceptions and in case, get the
1421    exception object and clear the pointer.
1422
1423 *******************************************************************************/
1424
1425 java_objectheader *codegen_finish_native_call(u1 *datasp)
1426 {
1427         stackframeinfo     *sfi;
1428         stackframeinfo    **psfi;
1429 #if defined(ENABLE_JNI)
1430         localref_table     *lrt;
1431         localref_table     *plrt;
1432         s4                  localframes;
1433 #endif
1434         java_objectheader  *e;
1435
1436         /* get data structures from stack */
1437
1438         sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1439
1440         /* remove current stackframeinfo from chain */
1441
1442         psfi = &STACKFRAMEINFO;
1443
1444         *psfi = sfi->prev;
1445
1446 #if defined(ENABLE_JNI)
1447         /* release JNI local references tables for this thread */
1448
1449         lrt = LOCALREFTABLE;
1450
1451         /* release all current local frames */
1452
1453         for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1454                 /* get previous frame */
1455
1456                 plrt = lrt->prev;
1457
1458                 /* Clear all reference entries (only for tables allocated on
1459                    the Java heap). */
1460
1461                 if (localframes > 1)
1462                         MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1463
1464                 lrt->prev = NULL;
1465
1466                 /* set new local references table */
1467
1468                 lrt = plrt;
1469         }
1470
1471         /* now store the previous local frames in the thread structure */
1472
1473         LOCALREFTABLE = lrt;
1474 #endif
1475
1476         /* get the exception and return it */
1477
1478         e = exceptions_get_and_clear_exception();
1479
1480         return e;
1481 }
1482
1483
1484 /* removecompilerstub **********************************************************
1485
1486    Deletes a compilerstub from memory (simply by freeing it).
1487
1488 *******************************************************************************/
1489
1490 void removecompilerstub(u1 *stub)
1491 {
1492         /* pass size 1 to keep the intern function happy */
1493
1494         CFREE((void *) stub, 1);
1495 }
1496
1497
1498 /* removenativestub ************************************************************
1499
1500    Removes a previously created native-stub from memory.
1501     
1502 *******************************************************************************/
1503
1504 void removenativestub(u1 *stub)
1505 {
1506         /* pass size 1 to keep the intern function happy */
1507
1508         CFREE((void *) stub, 1);
1509 }
1510
1511
1512 /* codegen_reg_of_var **********************************************************
1513
1514    This function determines a register, to which the result of an
1515    operation should go, when it is ultimatively intended to store the
1516    result in pseudoregister v.  If v is assigned to an actual
1517    register, this register will be returned.  Otherwise (when v is
1518    spilled) this function returns tempregnum.  If not already done,
1519    regoff and flags are set in the stack location.
1520        
1521 *******************************************************************************/
1522
1523 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1524 {
1525
1526 #if 0
1527         /* Do we have to generate a conditional move?  Yes, then always
1528            return the temporary register.  The real register is identified
1529            during the store. */
1530
1531         if (opcode & ICMD_CONDITION_MASK)
1532                 return tempregnum;
1533 #endif
1534
1535         if (!(v->flags & INMEMORY))
1536                 return v->vv.regoff;
1537
1538         return tempregnum;
1539 }
1540
1541
1542 /* codegen_reg_of_dst **********************************************************
1543
1544    This function determines a register, to which the result of an
1545    operation should go, when it is ultimatively intended to store the
1546    result in iptr->dst.var.  If dst.var is assigned to an actual
1547    register, this register will be returned.  Otherwise (when it is
1548    spilled) this function returns tempregnum.  If not already done,
1549    regoff and flags are set in the stack location.
1550        
1551 *******************************************************************************/
1552
1553 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1554 {
1555         return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1556 }
1557
1558
1559 /* codegen_emit_phi_moves ****************************************************
1560
1561    Emits phi moves at the end of the basicblock.
1562
1563 *******************************************************************************/
1564
1565 #if defined(ENABLE_SSA)
1566 void codegen_emit_phi_moves(jitdata *jd, basicblock *bptr)
1567 {
1568         int lt_d,lt_s,i;
1569         lsradata *ls;
1570         codegendata *cd;
1571         varinfo *s, *d;
1572         instruction tmp_i;
1573
1574         cd = jd->cd;
1575         ls = jd->ls;
1576
1577         MCODECHECK(512);
1578
1579         /* Moves from phi functions with highest indices have to be */
1580         /* inserted first, since this is the order as is used for   */
1581         /* conflict resolution */
1582
1583         for(i = ls->num_phi_moves[bptr->nr] - 1; i >= 0 ; i--) {
1584                 lt_d = ls->phi_moves[bptr->nr][i][0];
1585                 lt_s = ls->phi_moves[bptr->nr][i][1];
1586 #if defined(SSA_DEBUG_VERBOSE)
1587                 if (compileverbose)
1588                         printf("BB %3i Move %3i <- %3i ", bptr->nr, lt_d, lt_s);
1589 #endif
1590                 if (lt_s == UNUSED) {
1591 #if defined(SSA_DEBUG_VERBOSE)
1592                 if (compileverbose)
1593                         printf(" ... not processed \n");
1594 #endif
1595                         continue;
1596                 }
1597                         
1598                 d = VAR(ls->lifetime[lt_d].v_index);
1599                 s = VAR(ls->lifetime[lt_s].v_index);
1600                 
1601
1602                 if (d->type == -1) {
1603 #if defined(SSA_DEBUG_VERBOSE)
1604                         if (compileverbose)
1605                                 printf("...returning - phi lifetimes where joined\n");
1606 #endif
1607                         return;
1608                 }
1609
1610                 if (s->type == -1) {
1611 #if defined(SSA_DEBUG_VERBOSE)
1612                         if (compileverbose)
1613                                 printf("...returning - phi lifetimes where joined\n");
1614 #endif
1615                         return;
1616                 }
1617
1618                 tmp_i.opc = 0;
1619                 tmp_i.s1.varindex = ls->lifetime[lt_s].v_index;
1620                 tmp_i.dst.varindex = ls->lifetime[lt_d].v_index;
1621                 emit_copy(jd, &tmp_i);
1622
1623 #if defined(SSA_DEBUG_VERBOSE)
1624                 if (compileverbose) {
1625                         if (IS_INMEMORY(d->flags) && IS_INMEMORY(s->flags)) {
1626                                 /* mem -> mem */
1627                                 printf("M%3i <- M%3i",d->vv.regoff,s->vv.regoff);
1628                         }
1629                         else if (IS_INMEMORY(s->flags)) {
1630                                 /* mem -> reg */
1631                                 printf("R%3i <- M%3i",d->vv.regoff,s->vv.regoff);
1632                         }
1633                         else if (IS_INMEMORY(d->flags)) {
1634                                 /* reg -> mem */
1635                                 printf("M%3i <- R%3i",d->vv.regoff,s->vv.regoff);
1636                         }
1637                         else {
1638                                 /* reg -> reg */
1639                                 printf("R%3i <- R%3i",d->vv.regoff,s->vv.regoff);
1640                         }
1641                         printf("\n");
1642                 }
1643 #endif /* defined(SSA_DEBUG_VERBOSE) */
1644         }
1645 }
1646 #endif /* defined(ENABLE_SSA) */
1647
1648
1649
1650 /*
1651  * These are local overrides for various environment variables in Emacs.
1652  * Please do not remove this and leave it at the end of the file, where
1653  * Emacs will automagically detect them.
1654  * ---------------------------------------------------------------------
1655  * Local variables:
1656  * mode: c
1657  * indent-tabs-mode: t
1658  * c-basic-offset: 4
1659  * tab-width: 4
1660  * End:
1661  * vim:noexpandtab:sw=4:ts=4:
1662  */