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 5052 2006-06-28 17:05: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(ENABLE_THREADS)
80 # include "threads/native/threads.h"
83 #include "vm/exceptions.h"
84 #include "vm/method.h"
85 #include "vm/options.h"
86 #include "vm/statistics.h"
87 #include "vm/stringlocal.h"
88 #include "vm/jit/asmpart.h"
89 #include "vm/jit/codegen-common.h"
91 #if defined(ENABLE_DISASSEMBLER)
92 # include "vm/jit/disass.h"
95 #include "vm/jit/dseg.h"
96 #include "vm/jit/jit.h"
97 #include "vm/jit/stacktrace.h"
98 #include "vm/jit/replace.h"
101 /* in this tree we store all method addresses *********************************/
103 static avl_tree *methodtree = NULL;
104 static s4 methodtree_comparator(const void *pc, const void *element);
107 /* codegen_init ****************************************************************
111 *******************************************************************************/
113 void codegen_init(void)
115 /* this tree is global, not method specific */
118 #if defined(ENABLE_JIT)
119 methodtree_element *mte;
122 methodtree = avl_create(&methodtree_comparator);
124 #if defined(ENABLE_JIT)
125 /* insert asm_vm_call_method */
127 mte = NEW(methodtree_element);
129 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
130 mte->endpc = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
132 avl_insert(methodtree, mte);
133 #endif /* defined(ENABLE_JIT) */
138 /* codegen_setup ***************************************************************
140 Allocates and initialises code area, data area and references.
142 *******************************************************************************/
144 void codegen_setup(jitdata *jd)
149 /* get required compiler data */
154 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
155 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
156 cd->mcodesize = MCODEINITSIZE;
158 /* initialize mcode variables */
160 cd->mcodeptr = cd->mcodebase;
161 cd->lastmcodeptr = cd->mcodebase;
163 #if defined(ENABLE_INTRP)
164 /* native dynamic superinstructions variables */
167 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
168 cd->ncodesize = NCODEINITSIZE;
170 /* initialize ncode variables */
172 cd->ncodeptr = cd->ncodebase;
174 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
175 cd->superstarts = NULL;
179 cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
180 cd->dsegsize = DSEGINITSIZE;
181 cd->dsegtop += cd->dsegsize;
184 cd->jumpreferences = NULL;
186 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
187 cd->datareferences = NULL;
190 cd->exceptionrefs = NULL;
191 cd->patchrefs = NULL;
193 cd->linenumberreferences = NULL;
194 cd->linenumbertablesizepos = 0;
195 cd->linenumbertablestartpos = 0;
196 cd->linenumbertab = 0;
199 cd->exceptiontable = 0;
200 cd->exceptiontablelength = 0;
202 if (m->exceptiontablelength > 0) {
203 cd->exceptiontablelength = m->exceptiontablelength;
204 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
207 cd->maxstack = m->maxstack;
208 cd->maxlocals = m->maxlocals;
210 #if defined(ENABLE_THREADS)
211 cd->threadcritcurrent.next = NULL;
212 cd->threadcritcount = 0;
217 /* codegen_close ***************************************************************
221 *******************************************************************************/
223 void codegen_close(void)
225 /* TODO: release avl tree on i386 and x86_64 */
229 /* codegen_increase ************************************************************
233 *******************************************************************************/
235 void codegen_increase(codegendata *cd)
239 /* save old mcodebase pointer */
241 oldmcodebase = cd->mcodebase;
243 /* reallocate to new, doubled memory */
245 cd->mcodebase = DMREALLOC(cd->mcodebase,
250 cd->mcodeend = cd->mcodebase + cd->mcodesize;
252 /* set new mcodeptr */
254 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
256 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
257 /* adjust the pointer to the last patcher position */
259 if (cd->lastmcodeptr != NULL)
260 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
265 /* codegen_ncode_increase ******************************************************
269 *******************************************************************************/
271 #if defined(ENABLE_INTRP)
272 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
276 /* save old ncodebase pointer */
278 oldncodebase = cd->ncodebase;
280 /* reallocate to new, doubled memory */
282 cd->ncodebase = DMREALLOC(cd->ncodebase,
288 /* return the new ncodeptr */
290 return (cd->ncodebase + (ncodeptr - oldncodebase));
295 void codegen_addreference(codegendata *cd, basicblock *target)
299 branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
301 #if defined(ENABLE_JIT)
302 /* Check if the target basicblock has already a start pc, so the
303 jump is backward and we can resolve it immediately. */
305 /* The interpreter uses absolute branches, so we do branch
306 resolving after the code and data segment move. */
309 # if defined(ENABLE_INTRP)
314 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
321 branchref *br = DNEW(branchref);
323 br->branchpos = branchpos;
324 br->next = target->branchrefs;
326 target->branchrefs = br;
331 /* codegen_add_exception_ref ***************************************************
333 Adds an exception branch to the list.
335 *******************************************************************************/
337 static void codegen_add_exception_ref(codegendata *cd, s4 reg,
338 functionptr function)
343 branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
345 eref = DNEW(exceptionref);
347 eref->branchpos = branchpos;
349 eref->function = function;
350 eref->next = cd->exceptionrefs;
352 cd->exceptionrefs = eref;
356 /* codegen_add_arithmeticexception_ref *****************************************
358 Adds an ArithmeticException branch to the list.
360 *******************************************************************************/
362 void codegen_add_arithmeticexception_ref(codegendata *cd)
364 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arithmeticexception);
368 /* codegen_add_arrayindexoutofboundsexception_ref ******************************
370 Adds an ArrayIndexOutOfBoundsException branch to the list.
372 *******************************************************************************/
374 void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd, s4 reg)
376 codegen_add_exception_ref(cd, reg,
377 STACKTRACE_inline_arrayindexoutofboundsexception);
381 /* codegen_add_arraystoreexception_ref *****************************************
383 Adds an ArrayStoreException branch to the list.
385 *******************************************************************************/
387 void codegen_add_arraystoreexception_ref(codegendata *cd)
389 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arraystoreexception);
393 /* codegen_add_classcastexception_ref ******************************************
395 Adds an ClassCastException branch to the list.
397 *******************************************************************************/
399 void codegen_add_classcastexception_ref(codegendata *cd)
401 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_classcastexception);
405 /* codegen_add_nullpointerexception_ref ****************************************
407 Adds an NullPointerException branch to the list.
409 *******************************************************************************/
411 void codegen_add_nullpointerexception_ref(codegendata *cd)
413 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_nullpointerexception);
417 /* codegen_add_fillinstacktrace_ref ********************************************
419 Adds a fillInStackTrace branch to the list.
421 *******************************************************************************/
423 void codegen_add_fillinstacktrace_ref(codegendata *cd)
425 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_fillInStackTrace);
429 /* codegen_addpatchref *********************************************************
431 Adds a new patcher reference to the list of patching positions.
433 *******************************************************************************/
435 void codegen_addpatchref(codegendata *cd, functionptr patcher, voidptr ref,
441 branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
445 pr->branchpos = branchpos;
446 pr->patcher = patcher;
450 pr->next = cd->patchrefs;
453 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
454 /* On some architectures the patcher stub call instruction might
455 be longer than the actual instruction generated. On this
456 architectures we store the last patcher call position and after
457 the basic block code generation is completed, we check the
458 range and maybe generate some nop's. */
460 cd->lastmcodeptr = ((u1 *) cd->mcodeptr) + PATCHER_CALL_SIZE;
465 /* methodtree_comparator *******************************************************
467 Comparator function used for the AVL tree of methods.
469 *******************************************************************************/
471 static s4 methodtree_comparator(const void *pc, const void *element)
473 methodtree_element *mte;
474 methodtree_element *mtepc;
476 mte = (methodtree_element *) element;
477 mtepc = (methodtree_element *) pc;
479 /* compare both startpc and endpc of pc, even if they have the same value,
480 otherwise the avl_probe sometimes thinks the element is already in the
483 if ((long) mte->startpc <= (long) mtepc->startpc &&
484 (long) mtepc->startpc <= (long) mte->endpc &&
485 (long) mte->startpc <= (long) mtepc->endpc &&
486 (long) mtepc->endpc <= (long) mte->endpc) {
489 } else if ((long) mtepc->startpc < (long) mte->startpc) {
498 /* codegen_insertmethod ********************************************************
500 Insert the machine code range of a method into the AVL tree of methods.
502 *******************************************************************************/
504 void codegen_insertmethod(u1 *startpc, u1 *endpc)
506 methodtree_element *mte;
508 /* allocate new method entry */
510 mte = NEW(methodtree_element);
512 mte->startpc = startpc;
515 /* this function does not return an error, but asserts for
518 avl_insert(methodtree, mte);
522 /* codegen_findmethod **********************************************************
524 Find the PV for the given PC by searching in the AVL tree of methods.
526 *******************************************************************************/
528 u1 *codegen_findmethod(u1 *pc)
530 methodtree_element mtepc;
531 methodtree_element *mte;
533 /* allocation of the search structure on the stack is much faster */
538 mte = avl_find(methodtree, &mtepc);
541 /* fprintf(stderr, "Cannot find Java function at %p\n", (void *) (ptrint) pc); */
550 /* codegen_finish **************************************************************
552 Finishes the code generation. A new memory, large enough for both
553 data and code, is allocated and data and code are copied together
554 to their final layout, unresolved jumps are resolved, ...
556 *******************************************************************************/
558 void codegen_finish(jitdata *jd)
563 #if defined(ENABLE_INTRP)
572 /* get required compiler data */
577 /* prevent compiler warning */
579 #if defined(ENABLE_INTRP)
583 /* calculate the code length */
585 mcodelen = (s4) ((u1 *) cd->mcodeptr - cd->mcodebase);
587 #if defined(ENABLE_THREADS)
588 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
593 #if defined(ENABLE_STATISTICS)
595 count_code_len += mcodelen;
596 count_data_len += cd->dseglen;
600 alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
602 #if defined(ENABLE_INTRP)
604 ncodelen = cd->ncodeptr - cd->ncodebase;
606 ncodelen = 0; /* avoid compiler warning */
610 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
611 alignedlen = alignedmcodelen + cd->dseglen;
613 #if defined(ENABLE_INTRP)
615 alignedlen += ncodelen;
619 /* allocate new memory */
621 code->mcodelength = mcodelen + cd->dseglen;
622 code->mcode = CNEW(u1, alignedlen + extralen);
624 /* copy data and code to their new location */
626 MCOPY((void *) code->mcode, cd->dsegtop - cd->dseglen, u1, cd->dseglen);
627 MCOPY((void *) (code->mcode + cd->dseglen), cd->mcodebase, u1, mcodelen);
629 /* set the entrypoint of the method */
631 assert(code->entrypoint == NULL);
632 code->entrypoint = epoint = (code->mcode + cd->dseglen);
634 #if defined(ENABLE_INTRP)
635 /* relocate native dynamic superinstruction code (if any) */
638 cd->mcodebase = code->entrypoint;
641 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
643 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
645 /* flush the instruction and data caches */
647 md_cacheflush(ncodebase, ncodelen);
649 /* set some cd variables for dynamic_super_rerwite */
651 cd->ncodebase = ncodebase;
654 cd->ncodebase = NULL;
657 dynamic_super_rewrite(cd);
661 /* jump table resolving */
663 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
664 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
665 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
667 /* line number table resolving */
673 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
675 target = lr->targetmpc;
676 /* if the entry contains an mcode pointer (normal case), resolve it */
677 /* (see doc/inlining_stacktrace.txt for details) */
678 if (lr->linenumber >= -2) {
679 target += (ptrint) epoint;
681 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
682 (functionptr) target;
685 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
686 (functionptr) ((ptrint) epoint + cd->linenumbertab);
688 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
691 /* replacement point resolving */
696 rp = code->rplpoints;
697 for (i=0; i<code->rplpointcount; ++i, ++rp) {
698 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
699 rp->outcode = (u1*) ((ptrint) epoint + (ptrint) rp->outcode);
703 /* add method into methodtree to find the entrypoint */
705 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
707 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
708 /* resolve data segment references */
710 dseg_resolve_datareferences(jd);
713 #if defined(ENABLE_THREADS)
715 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
717 codegen_critical_section_t *nt = cd->threadcrit;
719 for (i = 0; i < cd->threadcritcount; i++) {
720 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
721 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
722 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
723 critical_register_critical_section(n);
730 /* flush the instruction and data caches */
732 md_cacheflush(code->mcode, code->mcodelength);
736 /* codegen_createnativestub ****************************************************
738 Wrapper for createnativestub.
741 the codeinfo representing the stub code.
743 *******************************************************************************/
745 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
754 /* mark dump memory */
756 dumpsize = dump_size();
761 jd->cd = DNEW(codegendata);
762 jd->rd = DNEW(registerdata);
764 /* Allocate codeinfo memory from the heap as we need to keep them. */
766 jd->code = code_codeinfo_new(m); /* XXX check allocation */
768 /* get required compiler data */
772 /* set the flags for the current JIT run */
775 jd->flags |= JITDATA_FLAG_VERBOSECALL;
777 /* setup code generation stuff */
779 #if defined(ENABLE_JIT)
780 # if defined(ENABLE_INTRP)
788 /* create new method descriptor with additional native parameters */
791 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
793 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
794 md->paramcount * sizeof(typedesc) +
795 nativeparams * sizeof(typedesc));
797 nmd->paramcount = md->paramcount + nativeparams;
799 nmd->params = DMNEW(paramdesc, nmd->paramcount);
801 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
803 if (m->flags & ACC_STATIC)
804 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
806 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
809 #if defined(ENABLE_JIT)
810 # if defined(ENABLE_INTRP)
816 /* generate the code */
818 #if defined(ENABLE_JIT)
819 # if defined(ENABLE_INTRP)
821 code->entrypoint = intrp_createnativestub(f, jd, nmd);
824 code->entrypoint = createnativestub(f, jd, nmd);
826 code->entrypoint = intrp_createnativestub(f, jd, nmd);
829 #if defined(ENABLE_STATISTICS)
831 count_nstub_len += code->mcodelength;
835 /* disassemble native stub */
837 if (opt_shownativestub) {
838 #if defined(ENABLE_DISASSEMBLER)
839 codegen_disassemble_nativestub(m,
840 (u1 *) (ptrint) code->entrypoint,
841 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
844 /* show data segment */
846 if (opt_showddatasegment)
849 #endif /* !defined(NDEBUG) */
853 dump_release(dumpsize);
855 /* return native stub code */
861 /* codegen_disassemble_nativestub **********************************************
863 Disassembles the generated native stub.
865 *******************************************************************************/
867 #if defined(ENABLE_DISASSEMBLER)
868 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
870 printf("Native stub: ");
871 utf_fprint_printable_ascii_classname(stdout, m->class->name);
873 utf_fprint_printable_ascii(stdout, m->name);
874 utf_fprint_printable_ascii(stdout, m->descriptor);
875 printf("\n\nLength: %d\n\n", (s4) (end - start));
877 DISASSEMBLE(start, end);
882 /* codegen_start_native_call ***************************************************
884 Prepares the stuff required for a native (JNI) function call:
886 - adds a stackframe info structure to the chain, for stacktraces
887 - prepares the local references table on the stack
889 The layout of the native stub stackframe should look like this:
891 +---------------------------+ <- SP (of parent Java function)
893 +---------------------------+
895 | stackframe info structure |
897 +---------------------------+
899 | local references table |
901 +---------------------------+
903 | arguments (if any) |
905 +---------------------------+ <- SP (native stub)
907 *******************************************************************************/
909 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
914 /* get data structures from stack */
916 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
917 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
918 sizeof(localref_table));
920 /* add a stackframeinfo to the chain */
922 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
924 /* add current JNI local references table to this thread */
926 lrt->capacity = LOCALREFTABLE_CAPACITY;
928 lrt->localframes = 1;
929 lrt->prev = LOCALREFTABLE;
931 /* clear the references array (memset is faster the a for-loop) */
933 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
939 /* codegen_finish_native_call **************************************************
941 Removes the stuff required for a native (JNI) function call.
943 *******************************************************************************/
945 void codegen_finish_native_call(u1 *datasp)
948 stackframeinfo **psfi;
950 localref_table *plrt;
953 /* get data structures from stack */
955 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
956 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
957 sizeof(localref_table));
959 /* remove current stackframeinfo from chain */
961 psfi = STACKFRAMEINFO;
965 /* release JNI local references tables for this thread */
969 /* release all current local frames */
971 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
972 /* get previous frame */
976 /* Clear all reference entries (only for tables allocated on
980 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
984 /* set new local references table */
989 /* now store the previous local frames in the thread structure */
995 /* removecompilerstub **********************************************************
997 Deletes a compilerstub from memory (simply by freeing it).
999 *******************************************************************************/
1001 void removecompilerstub(u1 *stub)
1003 /* pass size 1 to keep the intern function happy */
1005 CFREE((void *) stub, 1);
1009 /* removenativestub ************************************************************
1011 Removes a previously created native-stub from memory.
1013 *******************************************************************************/
1015 void removenativestub(u1 *stub)
1017 /* pass size 1 to keep the intern function happy */
1019 CFREE((void *) stub, 1);
1023 /* codegen_reg_of_var **********************************************************
1025 This function determines a register, to which the result of an
1026 operation should go, when it is ultimatively intended to store the
1027 result in pseudoregister v. If v is assigned to an actual
1028 register, this register will be returned. Otherwise (when v is
1029 spilled) this function returns tempregnum. If not already done,
1030 regoff and flags are set in the stack location.
1032 On ARM we have to check if a long/double variable is splitted
1033 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1034 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1035 cases. (michi 2005/07/24)
1037 *******************************************************************************/
1039 s4 codegen_reg_of_var(registerdata *rd, u2 opcode, stackptr v, s4 tempregnum)
1044 /* Do we have to generate a conditional move? Yes, then always
1045 return the temporary register. The real register is identified
1046 during the store. */
1048 if (opcode & ICMD_CONDITION_MASK)
1052 switch (v->varkind) {
1054 if (!(v->flags & INMEMORY))
1059 var = &(rd->interfaces[v->varnum][v->type]);
1060 v->regoff = var->regoff;
1061 if (!(var->flags & INMEMORY))
1062 return(var->regoff);
1066 var = &(rd->locals[v->varnum][v->type]);
1067 v->regoff = var->regoff;
1068 if (!(var->flags & INMEMORY)) {
1069 #if defined(__ARM__) && defined(__ARMEL__)
1070 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1071 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1073 #if defined(__ARM__) && defined(__ARMEB__)
1074 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1075 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1077 return(var->regoff);
1082 if (!(v->flags & INMEMORY)) {
1083 #if defined(__ARM__) && defined(__ARMEL__)
1084 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1085 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1087 #if defined(__ARM__) && defined(__ARMEB__)
1088 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1089 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1096 #if defined(ENABLE_STATISTICS)
1098 count_spills_read++;
1101 v->flags |= INMEMORY;
1107 #if defined(ENABLE_THREADS)
1108 void codegen_threadcritrestart(codegendata *cd, int offset)
1110 cd->threadcritcurrent.mcoderestart = offset;
1114 void codegen_threadcritstart(codegendata *cd, int offset)
1116 cd->threadcritcurrent.mcodebegin = offset;
1120 void codegen_threadcritstop(codegendata *cd, int offset)
1122 cd->threadcritcurrent.next = cd->threadcrit;
1123 cd->threadcritcurrent.mcodeend = offset;
1124 cd->threadcrit = DNEW(codegen_critical_section_t);
1125 *(cd->threadcrit) = cd->threadcritcurrent;
1126 cd->threadcritcount++;
1132 * These are local overrides for various environment variables in Emacs.
1133 * Please do not remove this and leave it at the end of the file, where
1134 * Emacs will automagically detect them.
1135 * ---------------------------------------------------------------------
1138 * indent-tabs-mode: t
1142 * vim:noexpandtab:sw=4:ts=4: