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 4606 2006-03-15 04:43:25Z edwin $
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->xboundrefs = NULL;
186 cd->xnullrefs = NULL;
187 cd->xcastrefs = NULL;
188 cd->xstorerefs = NULL;
190 cd->xexceptionrefs = NULL;
191 cd->patchrefs = NULL;
193 cd->linenumberreferences = NULL;
194 cd->linenumbertablesizepos = 0;
195 cd->linenumbertablestartpos = 0;
196 cd->linenumbertab = 0;
199 cd->code = code_codeinfo_new(m); /* XXX check allocation */
200 cd->exceptiontable = 0;
201 cd->exceptiontablelength = 0;
203 if (m->exceptiontablelength > 0) {
204 cd->exceptiontablelength = m->exceptiontablelength;
205 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
208 cd->maxstack = m->maxstack;
209 cd->maxlocals = m->maxlocals;
211 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
212 cd->threadcritcurrent.next = NULL;
213 cd->threadcritcount = 0;
218 /* codegen_free ****************************************************************
220 Releases temporary code and data area.
222 *******************************************************************************/
224 void codegen_free(methodinfo *m, codegendata *cd)
229 MFREE(cd->mcodebase, u1, cd->mcodesize);
230 cd->mcodebase = NULL;
234 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
242 /* codegen_close ***************************************************************
246 *******************************************************************************/
248 void codegen_close(void)
250 /* TODO: release avl tree on i386 and x86_64 */
254 /* codegen_increase ************************************************************
258 *******************************************************************************/
260 s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
264 /* save old mcodebase pointer */
266 oldmcodebase = cd->mcodebase;
268 /* reallocate to new, doubled memory */
270 cd->mcodebase = DMREALLOC(cd->mcodebase,
275 cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
277 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
278 /* adjust the pointer to the last patcher position */
280 if (cd->lastmcodeptr != NULL)
281 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
284 /* return the new mcodeptr */
286 return (s4 *) (cd->mcodebase + (mcodeptr - oldmcodebase));
290 /* codegen_ncode_increase ******************************************************
294 *******************************************************************************/
296 #if defined(ENABLE_INTRP)
297 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
301 /* save old ncodebase pointer */
303 oldncodebase = cd->ncodebase;
305 /* reallocate to new, doubled memory */
307 cd->ncodebase = DMREALLOC(cd->ncodebase,
313 /* return the new ncodeptr */
315 return (cd->ncodebase + (ncodeptr - oldncodebase));
320 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
324 branchpos = (u1 *) branchptr - cd->mcodebase;
326 #if defined(ENABLE_JIT)
327 /* Check if the target basicblock has already a start pc, so the
328 jump is backward and we can resolve it immediately. */
330 /* The interpreter uses absolute branches, so we do branch
331 resolving after the code and data segment move. */
334 # if defined(ENABLE_INTRP)
339 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
346 branchref *br = DNEW(branchref);
348 br->branchpos = branchpos;
349 br->next = target->branchrefs;
351 target->branchrefs = br;
356 /* codegen_addxboundrefs *******************************************************
358 Adds an ArrayIndexOutOfBoundsException branch to the list.
360 *******************************************************************************/
362 void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
367 branchpos = (u1 *) branchptr - cd->mcodebase;
369 br = DNEW(branchref);
371 br->branchpos = branchpos;
373 br->next = cd->xboundrefs;
379 /* codegen_addxcastrefs ********************************************************
381 Adds an ClassCastException branch to the list.
383 *******************************************************************************/
385 void codegen_addxcastrefs(codegendata *cd, void *branchptr)
390 branchpos = (u1 *) branchptr - cd->mcodebase;
392 br = DNEW(branchref);
394 br->branchpos = branchpos;
395 br->next = cd->xcastrefs;
401 /* codegen_addxdivrefs *********************************************************
403 Adds an ArithmeticException branch to the list.
405 *******************************************************************************/
407 void codegen_addxdivrefs(codegendata *cd, void *branchptr)
412 branchpos = (u1 *) branchptr - cd->mcodebase;
414 br = DNEW(branchref);
416 br->branchpos = branchpos;
417 br->next = cd->xdivrefs;
423 /* codegen_addxstorerefs *******************************************************
425 Adds an ArrayStoreException branch to the list.
427 *******************************************************************************/
429 void codegen_addxstorerefs(codegendata *cd, void *branchptr)
434 branchpos = (u1 *) branchptr - cd->mcodebase;
436 br = DNEW(branchref);
438 br->branchpos = branchpos;
439 br->next = cd->xstorerefs;
445 /* codegen_addxnullrefs ********************************************************
447 Adds an NullPointerException branch to the list.
449 *******************************************************************************/
451 void codegen_addxnullrefs(codegendata *cd, void *branchptr)
456 branchpos = (u1 *) branchptr - cd->mcodebase;
458 br = DNEW(branchref);
460 br->branchpos = branchpos;
461 br->next = cd->xnullrefs;
467 /* codegen_addxexceptionsrefs **************************************************
469 Adds an common exception branch to the list.
471 *******************************************************************************/
473 void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
478 branchpos = (u1 *) branchptr - cd->mcodebase;
480 br = DNEW(branchref);
482 br->branchpos = branchpos;
483 br->next = cd->xexceptionrefs;
485 cd->xexceptionrefs = br;
489 /* codegen_addpatchref *********************************************************
491 Adds a new patcher reference to the list of patching positions.
493 *******************************************************************************/
495 void codegen_addpatchref(codegendata *cd, voidptr branchptr,
496 functionptr patcher, voidptr ref, s4 disp)
501 branchpos = (u1 *) branchptr - cd->mcodebase;
505 pr->branchpos = branchpos;
506 pr->patcher = patcher;
510 pr->next = cd->patchrefs;
513 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
514 /* On some architectures the patcher stub call instruction might
515 be longer than the actual instruction generated. On this
516 architectures we store the last patcher call position and after
517 the basic block code generation is completed, we check the
518 range and maybe generate some nop's. */
520 cd->lastmcodeptr = ((u1 *) branchptr) + PATCHER_CALL_SIZE;
525 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
526 /* methodtree_comparator *******************************************************
530 *******************************************************************************/
532 static s4 methodtree_comparator(const void *pc, const void *element)
534 methodtree_element *mte;
535 methodtree_element *mtepc;
537 mte = (methodtree_element *) element;
538 mtepc = (methodtree_element *) pc;
540 /* compare both startpc and endpc of pc, even if they have the same value,
541 otherwise the avl_probe sometimes thinks the element is already in the
544 if ((long) mte->startpc <= (long) mtepc->startpc &&
545 (long) mtepc->startpc <= (long) mte->endpc &&
546 (long) mte->startpc <= (long) mtepc->endpc &&
547 (long) mtepc->endpc <= (long) mte->endpc) {
550 } else if ((long) mtepc->startpc < (long) mte->startpc) {
559 /* codegen_insertmethod ********************************************************
563 *******************************************************************************/
565 void codegen_insertmethod(u1 *startpc, u1 *endpc)
567 methodtree_element *mte;
569 /* allocate new method entry */
571 mte = NEW(methodtree_element);
573 mte->startpc = startpc;
576 /* this function does not return an error, but asserts for
579 avl_insert(methodtree, mte);
583 /* codegen_findmethod **********************************************************
587 *******************************************************************************/
589 u1 *codegen_findmethod(u1 *pc)
591 methodtree_element mtepc;
592 methodtree_element *mte;
594 /* allocation of the search structure on the stack is much faster */
599 mte = avl_find(methodtree, &mtepc);
602 printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
605 throw_cacao_exception_exit(string_java_lang_InternalError,
606 "Cannot find Java function at %p", pc);
611 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
614 /* codegen_finish **************************************************************
616 Finishes the code generation. A new memory, large enough for both
617 data and code, is allocated and data and code are copied together
618 to their final layout, unresolved jumps are resolved, ...
620 *******************************************************************************/
622 void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
627 #if defined(ENABLE_INTRP)
639 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
640 extralen = sizeof(threadcritnode) * cd->threadcritcount;
645 #if defined(ENABLE_STATISTICS)
647 count_code_len += mcodelen;
648 count_data_len += cd->dseglen;
653 mcodelen = cd->mcodeptr - cd->mcodebase;
655 alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
657 #if defined(ENABLE_INTRP)
659 ncodelen = cd->ncodeptr - cd->ncodebase;
663 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
664 alignedlen = alignedmcodelen + cd->dseglen;
666 #if defined(ENABLE_INTRP)
668 alignedlen += ncodelen;
672 /* allocate new memory */
674 code->mcodelength = mcodelen + cd->dseglen;
675 code->mcode = CNEW(u1, alignedlen + extralen);
677 /* copy data and code to their new location */
679 MCOPY((void *) code->mcode, cd->dsegtop - cd->dseglen, u1, cd->dseglen);
680 MCOPY((void *) (code->mcode + cd->dseglen), cd->mcodebase, u1, mcodelen);
682 /* set the entrypoint of the method */
684 assert(code->entrypoint == NULL);
685 code->entrypoint = epoint = (code->mcode + cd->dseglen);
687 #if defined(ENABLE_INTRP)
688 /* relocate native dynamic superinstruction code (if any) */
691 cd->mcodebase = code->entrypoint;
694 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
695 MCOPY((void *)ncodebase, cd->ncodebase, u1, ncodelen);
696 /* XXX cacheflush((void *)ncodebase, ncodelen); */
697 /* set some cd variables for dynamic_super_rerwite */
699 cd->ncodebase = ncodebase;
702 cd->ncodebase = NULL;
705 dynamic_super_rewrite(cd);
709 /* jump table resolving */
711 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
712 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
713 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
715 /* line number table resolving */
721 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
723 target = lr->targetmpc;
724 /* if the entry contains an mcode pointer (normal case), resolve it */
725 /* (see doc/inlining_stacktrace.txt for details) */
726 if (lr->linenumber >= -2) {
727 target += (ptrint) epoint;
729 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
730 (functionptr) target;
733 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
734 (functionptr) ((ptrint) epoint + cd->linenumbertab);
736 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
739 /* replacement point resolving */
744 rp = code->rplpoints;
745 for (i=0; i<code->rplpointcount; ++i, ++rp) {
746 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
747 rp->outcode = (u1*) ((ptrint) epoint + (ptrint) rp->outcode);
751 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
752 /* add method into methodtree to find the entrypoint */
754 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
758 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
759 /* resolve data segment references */
761 dseg_resolve_datareferences(cd, m);
765 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
767 threadcritnode *n = (threadcritnode *) ((ptrint) code->mcode + alignedlen);
769 threadcritnodetemp *nt = cd->threadcrit;
771 for (i = 0; i < cd->threadcritcount; i++) {
772 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
773 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
774 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
775 thread_registercritical(n);
784 /* codegen_createnativestub ****************************************************
786 Wrapper for createnativestub.
789 the codeinfo representing the stub code.
791 *******************************************************************************/
793 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
803 /* mark dump memory */
805 dumpsize = dump_size();
807 cd = DNEW(codegendata);
808 rd = DNEW(registerdata);
810 /* setup code generation stuff */
812 #if defined(ENABLE_JIT)
813 # if defined(ENABLE_INTRP)
819 codegen_setup(m, cd);
823 /* create new method descriptor with additional native parameters */
826 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
828 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
829 md->paramcount * sizeof(typedesc) +
830 nativeparams * sizeof(typedesc));
832 nmd->paramcount = md->paramcount + nativeparams;
834 nmd->params = DMNEW(paramdesc, nmd->paramcount);
836 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
838 if (m->flags & ACC_STATIC)
839 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
841 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
844 #if defined(ENABLE_JIT)
845 # if defined(ENABLE_INTRP)
851 /* generate the code */
853 #if defined(ENABLE_JIT)
854 # if defined(ENABLE_INTRP)
856 code->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
859 code->entrypoint = createnativestub(f, m, cd, rd, nmd);
861 code->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
864 #if defined(ENABLE_STATISTICS)
866 count_nstub_len += code->mcodelength;
869 /* disassemble native stub */
871 if (opt_shownativestub) {
872 codegen_disassemble_nativestub(m,
873 (u1 *) (ptrint) code->entrypoint,
874 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - cd->dseglen));
876 /* show data segment */
878 if (opt_showddatasegment)
884 dump_release(dumpsize);
886 /* return native stub code */
892 /* codegen_disassemble_nativestub **********************************************
894 Disassembles the generated native stub.
896 *******************************************************************************/
898 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
900 printf("Native stub: ");
901 utf_fprint_classname(stdout, m->class->name);
903 utf_fprint(stdout, m->name);
904 utf_fprint(stdout, m->descriptor);
905 printf("\n\nLength: %d\n\n", (s4) (end - start));
907 DISASSEMBLE(start, end);
911 /* codegen_start_native_call ***************************************************
913 Prepares the stuff required for a native (JNI) function call:
915 - adds a stackframe info structure to the chain, for stacktraces
916 - prepares the local references table on the stack
918 The layout of the native stub stackframe should look like this:
920 +---------------------------+ <- SP (of parent Java function)
922 +---------------------------+
924 | stackframe info structure |
926 +---------------------------+
928 | local references table |
930 +---------------------------+
932 | arguments (if any) |
934 +---------------------------+ <- SP (native stub)
936 *******************************************************************************/
938 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
943 /* get data structures from stack */
945 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
946 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
947 sizeof(localref_table));
949 /* add a stackframeinfo to the chain */
951 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
953 /* add current JNI local references table to this thread */
955 lrt->capacity = LOCALREFTABLE_CAPACITY;
957 lrt->localframes = 1;
958 lrt->prev = LOCALREFTABLE;
960 /* clear the references array (memset is faster the a for-loop) */
962 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
968 /* codegen_finish_native_call **************************************************
970 Removes the stuff required for a native (JNI) function call.
972 *******************************************************************************/
974 void codegen_finish_native_call(u1 *datasp)
977 stackframeinfo **psfi;
979 localref_table *plrt;
982 /* get data structures from stack */
984 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
985 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
986 sizeof(localref_table));
988 /* remove current stackframeinfo from chain */
990 psfi = STACKFRAMEINFO;
994 /* release JNI local references tables for this thread */
998 /* release all current local frames */
1000 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1001 /* get previous frame */
1005 /* Clear all reference entries (only for tables allocated on
1008 if (localframes > 1)
1009 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1013 /* set new local references table */
1018 /* now store the previous local frames in the thread structure */
1020 LOCALREFTABLE = lrt;
1024 /* removecompilerstub **********************************************************
1026 Deletes a compilerstub from memory (simply by freeing it).
1028 *******************************************************************************/
1030 void removecompilerstub(u1 *stub)
1032 /* pass size 1 to keep the intern function happy */
1034 CFREE((void *) stub, 1);
1038 /* removenativestub ************************************************************
1040 Removes a previously created native-stub from memory.
1042 *******************************************************************************/
1044 void removenativestub(u1 *stub)
1046 /* pass size 1 to keep the intern function happy */
1048 CFREE((void *) stub, 1);
1052 /* reg_of_var ******************************************************************
1054 This function determines a register, to which the result of an
1055 operation should go, when it is ultimatively intended to store the
1056 result in pseudoregister v. If v is assigned to an actual
1057 register, this register will be returned. Otherwise (when v is
1058 spilled) this function returns tempregnum. If not already done,
1059 regoff and flags are set in the stack location.
1061 On ARM we have to check if a long/double variable is splitted
1062 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1063 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1064 cases. (michi 2005/07/24)
1066 *******************************************************************************/
1068 s4 reg_of_var(registerdata *rd, stackptr v, s4 tempregnum)
1072 switch (v->varkind) {
1074 if (!(v->flags & INMEMORY))
1079 var = &(rd->interfaces[v->varnum][v->type]);
1080 v->regoff = var->regoff;
1081 if (!(var->flags & INMEMORY))
1082 return(var->regoff);
1086 var = &(rd->locals[v->varnum][v->type]);
1087 v->regoff = var->regoff;
1088 if (!(var->flags & INMEMORY)) {
1089 #if defined(__ARM__) && defined(__ARMEL__)
1090 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1091 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1093 #if defined(__ARM__) && defined(__ARMEB__)
1094 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1095 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1097 return(var->regoff);
1102 if (!(v->flags & INMEMORY)) {
1103 #if defined(__ARM__) && defined(__ARMEL__)
1104 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1105 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1107 #if defined(__ARM__) && defined(__ARMEB__)
1108 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1109 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1116 #if defined(ENABLE_STATISTICS)
1118 count_spills_read++;
1121 v->flags |= INMEMORY;
1127 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1128 void codegen_threadcritrestart(codegendata *cd, int offset)
1130 cd->threadcritcurrent.mcoderestart = offset;
1134 void codegen_threadcritstart(codegendata *cd, int offset)
1136 cd->threadcritcurrent.mcodebegin = offset;
1140 void codegen_threadcritstop(codegendata *cd, int offset)
1142 cd->threadcritcurrent.next = cd->threadcrit;
1143 cd->threadcritcurrent.mcodeend = offset;
1144 cd->threadcrit = DNEW(threadcritnodetemp);
1145 *(cd->threadcrit) = cd->threadcritcurrent;
1146 cd->threadcritcount++;
1152 * These are local overrides for various environment variables in Emacs.
1153 * Please do not remove this and leave it at the end of the file, where
1154 * Emacs will automagically detect them.
1155 * ---------------------------------------------------------------------
1158 * indent-tabs-mode: t
1162 * vim:noexpandtab:sw=4:ts=4: