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 4336 2006-01-22 14:44:23Z 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;
188 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
189 cd->datareferences = NULL;
192 cd->xboundrefs = NULL;
193 cd->xnullrefs = NULL;
194 cd->xcastrefs = NULL;
195 cd->xstorerefs = NULL;
197 cd->xexceptionrefs = NULL;
198 cd->patchrefs = NULL;
200 cd->linenumberreferences = NULL;
201 cd->linenumbertablesizepos = 0;
202 cd->linenumbertablestartpos = 0;
203 cd->linenumbertab = 0;
206 cd->exceptiontable = 0;
207 cd->exceptiontablelength = 0;
209 if (useinlining && id) {
210 if (id->cumextablelength > 0) {
211 cd->exceptiontablelength = id->cumextablelength;
213 DMNEW(exceptiontable, id->cumextablelength + 1);
216 } else if (id && (id->method->exceptiontablelength > 0)) {
217 cd->exceptiontablelength = m->exceptiontablelength;
218 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
222 cd->maxstack = id->cummaxstack;
223 cd->maxlocals = id->cumlocals;
225 cd->maxstack = m->maxstack;
226 cd->maxlocals = m->maxlocals;
229 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
230 cd->threadcritcurrent.next = NULL;
231 cd->threadcritcount = 0;
236 /* codegen_free ****************************************************************
238 Releases temporary code and data area.
240 *******************************************************************************/
242 void codegen_free(methodinfo *m, codegendata *cd)
247 MFREE(cd->mcodebase, u1, cd->mcodesize);
248 cd->mcodebase = NULL;
252 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
260 /* codegen_close ***************************************************************
264 *******************************************************************************/
266 void codegen_close(void)
268 /* TODO: release avl tree on i386 and x86_64 */
272 /* codegen_increase ************************************************************
276 *******************************************************************************/
278 s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
282 /* save old mcodebase pointer */
284 oldmcodebase = cd->mcodebase;
286 /* reallocate to new, doubled memory */
288 cd->mcodebase = DMREALLOC(cd->mcodebase,
293 cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
295 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
296 /* adjust the pointer to the last patcher position */
298 if (cd->lastmcodeptr != NULL)
299 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
302 /* return the new mcodeptr */
304 return (s4 *) (cd->mcodebase + (mcodeptr - oldmcodebase));
308 /* codegen_ncode_increase ******************************************************
312 *******************************************************************************/
314 #if defined(ENABLE_INTRP)
315 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
319 /* save old ncodebase pointer */
321 oldncodebase = cd->ncodebase;
323 /* reallocate to new, doubled memory */
325 cd->ncodebase = DMREALLOC(cd->ncodebase,
331 /* return the new ncodeptr */
333 return (cd->ncodebase + (ncodeptr - oldncodebase));
338 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
342 branchpos = (u1 *) branchptr - cd->mcodebase;
344 #if defined(ENABLE_JIT)
345 /* Check if the target basicblock has already a start pc, so the
346 jump is backward and we can resolve it immediately. */
348 /* The interpreter uses absolute branches, so we do branch
349 resolving after the code and data segment move. */
352 # if defined(ENABLE_INTRP)
357 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
364 branchref *br = DNEW(branchref);
366 br->branchpos = branchpos;
367 br->next = target->branchrefs;
369 target->branchrefs = br;
374 /* codegen_addxboundrefs *******************************************************
376 Adds an ArrayIndexOutOfBoundsException branch to the list.
378 *******************************************************************************/
380 void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
385 branchpos = (u1 *) branchptr - cd->mcodebase;
387 br = DNEW(branchref);
389 br->branchpos = branchpos;
391 br->next = cd->xboundrefs;
397 /* codegen_addxcastrefs ********************************************************
399 Adds an ClassCastException branch to the list.
401 *******************************************************************************/
403 void codegen_addxcastrefs(codegendata *cd, void *branchptr)
408 branchpos = (u1 *) branchptr - cd->mcodebase;
410 br = DNEW(branchref);
412 br->branchpos = branchpos;
413 br->next = cd->xcastrefs;
419 /* codegen_addxdivrefs *********************************************************
421 Adds an ArithmeticException branch to the list.
423 *******************************************************************************/
425 void codegen_addxdivrefs(codegendata *cd, void *branchptr)
430 branchpos = (u1 *) branchptr - cd->mcodebase;
432 br = DNEW(branchref);
434 br->branchpos = branchpos;
435 br->next = cd->xdivrefs;
441 /* codegen_addxstorerefs *******************************************************
443 Adds an ArrayStoreException branch to the list.
445 *******************************************************************************/
447 void codegen_addxstorerefs(codegendata *cd, void *branchptr)
452 branchpos = (u1 *) branchptr - cd->mcodebase;
454 br = DNEW(branchref);
456 br->branchpos = branchpos;
457 br->next = cd->xstorerefs;
463 /* codegen_addxnullrefs ********************************************************
465 Adds an NullPointerException branch to the list.
467 *******************************************************************************/
469 void codegen_addxnullrefs(codegendata *cd, void *branchptr)
474 branchpos = (u1 *) branchptr - cd->mcodebase;
476 br = DNEW(branchref);
478 br->branchpos = branchpos;
479 br->next = cd->xnullrefs;
485 /* codegen_addxexceptionsrefs **************************************************
487 Adds an common exception branch to the list.
489 *******************************************************************************/
491 void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
496 branchpos = (u1 *) branchptr - cd->mcodebase;
498 br = DNEW(branchref);
500 br->branchpos = branchpos;
501 br->next = cd->xexceptionrefs;
503 cd->xexceptionrefs = br;
507 /* codegen_addpatchref *********************************************************
509 Adds a new patcher reference to the list of patching positions.
511 *******************************************************************************/
513 void codegen_addpatchref(codegendata *cd, voidptr branchptr,
514 functionptr patcher, voidptr ref, s4 disp)
519 branchpos = (u1 *) branchptr - cd->mcodebase;
523 pr->branchpos = branchpos;
524 pr->patcher = patcher;
528 pr->next = cd->patchrefs;
531 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
532 /* On some architectures the patcher stub call instruction might
533 be longer than the actual instruction generated. On this
534 architectures we store the last patcher call position and after
535 the basic block code generation is completed, we check the
536 range and maybe generate some nop's. */
538 cd->lastmcodeptr = ((u1 *) branchptr) + PATCHER_CALL_SIZE;
543 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
544 /* methodtree_comparator *******************************************************
548 *******************************************************************************/
550 static s4 methodtree_comparator(const void *pc, const void *element)
552 methodtree_element *mte;
553 methodtree_element *mtepc;
555 mte = (methodtree_element *) element;
556 mtepc = (methodtree_element *) pc;
558 /* compare both startpc and endpc of pc, even if they have the same value,
559 otherwise the avl_probe sometimes thinks the element is already in the
562 if ((long) mte->startpc <= (long) mtepc->startpc &&
563 (long) mtepc->startpc <= (long) mte->endpc &&
564 (long) mte->startpc <= (long) mtepc->endpc &&
565 (long) mtepc->endpc <= (long) mte->endpc) {
568 } else if ((long) mtepc->startpc < (long) mte->startpc) {
577 /* codegen_insertmethod ********************************************************
581 *******************************************************************************/
583 void codegen_insertmethod(u1 *startpc, u1 *endpc)
585 methodtree_element *mte;
587 /* allocate new method entry */
589 mte = NEW(methodtree_element);
591 mte->startpc = startpc;
594 /* this function does not return an error, but asserts for
597 avl_insert(methodtree, mte);
601 /* codegen_findmethod **********************************************************
605 *******************************************************************************/
607 u1 *codegen_findmethod(u1 *pc)
609 methodtree_element mtepc;
610 methodtree_element *mte;
612 /* allocation of the search structure on the stack is much faster */
617 mte = avl_find(methodtree, &mtepc);
620 printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
623 throw_cacao_exception_exit(string_java_lang_InternalError,
624 "Cannot find Java function at %p", pc);
629 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
632 /* codegen_finish **************************************************************
634 Finishes the code generation. A new memory, large enough for both
635 data and code, is allocated and data and code are copied together
636 to their final layout, unresolved jumps are resolved, ...
638 *******************************************************************************/
640 void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
645 #if defined(ENABLE_INTRP)
654 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
655 extralen = sizeof(threadcritnode) * cd->threadcritcount;
660 #if defined(ENABLE_STATISTICS)
662 count_code_len += mcodelen;
663 count_data_len += cd->dseglen;
668 mcodelen = cd->mcodeptr - cd->mcodebase;
670 alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
672 #if defined(ENABLE_INTRP)
674 ncodelen = cd->ncodeptr - cd->ncodebase;
678 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
679 alignedlen = alignedmcodelen + cd->dseglen;
681 #if defined(ENABLE_INTRP)
683 alignedlen += ncodelen;
687 /* allocate new memory */
689 m->mcodelength = mcodelen + cd->dseglen;
690 m->mcode = CNEW(u1, alignedlen + extralen);
692 /* copy data and code to their new location */
694 MCOPY((void *) m->mcode, cd->dsegtop - cd->dseglen, u1, cd->dseglen);
695 MCOPY((void *) (m->mcode + cd->dseglen), cd->mcodebase, u1, mcodelen);
697 m->entrypoint = epoint = (m->mcode + cd->dseglen);
699 #if defined(ENABLE_INTRP)
700 /* relocate native dynamic superinstruction code (if any) */
703 cd->mcodebase = m->entrypoint;
706 u1 *ncodebase = m->mcode + cd->dseglen + alignedmcodelen;
707 MCOPY((void *)ncodebase, cd->ncodebase, u1, ncodelen);
708 /* XXX cacheflush((void *)ncodebase, ncodelen); */
709 /* set some cd variables for dynamic_super_rerwite */
711 cd->ncodebase = ncodebase;
714 cd->ncodebase = NULL;
717 dynamic_super_rewrite(cd);
721 /* jump table resolving */
723 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
724 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
725 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
727 /* line number table resolving */
732 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
734 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
735 (functionptr) ((ptrint) epoint + (ptrint) lr->targetmpc);
738 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
739 (functionptr) ((ptrint) epoint + cd->linenumbertab);
741 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
744 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
745 /* add method into methodtree to find the entrypoint */
747 codegen_insertmethod(m->entrypoint, m->entrypoint + mcodelen);
751 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
752 /* resolve data segment references */
754 dseg_resolve_datareferences(cd, m);
758 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
760 threadcritnode *n = (threadcritnode *) ((ptrint) m->mcode + alignedlen);
762 threadcritnodetemp *nt = cd->threadcrit;
764 for (i = 0; i < cd->threadcritcount; i++) {
765 n->mcodebegin = (u1 *) (ptrint) m->mcode + nt->mcodebegin;
766 n->mcodeend = (u1 *) (ptrint) m->mcode + nt->mcodeend;
767 n->mcoderestart = (u1 *) (ptrint) m->mcode + nt->mcoderestart;
768 thread_registercritical(n);
777 /* codegen_createnativestub ****************************************************
779 Wrapper for createnativestub.
781 *******************************************************************************/
783 u1 *codegen_createnativestub(functionptr f, methodinfo *m)
787 t_inlining_globals *id;
793 /* mark dump memory */
795 dumpsize = dump_size();
797 cd = DNEW(codegendata);
798 rd = DNEW(registerdata);
799 id = DNEW(t_inlining_globals);
801 /* setup code generation stuff */
803 inlining_setup(m, id);
805 #if defined(ENABLE_JIT)
806 # if defined(ENABLE_INTRP)
809 reg_setup(m, rd, id);
812 codegen_setup(m, cd, id);
814 /* create new method descriptor with additional native parameters */
817 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
819 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
820 md->paramcount * sizeof(typedesc) +
821 nativeparams * sizeof(typedesc));
823 nmd->paramcount = md->paramcount + nativeparams;
825 nmd->params = DMNEW(paramdesc, nmd->paramcount);
827 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
829 if (m->flags & ACC_STATIC)
830 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
832 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
835 #if defined(ENABLE_JIT)
836 # if defined(ENABLE_INTRP)
842 /* generate the code */
844 #if defined(ENABLE_JIT)
845 # if defined(ENABLE_INTRP)
847 m->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
850 m->entrypoint = createnativestub(f, m, cd, rd, nmd);
852 m->entrypoint = intrp_createnativestub(f, m, cd, rd, nmd);
855 #if defined(ENABLE_STATISTICS)
857 count_nstub_len += m->mcodelength;
860 /* disassemble native stub */
862 if (opt_shownativestub) {
863 codegen_disassemble_nativestub(m,
864 (u1 *) (ptrint) m->entrypoint,
865 (u1 *) (ptrint) m->entrypoint + (m->mcodelength - cd->dseglen));
867 /* show data segment */
869 if (opt_showddatasegment)
875 dump_release(dumpsize);
877 /* return native stub entry point */
879 return m->entrypoint;
883 /* codegen_disassemble_nativestub **********************************************
885 Disassembles the generated native stub.
887 *******************************************************************************/
889 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
891 printf("Native stub: ");
892 utf_fprint_classname(stdout, m->class->name);
894 utf_fprint(stdout, m->name);
895 utf_fprint(stdout, m->descriptor);
896 printf("\n\nLength: %d\n\n", (s4) (end - start));
898 DISASSEMBLE(start, end);
902 /* codegen_start_native_call ***************************************************
904 Prepares the stuff required for a native (JNI) function call:
906 - adds a stackframe info structure to the chain, for stacktraces
907 - prepares the local references table on the stack
909 The layout of the native stub stackframe should look like this:
911 +---------------------------+ <- SP (of parent Java function)
913 +---------------------------+
915 | stackframe info structure |
917 +---------------------------+
919 | local references table |
921 +---------------------------+
923 | arguments (if any) |
925 +---------------------------+ <- SP (native stub)
927 *******************************************************************************/
929 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
934 /* get data structures from stack */
936 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
937 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
938 sizeof(localref_table));
940 /* add a stackframeinfo to the chain */
942 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
944 /* add current JNI local references table to this thread */
946 lrt->capacity = LOCALREFTABLE_CAPACITY;
948 lrt->localframes = 1;
949 lrt->prev = LOCALREFTABLE;
951 /* clear the references array (memset is faster the a for-loop) */
953 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
959 /* codegen_finish_native_call **************************************************
961 Removes the stuff required for a native (JNI) function call.
963 *******************************************************************************/
965 void codegen_finish_native_call(u1 *datasp)
968 stackframeinfo **psfi;
972 /* get data structures from stack */
974 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
975 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
976 sizeof(localref_table));
978 /* remove current stackframeinfo from chain */
980 psfi = STACKFRAMEINFO;
984 /* release JNI local references tables for this thread */
988 /* got through all current local frames */
990 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
994 /* now store the previous local frames in the thread structure */
1000 /* removecompilerstub **********************************************************
1002 Deletes a compilerstub from memory (simply by freeing it).
1004 *******************************************************************************/
1006 void removecompilerstub(u1 *stub)
1008 /* pass size 1 to keep the intern function happy */
1010 CFREE((void *) stub, 1);
1014 /* removenativestub ************************************************************
1016 Removes a previously created native-stub from memory.
1018 *******************************************************************************/
1020 void removenativestub(u1 *stub)
1022 /* pass size 1 to keep the intern function happy */
1024 CFREE((void *) stub, 1);
1028 /* reg_of_var ******************************************************************
1030 This function determines a register, to which the result of an
1031 operation should go, when it is ultimatively intended to store the
1032 result in pseudoregister v. If v is assigned to an actual
1033 register, this register will be returned. Otherwise (when v is
1034 spilled) this function returns tempregnum. If not already done,
1035 regoff and flags are set in the stack location.
1037 On ARM we have to check if a long/double variable is splitted
1038 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1039 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1040 cases. (michi 2005/07/24)
1042 *******************************************************************************/
1044 s4 reg_of_var(registerdata *rd, stackptr v, s4 tempregnum)
1048 switch (v->varkind) {
1050 if (!(v->flags & INMEMORY))
1055 var = &(rd->interfaces[v->varnum][v->type]);
1056 v->regoff = var->regoff;
1057 if (!(var->flags & INMEMORY))
1058 return(var->regoff);
1062 var = &(rd->locals[v->varnum][v->type]);
1063 v->regoff = var->regoff;
1064 if (!(var->flags & INMEMORY)) {
1065 #if defined(__ARM__) && defined(__ARMEL__)
1066 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1067 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1069 #if defined(__ARM__) && defined(__ARMEB__)
1070 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1071 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1073 return(var->regoff);
1078 if (!(v->flags & INMEMORY)) {
1079 #if defined(__ARM__) && defined(__ARMEL__)
1080 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1081 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1083 #if defined(__ARM__) && defined(__ARMEB__)
1084 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1085 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1092 #if defined(ENABLE_STATISTICS)
1094 count_spills_read++;
1097 v->flags |= INMEMORY;
1103 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1104 void codegen_threadcritrestart(codegendata *cd, int offset)
1106 cd->threadcritcurrent.mcoderestart = offset;
1110 void codegen_threadcritstart(codegendata *cd, int offset)
1112 cd->threadcritcurrent.mcodebegin = offset;
1116 void codegen_threadcritstop(codegendata *cd, int offset)
1118 cd->threadcritcurrent.next = cd->threadcrit;
1119 cd->threadcritcurrent.mcodeend = offset;
1120 cd->threadcrit = DNEW(threadcritnodetemp);
1121 *(cd->threadcrit) = cd->threadcritcurrent;
1122 cd->threadcritcount++;
1128 * These are local overrides for various environment variables in Emacs.
1129 * Please do not remove this and leave it at the end of the file, where
1130 * Emacs will automagically detect them.
1131 * ---------------------------------------------------------------------
1134 * indent-tabs-mode: t