1 /* src/vm/jit/codegen-common.c - architecture independent code generator stuff
3 Copyright (C) 1996-2005, 2006 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
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@cacaojvm.org
27 Authors: Reinhard Grafl
30 Changes: Christian Thalinger
34 All functions assume the following code area / data area layout:
38 | code area | code area grows to higher addresses
40 +-----------+ <-- start of procedure
42 | data area | data area grows to lower addresses
46 The functions first write into a temporary code/data area allocated by
47 "codegen_init". "codegen_finish" copies the code and data area into permanent
48 memory. All functions writing values into the data area return the offset
49 relative the begin of the code area (start of procedure).
51 $Id: codegen-common.c 5332 2006-09-05 19:38:28Z twisti $
63 #if defined(ENABLE_JIT)
64 /* this is required for gen_resolvebranch and PATCHER_CALL_SIZE */
69 /* this is required for REG_SPLIT */
73 #include "mm/memory.h"
74 #include "toolbox/avl.h"
75 #include "toolbox/logging.h"
76 #include "native/jni.h"
77 #include "native/native.h"
79 #if defined(ENABLE_THREADS)
80 # include "threads/native/threads.h"
83 #include "vm/exceptions.h"
84 #include "vm/method.h"
85 #include "vm/options.h"
86 #include "vm/statistics.h"
87 #include "vm/stringlocal.h"
88 #include "vm/jit/asmpart.h"
89 #include "vm/jit/codegen-common.h"
91 #if defined(ENABLE_DISASSEMBLER)
92 # include "vm/jit/disass.h"
95 #include "vm/jit/dseg.h"
96 #include "vm/jit/jit.h"
97 #include "vm/jit/stacktrace.h"
98 #include "vm/jit/replace.h"
101 /* in this tree we store all method addresses *********************************/
103 static avl_tree *methodtree = NULL;
104 static s4 methodtree_comparator(const void *pc, const void *element);
107 /* codegen_init ****************************************************************
111 *******************************************************************************/
113 void codegen_init(void)
115 /* this tree is global, not method specific */
118 #if defined(ENABLE_JIT)
119 methodtree_element *mte;
122 methodtree = avl_create(&methodtree_comparator);
124 #if defined(ENABLE_JIT)
125 /* insert asm_vm_call_method */
127 mte = NEW(methodtree_element);
129 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
130 mte->endpc = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
132 avl_insert(methodtree, mte);
133 #endif /* defined(ENABLE_JIT) */
138 /* codegen_setup ***************************************************************
140 Allocates and initialises code area, data area and references.
142 *******************************************************************************/
144 void codegen_setup(jitdata *jd)
149 /* get required compiler data */
154 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
155 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
156 cd->mcodesize = MCODEINITSIZE;
158 /* initialize mcode variables */
160 cd->mcodeptr = cd->mcodebase;
161 cd->lastmcodeptr = cd->mcodebase;
163 #if defined(ENABLE_INTRP)
164 /* native dynamic superinstructions variables */
167 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
168 cd->ncodesize = NCODEINITSIZE;
170 /* initialize ncode variables */
172 cd->ncodeptr = cd->ncodebase;
174 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
175 cd->superstarts = NULL;
182 cd->jumpreferences = NULL;
184 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
185 cd->datareferences = NULL;
188 cd->exceptionrefs = NULL;
189 cd->patchrefs = NULL;
191 cd->linenumberreferences = NULL;
192 cd->linenumbertablesizepos = 0;
193 cd->linenumbertablestartpos = 0;
194 cd->linenumbertab = 0;
197 cd->exceptiontable = 0;
198 cd->exceptiontablelength = 0;
200 if (m->exceptiontablelength > 0) {
201 cd->exceptiontablelength = m->exceptiontablelength;
202 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
205 cd->maxstack = m->maxstack;
206 cd->maxlocals = m->maxlocals;
208 #if defined(ENABLE_THREADS)
209 cd->threadcritcurrent.next = NULL;
210 cd->threadcritcount = 0;
215 /* codegen_close ***************************************************************
219 *******************************************************************************/
221 void codegen_close(void)
223 /* TODO: release avl tree on i386 and x86_64 */
227 /* codegen_increase ************************************************************
231 *******************************************************************************/
233 void codegen_increase(codegendata *cd)
237 /* save old mcodebase pointer */
239 oldmcodebase = cd->mcodebase;
241 /* reallocate to new, doubled memory */
243 cd->mcodebase = DMREALLOC(cd->mcodebase,
248 cd->mcodeend = cd->mcodebase + cd->mcodesize;
250 /* set new mcodeptr */
252 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
254 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
255 /* adjust the pointer to the last patcher position */
257 if (cd->lastmcodeptr != NULL)
258 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
263 /* codegen_ncode_increase ******************************************************
267 *******************************************************************************/
269 #if defined(ENABLE_INTRP)
270 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
274 /* save old ncodebase pointer */
276 oldncodebase = cd->ncodebase;
278 /* reallocate to new, doubled memory */
280 cd->ncodebase = DMREALLOC(cd->ncodebase,
286 /* return the new ncodeptr */
288 return (cd->ncodebase + (ncodeptr - oldncodebase));
293 void codegen_addreference(codegendata *cd, basicblock *target)
297 branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
299 #if defined(ENABLE_JIT)
300 /* Check if the target basicblock has already a start pc, so the
301 jump is backward and we can resolve it immediately. */
303 /* The interpreter uses absolute branches, so we do branch
304 resolving after the code and data segment move. */
307 # if defined(ENABLE_INTRP)
312 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
319 branchref *br = DNEW(branchref);
321 br->branchpos = branchpos;
322 br->next = target->branchrefs;
324 target->branchrefs = br;
329 /* codegen_add_exception_ref ***************************************************
331 Adds an exception branch to the list.
333 *******************************************************************************/
335 static void codegen_add_exception_ref(codegendata *cd, s4 reg,
336 functionptr function)
341 branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
343 eref = DNEW(exceptionref);
345 eref->branchpos = branchpos;
347 eref->function = function;
348 eref->next = cd->exceptionrefs;
350 cd->exceptionrefs = eref;
354 /* codegen_add_arithmeticexception_ref *****************************************
356 Adds an ArithmeticException branch to the list.
358 *******************************************************************************/
360 void codegen_add_arithmeticexception_ref(codegendata *cd)
362 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arithmeticexception);
366 /* codegen_add_arrayindexoutofboundsexception_ref ******************************
368 Adds an ArrayIndexOutOfBoundsException branch to the list.
370 *******************************************************************************/
372 void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd, s4 reg)
374 codegen_add_exception_ref(cd, reg,
375 STACKTRACE_inline_arrayindexoutofboundsexception);
379 /* codegen_add_arraystoreexception_ref *****************************************
381 Adds an ArrayStoreException branch to the list.
383 *******************************************************************************/
385 void codegen_add_arraystoreexception_ref(codegendata *cd)
387 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arraystoreexception);
391 /* codegen_add_classcastexception_ref ******************************************
393 Adds an ClassCastException branch to the list.
395 *******************************************************************************/
397 void codegen_add_classcastexception_ref(codegendata *cd, s4 reg)
399 codegen_add_exception_ref(cd, reg, STACKTRACE_inline_classcastexception);
403 /* codegen_add_nullpointerexception_ref ****************************************
405 Adds an NullPointerException branch to the list.
407 *******************************************************************************/
409 void codegen_add_nullpointerexception_ref(codegendata *cd)
411 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_nullpointerexception);
415 /* codegen_add_fillinstacktrace_ref ********************************************
417 Adds a fillInStackTrace branch to the list.
419 *******************************************************************************/
421 void codegen_add_fillinstacktrace_ref(codegendata *cd)
423 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_fillInStackTrace);
427 /* codegen_addpatchref *********************************************************
429 Adds a new patcher reference to the list of patching positions.
431 *******************************************************************************/
433 void codegen_addpatchref(codegendata *cd, functionptr patcher, voidptr ref,
439 branchpos = cd->mcodeptr - cd->mcodebase;
443 pr->branchpos = branchpos;
444 pr->patcher = patcher;
448 pr->next = cd->patchrefs;
451 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
452 /* On some architectures the patcher stub call instruction might
453 be longer than the actual instruction generated. On this
454 architectures we store the last patcher call position and after
455 the basic block code generation is completed, we check the
456 range and maybe generate some nop's. */
458 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
463 /* methodtree_comparator *******************************************************
465 Comparator function used for the AVL tree of methods.
467 *******************************************************************************/
469 static s4 methodtree_comparator(const void *pc, const void *element)
471 methodtree_element *mte;
472 methodtree_element *mtepc;
474 mte = (methodtree_element *) element;
475 mtepc = (methodtree_element *) pc;
477 /* compare both startpc and endpc of pc, even if they have the same value,
478 otherwise the avl_probe sometimes thinks the element is already in the
481 if ((long) mte->startpc <= (long) mtepc->startpc &&
482 (long) mtepc->startpc <= (long) mte->endpc &&
483 (long) mte->startpc <= (long) mtepc->endpc &&
484 (long) mtepc->endpc <= (long) mte->endpc) {
487 } else if ((long) mtepc->startpc < (long) mte->startpc) {
496 /* codegen_insertmethod ********************************************************
498 Insert the machine code range of a method into the AVL tree of methods.
500 *******************************************************************************/
502 void codegen_insertmethod(u1 *startpc, u1 *endpc)
504 methodtree_element *mte;
506 /* allocate new method entry */
508 mte = NEW(methodtree_element);
510 mte->startpc = startpc;
513 /* this function does not return an error, but asserts for
516 avl_insert(methodtree, mte);
520 /* codegen_get_pv_from_pc ******************************************************
522 Find the PV for the given PC by searching in the AVL tree of
525 *******************************************************************************/
527 u1 *codegen_get_pv_from_pc(u1 *pc)
529 methodtree_element mtepc;
530 methodtree_element *mte;
532 /* allocation of the search structure on the stack is much faster */
537 mte = avl_find(methodtree, &mtepc);
540 /* No method was found. Let's dump a stacktrace. */
542 log_println("We received a SIGSEGV and tried to handle it, but we were");
543 log_println("unable to find a Java method at:");
545 #if SIZEOF_VOID_P == 8
546 log_println("PC=0x%016lx", pc);
548 log_println("PC=0x%08x", pc);
551 log_println("Dumping the current stacktrace:");
553 stacktrace_dump_trace();
555 vm_abort("Exiting...");
562 /* codegen_get_pv_from_pc_nocheck **********************************************
564 Find the PV for the given PC by searching in the AVL tree of
565 methods. This method does not check the return value and is used
568 *******************************************************************************/
570 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
572 methodtree_element mtepc;
573 methodtree_element *mte;
575 /* allocation of the search structure on the stack is much faster */
580 mte = avl_find(methodtree, &mtepc);
589 /* codegen_finish **************************************************************
591 Finishes the code generation. A new memory, large enough for both
592 data and code, is allocated and data and code are copied together
593 to their final layout, unresolved jumps are resolved, ...
595 *******************************************************************************/
597 void codegen_finish(jitdata *jd)
602 #if defined(ENABLE_INTRP)
611 /* get required compiler data */
616 /* prevent compiler warning */
618 #if defined(ENABLE_INTRP)
622 /* calculate the code length */
624 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
626 #if defined(ENABLE_THREADS)
627 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
632 #if defined(ENABLE_STATISTICS)
634 count_code_len += mcodelen;
635 count_data_len += cd->dseglen;
639 alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
641 #if defined(ENABLE_INTRP)
643 ncodelen = cd->ncodeptr - cd->ncodebase;
645 ncodelen = 0; /* avoid compiler warning */
649 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
650 alignedlen = alignedmcodelen + cd->dseglen;
652 #if defined(ENABLE_INTRP)
654 alignedlen += ncodelen;
658 /* allocate new memory */
660 code->mcodelength = mcodelen + cd->dseglen;
661 code->mcode = CNEW(u1, alignedlen + extralen);
663 /* set the entrypoint of the method */
665 assert(code->entrypoint == NULL);
666 code->entrypoint = epoint = (code->mcode + cd->dseglen);
668 /* fill the data segment (code->entrypoint must already be set!) */
672 /* copy code to the new location */
674 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
676 #if defined(ENABLE_INTRP)
677 /* relocate native dynamic superinstruction code (if any) */
680 cd->mcodebase = code->entrypoint;
683 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
685 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
687 /* flush the instruction and data caches */
689 md_cacheflush(ncodebase, ncodelen);
691 /* set some cd variables for dynamic_super_rerwite */
693 cd->ncodebase = ncodebase;
696 cd->ncodebase = NULL;
699 dynamic_super_rewrite(cd);
703 /* jump table resolving */
705 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
706 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
707 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
709 /* line number table resolving */
715 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
717 target = lr->targetmpc;
718 /* if the entry contains an mcode pointer (normal case), resolve it */
719 /* (see doc/inlining_stacktrace.txt for details) */
720 if (lr->linenumber >= -2) {
721 target += (ptrint) epoint;
723 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
724 (functionptr) target;
727 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
728 (functionptr) ((ptrint) epoint + cd->linenumbertab);
730 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
733 /* replacement point resolving */
738 rp = code->rplpoints;
739 for (i=0; i<code->rplpointcount; ++i, ++rp) {
740 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
741 rp->outcode = (u1*) ((ptrint) epoint + (ptrint) rp->outcode);
745 /* add method into methodtree to find the entrypoint */
747 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
749 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
750 /* resolve data segment references */
752 dseg_resolve_datareferences(jd);
755 #if defined(ENABLE_THREADS)
757 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
759 codegen_critical_section_t *nt = cd->threadcrit;
761 for (i = 0; i < cd->threadcritcount; i++) {
762 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
763 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
764 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
765 critical_register_critical_section(n);
772 /* flush the instruction and data caches */
774 md_cacheflush(code->mcode, code->mcodelength);
778 /* codegen_createnativestub ****************************************************
780 Wrapper for createnativestub.
783 the codeinfo representing the stub code.
785 *******************************************************************************/
787 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
796 /* mark dump memory */
798 dumpsize = dump_size();
803 jd->cd = DNEW(codegendata);
804 jd->rd = DNEW(registerdata);
806 /* Allocate codeinfo memory from the heap as we need to keep them. */
808 jd->code = code_codeinfo_new(m); /* XXX check allocation */
810 /* get required compiler data */
814 /* set the flags for the current JIT run */
817 jd->flags |= JITDATA_FLAG_INSTRUMENT;
820 jd->flags |= JITDATA_FLAG_VERBOSECALL;
822 /* setup code generation stuff */
824 #if defined(ENABLE_JIT)
825 # if defined(ENABLE_INTRP)
833 /* create new method descriptor with additional native parameters */
836 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
838 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
839 md->paramcount * sizeof(typedesc) +
840 nativeparams * sizeof(typedesc));
842 nmd->paramcount = md->paramcount + nativeparams;
844 nmd->params = DMNEW(paramdesc, nmd->paramcount);
846 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
848 if (m->flags & ACC_STATIC)
849 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
851 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
854 #if defined(ENABLE_JIT)
855 # if defined(ENABLE_INTRP)
861 /* generate the code */
863 #if defined(ENABLE_JIT)
864 # if defined(ENABLE_INTRP)
866 code->entrypoint = intrp_createnativestub(f, jd, nmd);
869 code->entrypoint = createnativestub(f, jd, nmd);
871 code->entrypoint = intrp_createnativestub(f, jd, nmd);
874 #if defined(ENABLE_STATISTICS)
876 count_nstub_len += code->mcodelength;
880 /* disassemble native stub */
882 if (opt_shownativestub) {
883 #if defined(ENABLE_DISASSEMBLER)
884 codegen_disassemble_nativestub(m,
885 (u1 *) (ptrint) code->entrypoint,
886 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
889 /* show data segment */
891 if (opt_showddatasegment)
894 #endif /* !defined(NDEBUG) */
898 dump_release(dumpsize);
900 /* return native stub code */
906 /* codegen_disassemble_nativestub **********************************************
908 Disassembles the generated native stub.
910 *******************************************************************************/
912 #if defined(ENABLE_DISASSEMBLER)
913 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
915 printf("Native stub: ");
916 utf_fprint_printable_ascii_classname(stdout, m->class->name);
918 utf_fprint_printable_ascii(stdout, m->name);
919 utf_fprint_printable_ascii(stdout, m->descriptor);
920 printf("\n\nLength: %d\n\n", (s4) (end - start));
922 DISASSEMBLE(start, end);
927 /* codegen_start_native_call ***************************************************
929 Prepares the stuff required for a native (JNI) function call:
931 - adds a stackframe info structure to the chain, for stacktraces
932 - prepares the local references table on the stack
934 The layout of the native stub stackframe should look like this:
936 +---------------------------+ <- SP (of parent Java function)
938 +---------------------------+
940 | stackframe info structure |
942 +---------------------------+
944 | local references table |
946 +---------------------------+
948 | arguments (if any) |
950 +---------------------------+ <- SP (native stub)
952 *******************************************************************************/
954 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
959 /* get data structures from stack */
961 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
962 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
963 sizeof(localref_table));
965 /* add a stackframeinfo to the chain */
967 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
969 /* add current JNI local references table to this thread */
971 lrt->capacity = LOCALREFTABLE_CAPACITY;
973 lrt->localframes = 1;
974 lrt->prev = LOCALREFTABLE;
976 /* clear the references array (memset is faster the a for-loop) */
978 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
984 /* codegen_finish_native_call **************************************************
986 Removes the stuff required for a native (JNI) function call.
987 Additionally it checks for an exceptions and in case, get the
988 exception object and clear the pointer.
990 *******************************************************************************/
992 java_objectheader *codegen_finish_native_call(u1 *datasp)
995 stackframeinfo **psfi;
997 localref_table *plrt;
999 java_objectheader *e;
1001 /* get data structures from stack */
1003 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1004 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1005 sizeof(localref_table));
1007 /* remove current stackframeinfo from chain */
1009 psfi = STACKFRAMEINFO;
1013 /* release JNI local references tables for this thread */
1015 lrt = LOCALREFTABLE;
1017 /* release all current local frames */
1019 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1020 /* get previous frame */
1024 /* Clear all reference entries (only for tables allocated on
1027 if (localframes > 1)
1028 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1032 /* set new local references table */
1037 /* now store the previous local frames in the thread structure */
1039 LOCALREFTABLE = lrt;
1041 /* get the exception and return it */
1043 e = exceptions_get_and_clear_exception();
1049 /* removecompilerstub **********************************************************
1051 Deletes a compilerstub from memory (simply by freeing it).
1053 *******************************************************************************/
1055 void removecompilerstub(u1 *stub)
1057 /* pass size 1 to keep the intern function happy */
1059 CFREE((void *) stub, 1);
1063 /* removenativestub ************************************************************
1065 Removes a previously created native-stub from memory.
1067 *******************************************************************************/
1069 void removenativestub(u1 *stub)
1071 /* pass size 1 to keep the intern function happy */
1073 CFREE((void *) stub, 1);
1077 /* codegen_reg_of_var **********************************************************
1079 This function determines a register, to which the result of an
1080 operation should go, when it is ultimatively intended to store the
1081 result in pseudoregister v. If v is assigned to an actual
1082 register, this register will be returned. Otherwise (when v is
1083 spilled) this function returns tempregnum. If not already done,
1084 regoff and flags are set in the stack location.
1086 On ARM we have to check if a long/double variable is splitted
1087 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1088 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1089 cases. (michi 2005/07/24)
1091 *******************************************************************************/
1093 s4 codegen_reg_of_var(registerdata *rd, u2 opcode, stackptr v, s4 tempregnum)
1098 /* Do we have to generate a conditional move? Yes, then always
1099 return the temporary register. The real register is identified
1100 during the store. */
1102 if (opcode & ICMD_CONDITION_MASK)
1106 switch (v->varkind) {
1108 if (!(v->flags & INMEMORY))
1113 var = &(rd->interfaces[v->varnum][v->type]);
1114 v->regoff = var->regoff;
1115 if (!(var->flags & INMEMORY))
1116 return(var->regoff);
1120 var = &(rd->locals[v->varnum][v->type]);
1121 v->regoff = var->regoff;
1122 if (!(var->flags & INMEMORY)) {
1123 #if defined(__ARM__) && defined(__ARMEL__)
1124 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1125 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1127 #if defined(__ARM__) && defined(__ARMEB__)
1128 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1129 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1131 return(var->regoff);
1136 if (!(v->flags & INMEMORY)) {
1137 #if defined(__ARM__) && defined(__ARMEL__)
1138 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1139 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1141 #if defined(__ARM__) && defined(__ARMEB__)
1142 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1143 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1150 #if defined(ENABLE_STATISTICS)
1152 count_spills_read++;
1155 v->flags |= INMEMORY;
1160 /* codegen_reg_of_dst **********************************************************
1162 This function determines a register, to which the result of an
1163 operation should go, when it is ultimatively intended to store the
1164 result in iptr->dst.var. If dst.var is assigned to an actual
1165 register, this register will be returned. Otherwise (when it is
1166 spilled) this function returns tempregnum. If not already done,
1167 regoff and flags are set in the stack location.
1169 On ARM we have to check if a long/double variable is splitted
1170 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1171 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1172 cases. (michi 2005/07/24)
1174 *******************************************************************************/
1176 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1179 stackptr v = iptr->dst.var;
1180 registerdata *rd = jd->rd;
1182 switch (v->varkind) {
1184 if (!(v->flags & INMEMORY))
1189 var = &(rd->interfaces[v->varnum][v->type]);
1190 v->regoff = var->regoff;
1191 if (!(var->flags & INMEMORY))
1192 return(var->regoff);
1196 var = &(rd->locals[v->varnum][v->type]);
1197 v->regoff = var->regoff;
1198 if (!(var->flags & INMEMORY)) {
1199 #if defined(__ARM__) && defined(__ARMEL__)
1200 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1201 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1203 #if defined(__ARM__) && defined(__ARMEB__)
1204 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1205 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1207 return(var->regoff);
1212 if (!(v->flags & INMEMORY)) {
1213 #if defined(__ARM__) && defined(__ARMEL__)
1214 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1215 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1217 #if defined(__ARM__) && defined(__ARMEB__)
1218 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1219 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1226 #if defined(ENABLE_STATISTICS)
1228 count_spills_read++;
1231 v->flags |= INMEMORY;
1237 #if defined(ENABLE_THREADS)
1238 void codegen_threadcritrestart(codegendata *cd, int offset)
1240 cd->threadcritcurrent.mcoderestart = offset;
1244 void codegen_threadcritstart(codegendata *cd, int offset)
1246 cd->threadcritcurrent.mcodebegin = offset;
1250 void codegen_threadcritstop(codegendata *cd, int offset)
1252 cd->threadcritcurrent.next = cd->threadcrit;
1253 cd->threadcritcurrent.mcodeend = offset;
1254 cd->threadcrit = DNEW(codegen_critical_section_t);
1255 *(cd->threadcrit) = cd->threadcritcurrent;
1256 cd->threadcritcount++;
1262 * These are local overrides for various environment variables in Emacs.
1263 * Please do not remove this and leave it at the end of the file, where
1264 * Emacs will automagically detect them.
1265 * ---------------------------------------------------------------------
1268 * indent-tabs-mode: t
1272 * vim:noexpandtab:sw=4:ts=4: