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 4690 2006-03-27 11:37:46Z 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(USE_THREADS)
80 # if defined(NATIVE_THREADS)
81 # include "threads/native/threads.h"
83 # include "threads/green/threads.h"
87 #include "vm/exceptions.h"
88 #include "vm/method.h"
89 #include "vm/options.h"
90 #include "vm/statistics.h"
91 #include "vm/stringlocal.h"
92 #include "vm/jit/asmpart.h"
93 #include "vm/jit/codegen-common.h"
94 #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 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
104 static avl_tree *methodtree = NULL;
105 static s4 methodtree_comparator(const void *pc, const void *element);
109 /* codegen_init ****************************************************************
113 *******************************************************************************/
115 void codegen_init(void)
117 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
118 /* this tree is global, not method specific */
121 #if defined(ENABLE_JIT)
122 methodtree_element *mte;
125 methodtree = avl_create(&methodtree_comparator);
127 #if defined(ENABLE_JIT)
128 /* insert asm_vm_call_method */
130 mte = NEW(methodtree_element);
132 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
133 mte->endpc = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
135 avl_insert(methodtree, mte);
136 #endif /* defined(ENABLE_JIT) */
138 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
142 /* codegen_setup **************************************************************
144 allocates and initialises code area, data area and references
146 *******************************************************************************/
148 void codegen_setup(methodinfo *m, codegendata *cd)
150 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
151 cd->mcodesize = MCODEINITSIZE;
153 /* initialize mcode variables */
155 cd->mcodeptr = cd->mcodebase;
156 cd->mcodeend = (s4 *) (cd->mcodebase + MCODEINITSIZE);
158 #if defined(ENABLE_INTRP)
159 /* native dynamic superinstructions variables */
162 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
163 cd->ncodesize = NCODEINITSIZE;
165 /* initialize ncode variables */
167 cd->ncodeptr = cd->ncodebase;
169 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
170 cd->superstarts = NULL;
174 cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
175 cd->dsegsize = DSEGINITSIZE;
176 cd->dsegtop += cd->dsegsize;
179 cd->jumpreferences = NULL;
181 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
182 cd->datareferences = NULL;
185 cd->exceptionrefs = NULL;
186 cd->patchrefs = NULL;
188 cd->linenumberreferences = NULL;
189 cd->linenumbertablesizepos = 0;
190 cd->linenumbertablestartpos = 0;
191 cd->linenumbertab = 0;
194 cd->code = code_codeinfo_new(m); /* XXX check allocation */
195 cd->exceptiontable = 0;
196 cd->exceptiontablelength = 0;
198 if (m->exceptiontablelength > 0) {
199 cd->exceptiontablelength = m->exceptiontablelength;
200 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
203 cd->maxstack = m->maxstack;
204 cd->maxlocals = m->maxlocals;
206 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
207 cd->threadcritcurrent.next = NULL;
208 cd->threadcritcount = 0;
213 /* codegen_free ****************************************************************
215 Releases temporary code and data area.
217 *******************************************************************************/
219 void codegen_free(methodinfo *m, codegendata *cd)
224 MFREE(cd->mcodebase, u1, cd->mcodesize);
225 cd->mcodebase = NULL;
229 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
237 /* codegen_close ***************************************************************
241 *******************************************************************************/
243 void codegen_close(void)
245 /* TODO: release avl tree on i386 and x86_64 */
249 /* codegen_increase ************************************************************
253 *******************************************************************************/
255 s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
259 /* save old mcodebase pointer */
261 oldmcodebase = cd->mcodebase;
263 /* reallocate to new, doubled memory */
265 cd->mcodebase = DMREALLOC(cd->mcodebase,
270 cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
272 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
273 /* adjust the pointer to the last patcher position */
275 if (cd->lastmcodeptr != NULL)
276 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
279 /* return the new mcodeptr */
281 return (s4 *) (cd->mcodebase + (mcodeptr - oldmcodebase));
285 /* codegen_ncode_increase ******************************************************
289 *******************************************************************************/
291 #if defined(ENABLE_INTRP)
292 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
296 /* save old ncodebase pointer */
298 oldncodebase = cd->ncodebase;
300 /* reallocate to new, doubled memory */
302 cd->ncodebase = DMREALLOC(cd->ncodebase,
308 /* return the new ncodeptr */
310 return (cd->ncodebase + (ncodeptr - oldncodebase));
315 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
319 branchpos = (u1 *) branchptr - cd->mcodebase;
321 #if defined(ENABLE_JIT)
322 /* Check if the target basicblock has already a start pc, so the
323 jump is backward and we can resolve it immediately. */
325 /* The interpreter uses absolute branches, so we do branch
326 resolving after the code and data segment move. */
329 # if defined(ENABLE_INTRP)
334 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
341 branchref *br = DNEW(branchref);
343 br->branchpos = branchpos;
344 br->next = target->branchrefs;
346 target->branchrefs = br;
351 /* codegen_add_exception_ref ***************************************************
353 Adds an exception branch to the list.
355 *******************************************************************************/
357 static void codegen_add_exception_ref(codegendata *cd, void *branchptr, s4 reg,
358 functionptr function)
363 branchpos = (u1 *) branchptr - cd->mcodebase;
365 eref = DNEW(exceptionref);
367 eref->branchpos = branchpos;
369 eref->function = function;
370 eref->next = cd->exceptionrefs;
372 cd->exceptionrefs = eref;
376 /* codegen_add_arithmeticexception_ref *****************************************
378 Adds an ArithmeticException branch to the list.
380 *******************************************************************************/
382 void codegen_add_arithmeticexception_ref(codegendata *cd, void *branchptr)
384 codegen_add_exception_ref(cd, branchptr, -1,
385 STACKTRACE_inline_arithmeticexception);
389 /* codegen_add_arrayindexoutofboundsexception_ref ******************************
391 Adds an ArrayIndexOutOfBoundsException branch to the list.
393 *******************************************************************************/
395 void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd,
396 void *branchptr, s4 reg)
398 codegen_add_exception_ref(cd, branchptr, reg,
399 STACKTRACE_inline_arrayindexoutofboundsexception);
403 /* codegen_add_arraystoreexception_ref *****************************************
405 Adds an ArrayStoreException branch to the list.
407 *******************************************************************************/
409 void codegen_add_arraystoreexception_ref(codegendata *cd, void *branchptr)
411 codegen_add_exception_ref(cd, branchptr, -1,
412 STACKTRACE_inline_arraystoreexception);
416 /* codegen_add_classcastexception_ref ******************************************
418 Adds an ClassCastException branch to the list.
420 *******************************************************************************/
422 void codegen_add_classcastexception_ref(codegendata *cd, void *branchptr)
424 codegen_add_exception_ref(cd, branchptr, -1,
425 STACKTRACE_inline_classcastexception);
429 /* codegen_add_nullpointerexception_ref ****************************************
431 Adds an NullPointerException branch to the list.
433 *******************************************************************************/
435 void codegen_add_nullpointerexception_ref(codegendata *cd, void *branchptr)
437 codegen_add_exception_ref(cd, branchptr, -1,
438 STACKTRACE_inline_nullpointerexception);
442 /* codegen_add_fillinstacktrace_ref ********************************************
444 Adds a fillInStackTrace branch to the list.
446 *******************************************************************************/
448 void codegen_add_fillinstacktrace_ref(codegendata *cd, void *branchptr)
450 codegen_add_exception_ref(cd, branchptr, -1,
451 STACKTRACE_inline_fillInStackTrace);
455 /* codegen_addpatchref *********************************************************
457 Adds a new patcher reference to the list of patching positions.
459 *******************************************************************************/
461 void codegen_addpatchref(codegendata *cd, voidptr branchptr,
462 functionptr patcher, voidptr ref, s4 disp)
467 branchpos = (u1 *) branchptr - cd->mcodebase;
471 pr->branchpos = branchpos;
472 pr->patcher = patcher;
476 pr->next = cd->patchrefs;
479 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
480 /* On some architectures the patcher stub call instruction might
481 be longer than the actual instruction generated. On this
482 architectures we store the last patcher call position and after
483 the basic block code generation is completed, we check the
484 range and maybe generate some nop's. */
486 cd->lastmcodeptr = ((u1 *) branchptr) + PATCHER_CALL_SIZE;
491 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
492 /* methodtree_comparator *******************************************************
496 *******************************************************************************/
498 static s4 methodtree_comparator(const void *pc, const void *element)
500 methodtree_element *mte;
501 methodtree_element *mtepc;
503 mte = (methodtree_element *) element;
504 mtepc = (methodtree_element *) pc;
506 /* compare both startpc and endpc of pc, even if they have the same value,
507 otherwise the avl_probe sometimes thinks the element is already in the
510 if ((long) mte->startpc <= (long) mtepc->startpc &&
511 (long) mtepc->startpc <= (long) mte->endpc &&
512 (long) mte->startpc <= (long) mtepc->endpc &&
513 (long) mtepc->endpc <= (long) mte->endpc) {
516 } else if ((long) mtepc->startpc < (long) mte->startpc) {
525 /* codegen_insertmethod ********************************************************
529 *******************************************************************************/
531 void codegen_insertmethod(u1 *startpc, u1 *endpc)
533 methodtree_element *mte;
535 /* allocate new method entry */
537 mte = NEW(methodtree_element);
539 mte->startpc = startpc;
542 /* this function does not return an error, but asserts for
545 avl_insert(methodtree, mte);
549 /* codegen_findmethod **********************************************************
553 *******************************************************************************/
555 u1 *codegen_findmethod(u1 *pc)
557 methodtree_element mtepc;
558 methodtree_element *mte;
560 /* allocation of the search structure on the stack is much faster */
565 mte = avl_find(methodtree, &mtepc);
568 printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
571 throw_cacao_exception_exit(string_java_lang_InternalError,
572 "Cannot find Java function at %p", pc);
577 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
580 /* codegen_finish **************************************************************
582 Finishes the code generation. A new memory, large enough for both
583 data and code, is allocated and data and code are copied together
584 to their final layout, unresolved jumps are resolved, ...
586 *******************************************************************************/
588 void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
593 #if defined(ENABLE_INTRP)
605 /* prevent compiler warning */
607 #if defined(ENABLE_INTRP)
611 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
612 extralen = sizeof(threadcritnode) * cd->threadcritcount;
617 #if defined(ENABLE_STATISTICS)
619 count_code_len += mcodelen;
620 count_data_len += cd->dseglen;
625 mcodelen = cd->mcodeptr - cd->mcodebase;
627 alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
629 #if defined(ENABLE_INTRP)
631 ncodelen = cd->ncodeptr - cd->ncodebase;
633 ncodelen = 0; /* avoid compiler warning */
637 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
638 alignedlen = alignedmcodelen + cd->dseglen;
640 #if defined(ENABLE_INTRP)
642 alignedlen += ncodelen;
646 /* allocate new memory */
648 code->mcodelength = mcodelen + cd->dseglen;
649 code->mcode = CNEW(u1, alignedlen + extralen);
651 /* copy data and code to their new location */
653 MCOPY((void *) code->mcode, cd->dsegtop - cd->dseglen, u1, cd->dseglen);
654 MCOPY((void *) (code->mcode + cd->dseglen), cd->mcodebase, u1, mcodelen);
656 /* set the entrypoint of the method */
658 assert(code->entrypoint == NULL);
659 code->entrypoint = epoint = (code->mcode + cd->dseglen);
661 #if defined(ENABLE_INTRP)
662 /* relocate native dynamic superinstruction code (if any) */
665 cd->mcodebase = code->entrypoint;
668 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
670 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
672 /* flush the instruction and data caches */
674 md_cacheflush(ncodebase, ncodelen);
676 /* set some cd variables for dynamic_super_rerwite */
678 cd->ncodebase = ncodebase;
681 cd->ncodebase = NULL;
684 dynamic_super_rewrite(cd);
688 /* jump table resolving */
690 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
691 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
692 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
694 /* line number table resolving */
700 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
702 target = lr->targetmpc;
703 /* if the entry contains an mcode pointer (normal case), resolve it */
704 /* (see doc/inlining_stacktrace.txt for details) */
705 if (lr->linenumber >= -2) {
706 target += (ptrint) epoint;
708 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
709 (functionptr) target;
712 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
713 (functionptr) ((ptrint) epoint + cd->linenumbertab);
715 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
718 /* replacement point resolving */
723 rp = code->rplpoints;
724 for (i=0; i<code->rplpointcount; ++i, ++rp) {
725 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
726 rp->outcode = (u1*) ((ptrint) epoint + (ptrint) rp->outcode);
730 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
731 /* add method into methodtree to find the entrypoint */
733 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
737 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
738 /* resolve data segment references */
740 dseg_resolve_datareferences(cd, m);
744 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
746 threadcritnode *n = (threadcritnode *) ((ptrint) code->mcode + alignedlen);
748 threadcritnodetemp *nt = cd->threadcrit;
750 for (i = 0; i < cd->threadcritcount; i++) {
751 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
752 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
753 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
754 thread_registercritical(n);
761 /* flush the instruction and data caches */
763 md_cacheflush(code->mcode, code->mcodelength);
767 /* codegen_createnativestub ****************************************************
769 Wrapper for createnativestub.
772 the codeinfo representing the stub code.
774 *******************************************************************************/
776 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
786 /* mark dump memory */
788 dumpsize = dump_size();
790 cd = DNEW(codegendata);
791 rd = DNEW(registerdata);
793 /* setup code generation stuff */
795 #if defined(ENABLE_JIT)
796 # if defined(ENABLE_INTRP)
802 codegen_setup(m, cd);
806 /* create new method descriptor with additional native parameters */
809 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
811 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
812 md->paramcount * sizeof(typedesc) +
813 nativeparams * sizeof(typedesc));
815 nmd->paramcount = md->paramcount + nativeparams;
817 nmd->params = DMNEW(paramdesc, nmd->paramcount);
819 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
821 if (m->flags & ACC_STATIC)
822 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
824 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
827 #if defined(ENABLE_JIT)
828 # if defined(ENABLE_INTRP)
834 /* generate the code */
836 #if defined(ENABLE_JIT)
837 # if defined(ENABLE_INTRP)
839 code->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
842 code->entrypoint = createnativestub(f, m, cd, rd, nmd);
844 code->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
847 #if defined(ENABLE_STATISTICS)
849 count_nstub_len += code->mcodelength;
853 /* disassemble native stub */
855 if (opt_shownativestub) {
856 codegen_disassemble_nativestub(m,
857 (u1 *) (ptrint) code->entrypoint,
858 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - cd->dseglen));
860 /* show data segment */
862 if (opt_showddatasegment)
865 #endif /* !defined(NDEBUG) */
869 dump_release(dumpsize);
871 /* return native stub code */
877 /* codegen_disassemble_nativestub **********************************************
879 Disassembles the generated native stub.
881 *******************************************************************************/
884 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
886 printf("Native stub: ");
887 utf_fprint_classname(stdout, m->class->name);
889 utf_fprint(stdout, m->name);
890 utf_fprint(stdout, m->descriptor);
891 printf("\n\nLength: %d\n\n", (s4) (end - start));
893 DISASSEMBLE(start, end);
898 /* codegen_start_native_call ***************************************************
900 Prepares the stuff required for a native (JNI) function call:
902 - adds a stackframe info structure to the chain, for stacktraces
903 - prepares the local references table on the stack
905 The layout of the native stub stackframe should look like this:
907 +---------------------------+ <- SP (of parent Java function)
909 +---------------------------+
911 | stackframe info structure |
913 +---------------------------+
915 | local references table |
917 +---------------------------+
919 | arguments (if any) |
921 +---------------------------+ <- SP (native stub)
923 *******************************************************************************/
925 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
930 /* get data structures from stack */
932 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
933 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
934 sizeof(localref_table));
936 /* add a stackframeinfo to the chain */
938 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
940 /* add current JNI local references table to this thread */
942 lrt->capacity = LOCALREFTABLE_CAPACITY;
944 lrt->localframes = 1;
945 lrt->prev = LOCALREFTABLE;
947 /* clear the references array (memset is faster the a for-loop) */
949 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
955 /* codegen_finish_native_call **************************************************
957 Removes the stuff required for a native (JNI) function call.
959 *******************************************************************************/
961 void codegen_finish_native_call(u1 *datasp)
964 stackframeinfo **psfi;
966 localref_table *plrt;
969 /* get data structures from stack */
971 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
972 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
973 sizeof(localref_table));
975 /* remove current stackframeinfo from chain */
977 psfi = STACKFRAMEINFO;
981 /* release JNI local references tables for this thread */
985 /* release all current local frames */
987 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
988 /* get previous frame */
992 /* Clear all reference entries (only for tables allocated on
996 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1000 /* set new local references table */
1005 /* now store the previous local frames in the thread structure */
1007 LOCALREFTABLE = lrt;
1011 /* removecompilerstub **********************************************************
1013 Deletes a compilerstub from memory (simply by freeing it).
1015 *******************************************************************************/
1017 void removecompilerstub(u1 *stub)
1019 /* pass size 1 to keep the intern function happy */
1021 CFREE((void *) stub, 1);
1025 /* removenativestub ************************************************************
1027 Removes a previously created native-stub from memory.
1029 *******************************************************************************/
1031 void removenativestub(u1 *stub)
1033 /* pass size 1 to keep the intern function happy */
1035 CFREE((void *) stub, 1);
1039 /* reg_of_var ******************************************************************
1041 This function determines a register, to which the result of an
1042 operation should go, when it is ultimatively intended to store the
1043 result in pseudoregister v. If v is assigned to an actual
1044 register, this register will be returned. Otherwise (when v is
1045 spilled) this function returns tempregnum. If not already done,
1046 regoff and flags are set in the stack location.
1048 On ARM we have to check if a long/double variable is splitted
1049 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1050 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1051 cases. (michi 2005/07/24)
1053 *******************************************************************************/
1055 s4 reg_of_var(registerdata *rd, stackptr v, s4 tempregnum)
1059 switch (v->varkind) {
1061 if (!(v->flags & INMEMORY))
1066 var = &(rd->interfaces[v->varnum][v->type]);
1067 v->regoff = var->regoff;
1068 if (!(var->flags & INMEMORY))
1069 return(var->regoff);
1073 var = &(rd->locals[v->varnum][v->type]);
1074 v->regoff = var->regoff;
1075 if (!(var->flags & INMEMORY)) {
1076 #if defined(__ARM__) && defined(__ARMEL__)
1077 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1078 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1080 #if defined(__ARM__) && defined(__ARMEB__)
1081 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1082 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1084 return(var->regoff);
1089 if (!(v->flags & INMEMORY)) {
1090 #if defined(__ARM__) && defined(__ARMEL__)
1091 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1092 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1094 #if defined(__ARM__) && defined(__ARMEB__)
1095 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1096 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1103 #if defined(ENABLE_STATISTICS)
1105 count_spills_read++;
1108 v->flags |= INMEMORY;
1114 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1115 void codegen_threadcritrestart(codegendata *cd, int offset)
1117 cd->threadcritcurrent.mcoderestart = offset;
1121 void codegen_threadcritstart(codegendata *cd, int offset)
1123 cd->threadcritcurrent.mcodebegin = offset;
1127 void codegen_threadcritstop(codegendata *cd, int offset)
1129 cd->threadcritcurrent.next = cd->threadcrit;
1130 cd->threadcritcurrent.mcodeend = offset;
1131 cd->threadcrit = DNEW(threadcritnodetemp);
1132 *(cd->threadcrit) = cd->threadcritcurrent;
1133 cd->threadcritcount++;
1139 * These are local overrides for various environment variables in Emacs.
1140 * Please do not remove this and leave it at the end of the file, where
1141 * Emacs will automagically detect them.
1142 * ---------------------------------------------------------------------
1145 * indent-tabs-mode: t
1149 * vim:noexpandtab:sw=4:ts=4: