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 4159 2006-01-12 21:35:36Z twisti $
62 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__)
63 /* this is required for 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(__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);
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);
741 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__)
745 /* data segment references resolving */
747 for (dr = cd->datareferences; dr != NULL; dr = dr->next)
748 *((u1 **) (epoint + dr->datapos - SIZEOF_VOID_P)) = epoint;
752 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
754 threadcritnode *n = (threadcritnode *) ((ptrint) m->mcode + alignedlen);
756 threadcritnodetemp *nt = cd->threadcrit;
758 for (i = 0; i < cd->threadcritcount; i++) {
759 n->mcodebegin = (u1 *) (ptrint) m->mcode + nt->mcodebegin;
760 n->mcodeend = (u1 *) (ptrint) m->mcode + nt->mcodeend;
761 n->mcoderestart = (u1 *) (ptrint) m->mcode + nt->mcoderestart;
762 thread_registercritical(n);
771 /* codegen_createnativestub ****************************************************
773 Wrapper for createnativestub.
775 *******************************************************************************/
777 u1 *codegen_createnativestub(functionptr f, methodinfo *m)
781 t_inlining_globals *id;
787 /* mark dump memory */
789 dumpsize = dump_size();
791 cd = DNEW(codegendata);
792 rd = DNEW(registerdata);
793 id = DNEW(t_inlining_globals);
795 /* setup code generation stuff */
797 inlining_setup(m, id);
799 #if defined(ENABLE_JIT)
800 # if defined(ENABLE_INTRP)
803 reg_setup(m, rd, id);
806 codegen_setup(m, cd, id);
808 /* create new method descriptor with additional native parameters */
811 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
813 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
814 md->paramcount * sizeof(typedesc) +
815 nativeparams * sizeof(typedesc));
817 nmd->paramcount = md->paramcount + nativeparams;
819 nmd->params = DMNEW(paramdesc, nmd->paramcount);
821 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
823 if (m->flags & ACC_STATIC)
824 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
826 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
831 /* generate the code */
833 #if defined(ENABLE_JIT)
834 # if defined(ENABLE_INTRP)
836 m->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
839 m->entrypoint = createnativestub(f, m, cd, rd, nmd);
841 m->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
844 #if defined(ENABLE_STATISTICS)
846 count_nstub_len += m->mcodelength;
849 /* disassemble native stub */
851 if (opt_shownativestub) {
852 codegen_disassemble_nativestub(m,
853 (u1 *) (ptrint) m->entrypoint,
854 (u1 *) (ptrint) m->entrypoint + (m->mcodelength - cd->dseglen));
856 /* show data segment */
858 if (opt_showddatasegment)
864 dump_release(dumpsize);
866 /* return native stub entry point */
868 return m->entrypoint;
872 /* codegen_disassemble_nativestub **********************************************
874 Disassembles the generated native stub.
876 *******************************************************************************/
878 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
880 printf("Native stub: ");
881 utf_fprint_classname(stdout, m->class->name);
883 utf_fprint(stdout, m->name);
884 utf_fprint(stdout, m->descriptor);
885 printf("\n\nLength: %d\n\n", (s4) (end - start));
887 disassemble(start, end);
891 /* codegen_start_native_call ***************************************************
893 Prepares the stuff required for a native (JNI) function call:
895 - adds a stackframe info structure to the chain, for stacktraces
896 - prepares the local references table on the stack
898 The layout of the native stub stackframe should look like this:
900 +---------------------------+ <- SP (of parent Java function)
902 +---------------------------+
904 | stackframe info structure |
906 +---------------------------+
908 | local references table |
910 +---------------------------+
912 | arguments (if any) |
914 +---------------------------+ <- SP (native stub)
916 *******************************************************************************/
918 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
923 /* get data structures from stack */
925 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
926 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
927 sizeof(localref_table));
929 /* add a stackframeinfo to the chain */
931 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
933 /* add current JNI local references table to this thread */
935 lrt->capacity = LOCALREFTABLE_CAPACITY;
937 lrt->localframes = 1;
938 lrt->prev = LOCALREFTABLE;
940 /* clear the references array (memset is faster the a for-loop) */
942 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
948 /* codegen_finish_native_call **************************************************
950 Removes the stuff required for a native (JNI) function call.
952 *******************************************************************************/
954 void codegen_finish_native_call(u1 *datasp)
957 stackframeinfo **psfi;
961 /* get data structures from stack */
963 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
964 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
965 sizeof(localref_table));
967 /* remove current stackframeinfo from chain */
969 psfi = STACKFRAMEINFO;
973 /* release JNI local references tables for this thread */
977 /* got through all current local frames */
979 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
983 /* now store the previous local frames in the thread structure */
989 /* removecompilerstub **********************************************************
991 Deletes a compilerstub from memory (simply by freeing it).
993 *******************************************************************************/
995 void removecompilerstub(u1 *stub)
997 /* pass size 1 to keep the intern function happy */
999 CFREE((void *) stub, 1);
1003 /* removenativestub ************************************************************
1005 Removes a previously created native-stub from memory.
1007 *******************************************************************************/
1009 void removenativestub(u1 *stub)
1011 /* pass size 1 to keep the intern function happy */
1013 CFREE((void *) stub, 1);
1017 /* reg_of_var ******************************************************************
1019 This function determines a register, to which the result of an
1020 operation should go, when it is ultimatively intended to store the
1021 result in pseudoregister v. If v is assigned to an actual
1022 register, this register will be returned. Otherwise (when v is
1023 spilled) this function returns tempregnum. If not already done,
1024 regoff and flags are set in the stack location.
1026 On ARM we have to check if a long/double variable is splitted
1027 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1028 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1029 cases. (michi 2005/07/24)
1031 *******************************************************************************/
1033 s4 reg_of_var(registerdata *rd, stackptr v, s4 tempregnum)
1037 switch (v->varkind) {
1039 if (!(v->flags & INMEMORY))
1044 var = &(rd->interfaces[v->varnum][v->type]);
1045 v->regoff = var->regoff;
1046 if (!(var->flags & INMEMORY))
1047 return(var->regoff);
1051 var = &(rd->locals[v->varnum][v->type]);
1052 v->regoff = var->regoff;
1053 if (!(var->flags & INMEMORY)) {
1054 #if defined(__ARM__) && defined(__ARMEL__)
1055 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1056 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1058 #if defined(__ARM__) && defined(__ARMEB__)
1059 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1060 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1062 return(var->regoff);
1067 if (!(v->flags & INMEMORY)) {
1068 #if defined(__ARM__) && defined(__ARMEL__)
1069 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1070 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1072 #if defined(__ARM__) && defined(__ARMEB__)
1073 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1074 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1081 #if defined(ENABLE_STATISTICS)
1083 count_spills_read++;
1086 v->flags |= INMEMORY;
1092 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1093 void codegen_threadcritrestart(codegendata *cd, int offset)
1095 cd->threadcritcurrent.mcoderestart = offset;
1099 void codegen_threadcritstart(codegendata *cd, int offset)
1101 cd->threadcritcurrent.mcodebegin = offset;
1105 void codegen_threadcritstop(codegendata *cd, int offset)
1107 cd->threadcritcurrent.next = cd->threadcrit;
1108 cd->threadcritcurrent.mcodeend = offset;
1109 cd->threadcrit = DNEW(threadcritnodetemp);
1110 *(cd->threadcrit) = cd->threadcritcurrent;
1111 cd->threadcritcount++;
1117 * These are local overrides for various environment variables in Emacs.
1118 * Please do not remove this and leave it at the end of the file, where
1119 * Emacs will automagically detect them.
1120 * ---------------------------------------------------------------------
1123 * indent-tabs-mode: t