1 /* src/vm/jit/codegen-common.c - architecture independent code generator stuff
3 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6 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., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Reinhard Grafl
30 Changes: Christian Thalinger
33 All functions assume the following code area / data area layout:
37 | code area | code area grows to higher addresses
39 +-----------+ <-- start of procedure
41 | data area | data area grows to lower addresses
45 The functions first write into a temporary code/data area allocated by
46 "codegen_init". "codegen_finish" copies the code and data area into permanent
47 memory. All functions writing values into the data area return the offset
48 relative the begin of the code area (start of procedure).
50 $Id: codegen-common.c 4199 2006-01-13 15:29:21Z twisti $
62 #if defined(ENABLE_JIT)
63 /* this is required for gen_resolvebranch and PATCHER_CALL_SIZE */
68 /* this is required for REG_SPLIT */
72 #include "mm/memory.h"
73 #include "toolbox/avl.h"
74 #include "toolbox/logging.h"
75 #include "native/jni.h"
76 #include "native/native.h"
78 #if defined(USE_THREADS)
79 # if defined(NATIVE_THREADS)
80 # include "threads/native/threads.h"
82 # include "threads/green/threads.h"
86 #include "vm/exceptions.h"
87 #include "vm/method.h"
88 #include "vm/options.h"
89 #include "vm/statistics.h"
90 #include "vm/stringlocal.h"
91 #include "vm/jit/asmpart.h"
92 #include "vm/jit/codegen-common.h"
93 #include "vm/jit/disass.h"
94 #include "vm/jit/dseg.h"
95 #include "vm/jit/jit.h"
96 #include "vm/jit/stacktrace.h"
99 /* in this tree we store all method addresses *********************************/
101 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
102 static avl_tree *methodtree = NULL;
103 static s4 methodtree_comparator(const void *pc, const void *element);
107 /* codegen_init ****************************************************************
111 *******************************************************************************/
113 void codegen_init(void)
115 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
116 /* this tree is global, not method specific */
119 #if defined(ENABLE_JIT)
120 methodtree_element *mte;
123 methodtree = avl_create(&methodtree_comparator);
125 #if defined(ENABLE_JIT)
126 /* insert asm_calljavafunction */
128 mte = NEW(methodtree_element);
130 mte->startpc = (u1 *) (ptrint) asm_calljavafunction;
131 mte->endpc = (u1 *) ((ptrint) asm_calljavafunction2 - 1);
133 avl_insert(methodtree, mte);
135 /* insert asm_calljavafunction2 */
137 mte = NEW(methodtree_element);
139 mte->startpc = (u1 *) (ptrint) asm_calljavafunction2;
140 mte->endpc = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
142 avl_insert(methodtree, mte);
143 #endif /* defined(ENABLE_JIT) */
145 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
149 /* codegen_setup **************************************************************
151 allocates and initialises code area, data area and references
153 *******************************************************************************/
155 void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
157 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
158 cd->mcodesize = MCODEINITSIZE;
160 /* initialize mcode variables */
162 cd->mcodeptr = cd->mcodebase;
163 cd->mcodeend = (s4 *) (cd->mcodebase + MCODEINITSIZE);
165 #if defined(ENABLE_INTRP)
166 /* native dynamic superinstructions variables */
169 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
170 cd->ncodesize = NCODEINITSIZE;
172 /* initialize ncode variables */
174 cd->ncodeptr = cd->ncodebase;
176 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
177 cd->superstarts = NULL;
181 cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
182 cd->dsegsize = DSEGINITSIZE;
183 cd->dsegtop += cd->dsegsize;
186 cd->jumpreferences = NULL;
187 cd->datareferences = NULL;
188 cd->xboundrefs = NULL;
189 cd->xnullrefs = NULL;
190 cd->xcastrefs = NULL;
191 cd->xstorerefs = NULL;
193 cd->xexceptionrefs = NULL;
194 cd->patchrefs = NULL;
196 cd->linenumberreferences = NULL;
197 cd->linenumbertablesizepos = 0;
198 cd->linenumbertablestartpos = 0;
199 cd->linenumbertab = 0;
202 cd->exceptiontable = 0;
203 cd->exceptiontablelength = 0;
205 if (useinlining && id) {
206 if (id->cumextablelength > 0) {
207 cd->exceptiontablelength = id->cumextablelength;
209 DMNEW(exceptiontable, id->cumextablelength + 1);
212 } else if (id && (id->method->exceptiontablelength > 0)) {
213 cd->exceptiontablelength = m->exceptiontablelength;
214 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
218 cd->maxstack = id->cummaxstack;
219 cd->maxlocals = id->cumlocals;
221 cd->maxstack = m->maxstack;
222 cd->maxlocals = m->maxlocals;
225 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
226 cd->threadcritcurrent.next = NULL;
227 cd->threadcritcount = 0;
232 /* codegen_free ****************************************************************
234 Releases temporary code and data area.
236 *******************************************************************************/
238 void codegen_free(methodinfo *m, codegendata *cd)
243 MFREE(cd->mcodebase, u1, cd->mcodesize);
244 cd->mcodebase = NULL;
248 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
256 /* codegen_close ***************************************************************
260 *******************************************************************************/
262 void codegen_close(void)
264 /* TODO: release avl tree on i386 and x86_64 */
268 /* codegen_increase ************************************************************
272 *******************************************************************************/
274 s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
278 /* save old mcodebase pointer */
280 oldmcodebase = cd->mcodebase;
282 /* reallocate to new, doubled memory */
284 cd->mcodebase = DMREALLOC(cd->mcodebase,
289 cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
291 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
292 /* adjust the pointer to the last patcher position */
294 if (cd->lastmcodeptr != NULL)
295 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
298 /* return the new mcodeptr */
300 return (s4 *) (cd->mcodebase + (mcodeptr - oldmcodebase));
304 /* codegen_ncode_increase ******************************************************
308 *******************************************************************************/
310 #if defined(ENABLE_INTRP)
311 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
315 /* save old ncodebase pointer */
317 oldncodebase = cd->ncodebase;
319 /* reallocate to new, doubled memory */
321 cd->ncodebase = DMREALLOC(cd->ncodebase,
327 /* return the new ncodeptr */
329 return (cd->ncodebase + (ncodeptr - oldncodebase));
334 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
338 branchpos = (u1 *) branchptr - cd->mcodebase;
340 #if !defined(ENABLE_INTRP)
341 /* The interpreter uses absolute branches, so we do branch resolving */
342 /* after the code and data segment move. */
344 /* Check if the target basicblock has already a start pc, so the jump is */
345 /* backward and we can resolve it immediately. */
347 if (target->mpc >= 0) {
348 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
355 branchref *br = DNEW(branchref);
357 br->branchpos = branchpos;
358 br->next = target->branchrefs;
360 target->branchrefs = br;
365 /* codegen_addxboundrefs *******************************************************
367 Adds an ArrayIndexOutOfBoundsException branch to the list.
369 *******************************************************************************/
371 void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
376 branchpos = (u1 *) branchptr - cd->mcodebase;
378 br = DNEW(branchref);
380 br->branchpos = branchpos;
382 br->next = cd->xboundrefs;
388 /* codegen_addxcastrefs ********************************************************
390 Adds an ClassCastException branch to the list.
392 *******************************************************************************/
394 void codegen_addxcastrefs(codegendata *cd, void *branchptr)
399 branchpos = (u1 *) branchptr - cd->mcodebase;
401 br = DNEW(branchref);
403 br->branchpos = branchpos;
404 br->next = cd->xcastrefs;
410 /* codegen_addxdivrefs *********************************************************
412 Adds an ArithmeticException branch to the list.
414 *******************************************************************************/
416 void codegen_addxdivrefs(codegendata *cd, void *branchptr)
421 branchpos = (u1 *) branchptr - cd->mcodebase;
423 br = DNEW(branchref);
425 br->branchpos = branchpos;
426 br->next = cd->xdivrefs;
432 /* codegen_addxstorerefs *******************************************************
434 Adds an ArrayStoreException branch to the list.
436 *******************************************************************************/
438 void codegen_addxstorerefs(codegendata *cd, void *branchptr)
443 branchpos = (u1 *) branchptr - cd->mcodebase;
445 br = DNEW(branchref);
447 br->branchpos = branchpos;
448 br->next = cd->xstorerefs;
454 /* codegen_addxnullrefs ********************************************************
456 Adds an NullPointerException branch to the list.
458 *******************************************************************************/
460 void codegen_addxnullrefs(codegendata *cd, void *branchptr)
465 branchpos = (u1 *) branchptr - cd->mcodebase;
467 br = DNEW(branchref);
469 br->branchpos = branchpos;
470 br->next = cd->xnullrefs;
476 /* codegen_addxexceptionsrefs **************************************************
478 Adds an common exception branch to the list.
480 *******************************************************************************/
482 void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
487 branchpos = (u1 *) branchptr - cd->mcodebase;
489 br = DNEW(branchref);
491 br->branchpos = branchpos;
492 br->next = cd->xexceptionrefs;
494 cd->xexceptionrefs = br;
498 /* codegen_addpatchref *********************************************************
500 Adds a new patcher reference to the list of patching positions.
502 *******************************************************************************/
504 void codegen_addpatchref(codegendata *cd, voidptr branchptr,
505 functionptr patcher, voidptr ref, s4 disp)
510 branchpos = (u1 *) branchptr - cd->mcodebase;
514 pr->branchpos = branchpos;
515 pr->patcher = patcher;
519 pr->next = cd->patchrefs;
522 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
523 /* On some architectures the patcher stub call instruction might
524 be longer than the actual instruction generated. On this
525 architectures we store the last patcher call position and after
526 the basic block code generation is completed, we check the
527 range and maybe generate some nop's. */
529 cd->lastmcodeptr = ((u1 *) branchptr) + PATCHER_CALL_SIZE;
534 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
535 /* methodtree_comparator *******************************************************
539 *******************************************************************************/
541 static s4 methodtree_comparator(const void *pc, const void *element)
543 methodtree_element *mte;
544 methodtree_element *mtepc;
546 mte = (methodtree_element *) element;
547 mtepc = (methodtree_element *) pc;
549 /* compare both startpc and endpc of pc, even if they have the same value,
550 otherwise the avl_probe sometimes thinks the element is already in the
553 if ((long) mte->startpc <= (long) mtepc->startpc &&
554 (long) mtepc->startpc <= (long) mte->endpc &&
555 (long) mte->startpc <= (long) mtepc->endpc &&
556 (long) mtepc->endpc <= (long) mte->endpc) {
559 } else if ((long) mtepc->startpc < (long) mte->startpc) {
568 /* codegen_insertmethod ********************************************************
572 *******************************************************************************/
574 void codegen_insertmethod(u1 *startpc, u1 *endpc)
576 methodtree_element *mte;
578 /* allocate new method entry */
580 mte = NEW(methodtree_element);
582 mte->startpc = startpc;
585 /* this function does not return an error, but asserts for
588 avl_insert(methodtree, mte);
592 /* codegen_findmethod **********************************************************
596 *******************************************************************************/
598 u1 *codegen_findmethod(u1 *pc)
600 methodtree_element mtepc;
601 methodtree_element *mte;
603 /* allocation of the search structure on the stack is much faster */
608 mte = avl_find(methodtree, &mtepc);
611 printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
614 throw_cacao_exception_exit(string_java_lang_InternalError,
615 "Cannot find Java function at %p", pc);
620 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
623 /* codegen_finish **************************************************************
625 Finishes the code generation. A new memory, large enough for both
626 data and code, is allocated and data and code are copied together
627 to their final layout, unresolved jumps are resolved, ...
629 *******************************************************************************/
631 void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
636 #if defined(ENABLE_INTRP)
645 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
646 extralen = sizeof(threadcritnode) * cd->threadcritcount;
651 #if defined(ENABLE_STATISTICS)
653 count_code_len += mcodelen;
654 count_data_len += cd->dseglen;
659 mcodelen = cd->mcodeptr - cd->mcodebase;
661 alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
663 #if defined(ENABLE_INTRP)
665 ncodelen = cd->ncodeptr - cd->ncodebase;
669 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
670 alignedlen = alignedmcodelen + cd->dseglen;
672 #if defined(ENABLE_INTRP)
674 alignedlen += ncodelen;
678 /* allocate new memory */
680 m->mcodelength = mcodelen + cd->dseglen;
681 m->mcode = CNEW(u1, alignedlen + extralen);
683 /* copy data and code to their new location */
685 MCOPY((void *) m->mcode, cd->dsegtop - cd->dseglen, u1, cd->dseglen);
686 MCOPY((void *) (m->mcode + cd->dseglen), cd->mcodebase, u1, mcodelen);
688 m->entrypoint = epoint = (m->mcode + cd->dseglen);
690 #if defined(ENABLE_INTRP)
691 /* relocate native dynamic superinstruction code (if any) */
694 cd->mcodebase = m->entrypoint;
697 u1 *ncodebase = m->mcode + cd->dseglen + alignedmcodelen;
698 MCOPY((void *)ncodebase, cd->ncodebase, u1, ncodelen);
699 /* XXX cacheflush((void *)ncodebase, ncodelen); */
700 /* set some cd variables for dynamic_super_rerwite */
702 cd->ncodebase = ncodebase;
705 cd->ncodebase = NULL;
708 dynamic_super_rewrite(cd);
712 /* jump table resolving */
714 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
715 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
716 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
718 /* line number table resolving */
723 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
725 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
726 (functionptr) ((ptrint) epoint + (ptrint) lr->targetmpc);
729 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
730 (functionptr) ((ptrint) epoint + cd->linenumbertab);
732 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
735 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
736 /* add method into methodtree to find the entrypoint */
738 codegen_insertmethod(m->entrypoint, m->entrypoint + mcodelen);
742 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
743 /* resolve data segment references */
745 dseg_resolve_datareferences(cd, m);
749 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
751 threadcritnode *n = (threadcritnode *) ((ptrint) m->mcode + alignedlen);
753 threadcritnodetemp *nt = cd->threadcrit;
755 for (i = 0; i < cd->threadcritcount; i++) {
756 n->mcodebegin = (u1 *) (ptrint) m->mcode + nt->mcodebegin;
757 n->mcodeend = (u1 *) (ptrint) m->mcode + nt->mcodeend;
758 n->mcoderestart = (u1 *) (ptrint) m->mcode + nt->mcoderestart;
759 thread_registercritical(n);
768 /* codegen_createnativestub ****************************************************
770 Wrapper for createnativestub.
772 *******************************************************************************/
774 u1 *codegen_createnativestub(functionptr f, methodinfo *m)
778 t_inlining_globals *id;
784 /* mark dump memory */
786 dumpsize = dump_size();
788 cd = DNEW(codegendata);
789 rd = DNEW(registerdata);
790 id = DNEW(t_inlining_globals);
792 /* setup code generation stuff */
794 inlining_setup(m, id);
796 #if defined(ENABLE_JIT)
797 # if defined(ENABLE_INTRP)
800 reg_setup(m, rd, id);
803 codegen_setup(m, cd, id);
805 /* create new method descriptor with additional native parameters */
808 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
810 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
811 md->paramcount * sizeof(typedesc) +
812 nativeparams * sizeof(typedesc));
814 nmd->paramcount = md->paramcount + nativeparams;
816 nmd->params = DMNEW(paramdesc, nmd->paramcount);
818 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
820 if (m->flags & ACC_STATIC)
821 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
823 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
826 #if defined(ENABLE_JIT)
827 # if defined(ENABLE_INTRP)
833 /* generate the code */
835 #if defined(ENABLE_JIT)
836 # if defined(ENABLE_INTRP)
838 m->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
841 m->entrypoint = createnativestub(f, m, cd, rd, nmd);
843 m->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
846 #if defined(ENABLE_STATISTICS)
848 count_nstub_len += m->mcodelength;
851 /* disassemble native stub */
853 if (opt_shownativestub) {
854 codegen_disassemble_nativestub(m,
855 (u1 *) (ptrint) m->entrypoint,
856 (u1 *) (ptrint) m->entrypoint + (m->mcodelength - cd->dseglen));
858 /* show data segment */
860 if (opt_showddatasegment)
866 dump_release(dumpsize);
868 /* return native stub entry point */
870 return m->entrypoint;
874 /* codegen_disassemble_nativestub **********************************************
876 Disassembles the generated native stub.
878 *******************************************************************************/
880 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
882 printf("Native stub: ");
883 utf_fprint_classname(stdout, m->class->name);
885 utf_fprint(stdout, m->name);
886 utf_fprint(stdout, m->descriptor);
887 printf("\n\nLength: %d\n\n", (s4) (end - start));
889 DISASSEMBLE(start, end);
893 /* codegen_start_native_call ***************************************************
895 Prepares the stuff required for a native (JNI) function call:
897 - adds a stackframe info structure to the chain, for stacktraces
898 - prepares the local references table on the stack
900 The layout of the native stub stackframe should look like this:
902 +---------------------------+ <- SP (of parent Java function)
904 +---------------------------+
906 | stackframe info structure |
908 +---------------------------+
910 | local references table |
912 +---------------------------+
914 | arguments (if any) |
916 +---------------------------+ <- SP (native stub)
918 *******************************************************************************/
920 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
925 /* get data structures from stack */
927 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
928 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
929 sizeof(localref_table));
931 /* add a stackframeinfo to the chain */
933 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
935 /* add current JNI local references table to this thread */
937 lrt->capacity = LOCALREFTABLE_CAPACITY;
939 lrt->localframes = 1;
940 lrt->prev = LOCALREFTABLE;
942 /* clear the references array (memset is faster the a for-loop) */
944 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
950 /* codegen_finish_native_call **************************************************
952 Removes the stuff required for a native (JNI) function call.
954 *******************************************************************************/
956 void codegen_finish_native_call(u1 *datasp)
959 stackframeinfo **psfi;
963 /* get data structures from stack */
965 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
966 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
967 sizeof(localref_table));
969 /* remove current stackframeinfo from chain */
971 psfi = STACKFRAMEINFO;
975 /* release JNI local references tables for this thread */
979 /* got through all current local frames */
981 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
985 /* now store the previous local frames in the thread structure */
991 /* removecompilerstub **********************************************************
993 Deletes a compilerstub from memory (simply by freeing it).
995 *******************************************************************************/
997 void removecompilerstub(u1 *stub)
999 /* pass size 1 to keep the intern function happy */
1001 CFREE((void *) stub, 1);
1005 /* removenativestub ************************************************************
1007 Removes a previously created native-stub from memory.
1009 *******************************************************************************/
1011 void removenativestub(u1 *stub)
1013 /* pass size 1 to keep the intern function happy */
1015 CFREE((void *) stub, 1);
1019 /* reg_of_var ******************************************************************
1021 This function determines a register, to which the result of an
1022 operation should go, when it is ultimatively intended to store the
1023 result in pseudoregister v. If v is assigned to an actual
1024 register, this register will be returned. Otherwise (when v is
1025 spilled) this function returns tempregnum. If not already done,
1026 regoff and flags are set in the stack location.
1028 On ARM we have to check if a long/double variable is splitted
1029 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1030 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1031 cases. (michi 2005/07/24)
1033 *******************************************************************************/
1035 s4 reg_of_var(registerdata *rd, stackptr v, s4 tempregnum)
1039 switch (v->varkind) {
1041 if (!(v->flags & INMEMORY))
1046 var = &(rd->interfaces[v->varnum][v->type]);
1047 v->regoff = var->regoff;
1048 if (!(var->flags & INMEMORY))
1049 return(var->regoff);
1053 var = &(rd->locals[v->varnum][v->type]);
1054 v->regoff = var->regoff;
1055 if (!(var->flags & INMEMORY)) {
1056 #if defined(__ARM__) && defined(__ARMEL__)
1057 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1058 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1060 #if defined(__ARM__) && defined(__ARMEB__)
1061 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1062 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1064 return(var->regoff);
1069 if (!(v->flags & INMEMORY)) {
1070 #if defined(__ARM__) && defined(__ARMEL__)
1071 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1072 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1074 #if defined(__ARM__) && defined(__ARMEB__)
1075 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1076 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1083 #if defined(ENABLE_STATISTICS)
1085 count_spills_read++;
1088 v->flags |= INMEMORY;
1094 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1095 void codegen_threadcritrestart(codegendata *cd, int offset)
1097 cd->threadcritcurrent.mcoderestart = offset;
1101 void codegen_threadcritstart(codegendata *cd, int offset)
1103 cd->threadcritcurrent.mcodebegin = offset;
1107 void codegen_threadcritstop(codegendata *cd, int offset)
1109 cd->threadcritcurrent.next = cd->threadcrit;
1110 cd->threadcritcurrent.mcodeend = offset;
1111 cd->threadcrit = DNEW(threadcritnodetemp);
1112 *(cd->threadcrit) = cd->threadcritcurrent;
1113 cd->threadcritcount++;
1119 * These are local overrides for various environment variables in Emacs.
1120 * Please do not remove this and leave it at the end of the file, where
1121 * Emacs will automagically detect them.
1122 * ---------------------------------------------------------------------
1125 * indent-tabs-mode: t