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 4921 2006-05-15 14:24:36Z 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 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
104 static avl_tree *methodtree = NULL;
105 static s4 methodtree_comparator(const void *pc, const void *element);
109 /* codegen_init ****************************************************************
113 *******************************************************************************/
115 void codegen_init(void)
117 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
118 /* this tree is global, not method specific */
121 #if defined(ENABLE_JIT)
122 methodtree_element *mte;
125 methodtree = avl_create(&methodtree_comparator);
127 #if defined(ENABLE_JIT)
128 /* insert asm_vm_call_method */
130 mte = NEW(methodtree_element);
132 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
133 mte->endpc = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
135 avl_insert(methodtree, mte);
136 #endif /* defined(ENABLE_JIT) */
138 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
142 /* codegen_setup ***************************************************************
144 Allocates and initialises code area, data area and references.
146 *******************************************************************************/
148 void codegen_setup(jitdata *jd)
153 /* get required compiler data */
158 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
159 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
160 cd->mcodesize = MCODEINITSIZE;
162 /* initialize mcode variables */
164 cd->mcodeptr = cd->mcodebase;
165 cd->lastmcodeptr = cd->mcodebase;
167 #if defined(ENABLE_INTRP)
168 /* native dynamic superinstructions variables */
171 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
172 cd->ncodesize = NCODEINITSIZE;
174 /* initialize ncode variables */
176 cd->ncodeptr = cd->ncodebase;
178 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
179 cd->superstarts = NULL;
183 cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
184 cd->dsegsize = DSEGINITSIZE;
185 cd->dsegtop += cd->dsegsize;
188 cd->jumpreferences = NULL;
190 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
191 cd->datareferences = NULL;
194 cd->exceptionrefs = NULL;
195 cd->patchrefs = NULL;
197 cd->linenumberreferences = NULL;
198 cd->linenumbertablesizepos = 0;
199 cd->linenumbertablestartpos = 0;
200 cd->linenumbertab = 0;
203 cd->exceptiontable = 0;
204 cd->exceptiontablelength = 0;
206 if (m->exceptiontablelength > 0) {
207 cd->exceptiontablelength = m->exceptiontablelength;
208 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
211 cd->maxstack = m->maxstack;
212 cd->maxlocals = m->maxlocals;
214 #if defined(ENABLE_THREADS)
215 cd->threadcritcurrent.next = NULL;
216 cd->threadcritcount = 0;
221 /* codegen_close ***************************************************************
225 *******************************************************************************/
227 void codegen_close(void)
229 /* TODO: release avl tree on i386 and x86_64 */
233 /* codegen_increase ************************************************************
237 *******************************************************************************/
239 void codegen_increase(codegendata *cd)
243 /* save old mcodebase pointer */
245 oldmcodebase = cd->mcodebase;
247 /* reallocate to new, doubled memory */
249 cd->mcodebase = DMREALLOC(cd->mcodebase,
254 cd->mcodeend = cd->mcodebase + cd->mcodesize;
256 /* set new mcodeptr */
258 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
260 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
261 /* adjust the pointer to the last patcher position */
263 if (cd->lastmcodeptr != NULL)
264 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
269 /* codegen_ncode_increase ******************************************************
273 *******************************************************************************/
275 #if defined(ENABLE_INTRP)
276 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
280 /* save old ncodebase pointer */
282 oldncodebase = cd->ncodebase;
284 /* reallocate to new, doubled memory */
286 cd->ncodebase = DMREALLOC(cd->ncodebase,
292 /* return the new ncodeptr */
294 return (cd->ncodebase + (ncodeptr - oldncodebase));
299 void codegen_addreference(codegendata *cd, basicblock *target)
303 branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
305 #if defined(ENABLE_JIT)
306 /* Check if the target basicblock has already a start pc, so the
307 jump is backward and we can resolve it immediately. */
309 /* The interpreter uses absolute branches, so we do branch
310 resolving after the code and data segment move. */
313 # if defined(ENABLE_INTRP)
318 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
325 branchref *br = DNEW(branchref);
327 br->branchpos = branchpos;
328 br->next = target->branchrefs;
330 target->branchrefs = br;
335 /* codegen_add_exception_ref ***************************************************
337 Adds an exception branch to the list.
339 *******************************************************************************/
341 static void codegen_add_exception_ref(codegendata *cd, s4 reg,
342 functionptr function)
347 branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
349 eref = DNEW(exceptionref);
351 eref->branchpos = branchpos;
353 eref->function = function;
354 eref->next = cd->exceptionrefs;
356 cd->exceptionrefs = eref;
360 /* codegen_add_arithmeticexception_ref *****************************************
362 Adds an ArithmeticException branch to the list.
364 *******************************************************************************/
366 void codegen_add_arithmeticexception_ref(codegendata *cd)
368 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arithmeticexception);
372 /* codegen_add_arrayindexoutofboundsexception_ref ******************************
374 Adds an ArrayIndexOutOfBoundsException branch to the list.
376 *******************************************************************************/
378 void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd, s4 reg)
380 codegen_add_exception_ref(cd, reg,
381 STACKTRACE_inline_arrayindexoutofboundsexception);
385 /* codegen_add_arraystoreexception_ref *****************************************
387 Adds an ArrayStoreException branch to the list.
389 *******************************************************************************/
391 void codegen_add_arraystoreexception_ref(codegendata *cd)
393 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arraystoreexception);
397 /* codegen_add_classcastexception_ref ******************************************
399 Adds an ClassCastException branch to the list.
401 *******************************************************************************/
403 void codegen_add_classcastexception_ref(codegendata *cd)
405 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_classcastexception);
409 /* codegen_add_nullpointerexception_ref ****************************************
411 Adds an NullPointerException branch to the list.
413 *******************************************************************************/
415 void codegen_add_nullpointerexception_ref(codegendata *cd)
417 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_nullpointerexception);
421 /* codegen_add_fillinstacktrace_ref ********************************************
423 Adds a fillInStackTrace branch to the list.
425 *******************************************************************************/
427 void codegen_add_fillinstacktrace_ref(codegendata *cd)
429 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_fillInStackTrace);
433 /* codegen_addpatchref *********************************************************
435 Adds a new patcher reference to the list of patching positions.
437 *******************************************************************************/
439 void codegen_addpatchref(codegendata *cd, functionptr patcher, voidptr ref,
445 branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
449 pr->branchpos = branchpos;
450 pr->patcher = patcher;
454 pr->next = cd->patchrefs;
457 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
458 /* On some architectures the patcher stub call instruction might
459 be longer than the actual instruction generated. On this
460 architectures we store the last patcher call position and after
461 the basic block code generation is completed, we check the
462 range and maybe generate some nop's. */
464 cd->lastmcodeptr = ((u1 *) cd->mcodeptr) + PATCHER_CALL_SIZE;
469 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
470 /* methodtree_comparator *******************************************************
474 *******************************************************************************/
476 static s4 methodtree_comparator(const void *pc, const void *element)
478 methodtree_element *mte;
479 methodtree_element *mtepc;
481 mte = (methodtree_element *) element;
482 mtepc = (methodtree_element *) pc;
484 /* compare both startpc and endpc of pc, even if they have the same value,
485 otherwise the avl_probe sometimes thinks the element is already in the
488 if ((long) mte->startpc <= (long) mtepc->startpc &&
489 (long) mtepc->startpc <= (long) mte->endpc &&
490 (long) mte->startpc <= (long) mtepc->endpc &&
491 (long) mtepc->endpc <= (long) mte->endpc) {
494 } else if ((long) mtepc->startpc < (long) mte->startpc) {
503 /* codegen_insertmethod ********************************************************
507 *******************************************************************************/
509 void codegen_insertmethod(u1 *startpc, u1 *endpc)
511 methodtree_element *mte;
513 /* allocate new method entry */
515 mte = NEW(methodtree_element);
517 mte->startpc = startpc;
520 /* this function does not return an error, but asserts for
523 avl_insert(methodtree, mte);
527 /* codegen_findmethod **********************************************************
531 *******************************************************************************/
533 u1 *codegen_findmethod(u1 *pc)
535 methodtree_element mtepc;
536 methodtree_element *mte;
538 /* allocation of the search structure on the stack is much faster */
543 mte = avl_find(methodtree, &mtepc);
546 printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
549 throw_cacao_exception_exit(string_java_lang_InternalError,
550 "Cannot find Java function at %p", pc);
555 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
558 /* codegen_finish **************************************************************
560 Finishes the code generation. A new memory, large enough for both
561 data and code, is allocated and data and code are copied together
562 to their final layout, unresolved jumps are resolved, ...
564 *******************************************************************************/
566 void codegen_finish(jitdata *jd)
571 #if defined(ENABLE_INTRP)
580 /* get required compiler data */
585 /* prevent compiler warning */
587 #if defined(ENABLE_INTRP)
591 /* calculate the code length */
593 mcodelen = (s4) ((u1 *) cd->mcodeptr - cd->mcodebase);
595 #if defined(ENABLE_THREADS)
596 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
601 #if defined(ENABLE_STATISTICS)
603 count_code_len += mcodelen;
604 count_data_len += cd->dseglen;
608 alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
610 #if defined(ENABLE_INTRP)
612 ncodelen = cd->ncodeptr - cd->ncodebase;
614 ncodelen = 0; /* avoid compiler warning */
618 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
619 alignedlen = alignedmcodelen + cd->dseglen;
621 #if defined(ENABLE_INTRP)
623 alignedlen += ncodelen;
627 /* allocate new memory */
629 code->mcodelength = mcodelen + cd->dseglen;
630 code->mcode = CNEW(u1, alignedlen + extralen);
632 /* copy data and code to their new location */
634 MCOPY((void *) code->mcode, cd->dsegtop - cd->dseglen, u1, cd->dseglen);
635 MCOPY((void *) (code->mcode + cd->dseglen), cd->mcodebase, u1, mcodelen);
637 /* set the entrypoint of the method */
639 assert(code->entrypoint == NULL);
640 code->entrypoint = epoint = (code->mcode + cd->dseglen);
642 #if defined(ENABLE_INTRP)
643 /* relocate native dynamic superinstruction code (if any) */
646 cd->mcodebase = code->entrypoint;
649 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
651 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
653 /* flush the instruction and data caches */
655 md_cacheflush(ncodebase, ncodelen);
657 /* set some cd variables for dynamic_super_rerwite */
659 cd->ncodebase = ncodebase;
662 cd->ncodebase = NULL;
665 dynamic_super_rewrite(cd);
669 /* jump table resolving */
671 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
672 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
673 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
675 /* line number table resolving */
681 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
683 target = lr->targetmpc;
684 /* if the entry contains an mcode pointer (normal case), resolve it */
685 /* (see doc/inlining_stacktrace.txt for details) */
686 if (lr->linenumber >= -2) {
687 target += (ptrint) epoint;
689 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
690 (functionptr) target;
693 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
694 (functionptr) ((ptrint) epoint + cd->linenumbertab);
696 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
699 /* replacement point resolving */
704 rp = code->rplpoints;
705 for (i=0; i<code->rplpointcount; ++i, ++rp) {
706 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
707 rp->outcode = (u1*) ((ptrint) epoint + (ptrint) rp->outcode);
711 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
712 /* add method into methodtree to find the entrypoint */
714 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
718 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
719 /* resolve data segment references */
721 dseg_resolve_datareferences(jd);
725 #if defined(ENABLE_THREADS)
727 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
729 codegen_critical_section_t *nt = cd->threadcrit;
731 for (i = 0; i < cd->threadcritcount; i++) {
732 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
733 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
734 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
735 critical_register_critical_section(n);
742 /* flush the instruction and data caches */
744 md_cacheflush(code->mcode, code->mcodelength);
748 /* codegen_createnativestub ****************************************************
750 Wrapper for createnativestub.
753 the codeinfo representing the stub code.
755 *******************************************************************************/
757 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
766 /* mark dump memory */
768 dumpsize = dump_size();
773 jd->cd = DNEW(codegendata);
774 jd->rd = DNEW(registerdata);
776 /* Allocate codeinfo memory from the heap as we need to keep them. */
778 jd->code = code_codeinfo_new(m); /* XXX check allocation */
780 /* get required compiler data */
784 /* setup code generation stuff */
786 #if defined(ENABLE_JIT)
787 # if defined(ENABLE_INTRP)
795 /* create new method descriptor with additional native parameters */
798 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
800 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
801 md->paramcount * sizeof(typedesc) +
802 nativeparams * sizeof(typedesc));
804 nmd->paramcount = md->paramcount + nativeparams;
806 nmd->params = DMNEW(paramdesc, nmd->paramcount);
808 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
810 if (m->flags & ACC_STATIC)
811 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
813 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
816 #if defined(ENABLE_JIT)
817 # if defined(ENABLE_INTRP)
823 /* generate the code */
825 #if defined(ENABLE_JIT)
826 # if defined(ENABLE_INTRP)
828 code->entrypoint = intrp_createnativestub(f, jd, nmd);
831 code->entrypoint = createnativestub(f, jd, nmd);
833 code->entrypoint = intrp_createnativestub(f, jd, nmd);
836 #if defined(ENABLE_STATISTICS)
838 count_nstub_len += code->mcodelength;
842 /* disassemble native stub */
844 if (opt_shownativestub) {
845 #if defined(ENABLE_DISASSEMBLER)
846 codegen_disassemble_nativestub(m,
847 (u1 *) (ptrint) code->entrypoint,
848 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
851 /* show data segment */
853 if (opt_showddatasegment)
856 #endif /* !defined(NDEBUG) */
860 dump_release(dumpsize);
862 /* return native stub code */
868 /* codegen_disassemble_nativestub **********************************************
870 Disassembles the generated native stub.
872 *******************************************************************************/
874 #if defined(ENABLE_DISASSEMBLER)
875 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
877 printf("Native stub: ");
878 utf_fprint_printable_ascii_classname(stdout, m->class->name);
880 utf_fprint_printable_ascii(stdout, m->name);
881 utf_fprint_printable_ascii(stdout, m->descriptor);
882 printf("\n\nLength: %d\n\n", (s4) (end - start));
884 DISASSEMBLE(start, end);
889 /* codegen_start_native_call ***************************************************
891 Prepares the stuff required for a native (JNI) function call:
893 - adds a stackframe info structure to the chain, for stacktraces
894 - prepares the local references table on the stack
896 The layout of the native stub stackframe should look like this:
898 +---------------------------+ <- SP (of parent Java function)
900 +---------------------------+
902 | stackframe info structure |
904 +---------------------------+
906 | local references table |
908 +---------------------------+
910 | arguments (if any) |
912 +---------------------------+ <- SP (native stub)
914 *******************************************************************************/
916 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
921 /* get data structures from stack */
923 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
924 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
925 sizeof(localref_table));
927 /* add a stackframeinfo to the chain */
929 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
931 /* add current JNI local references table to this thread */
933 lrt->capacity = LOCALREFTABLE_CAPACITY;
935 lrt->localframes = 1;
936 lrt->prev = LOCALREFTABLE;
938 /* clear the references array (memset is faster the a for-loop) */
940 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
946 /* codegen_finish_native_call **************************************************
948 Removes the stuff required for a native (JNI) function call.
950 *******************************************************************************/
952 void codegen_finish_native_call(u1 *datasp)
955 stackframeinfo **psfi;
957 localref_table *plrt;
960 /* get data structures from stack */
962 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
963 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
964 sizeof(localref_table));
966 /* remove current stackframeinfo from chain */
968 psfi = STACKFRAMEINFO;
972 /* release JNI local references tables for this thread */
976 /* release all current local frames */
978 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
979 /* get previous frame */
983 /* Clear all reference entries (only for tables allocated on
987 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
991 /* set new local references table */
996 /* now store the previous local frames in the thread structure */
1002 /* removecompilerstub **********************************************************
1004 Deletes a compilerstub from memory (simply by freeing it).
1006 *******************************************************************************/
1008 void removecompilerstub(u1 *stub)
1010 /* pass size 1 to keep the intern function happy */
1012 CFREE((void *) stub, 1);
1016 /* removenativestub ************************************************************
1018 Removes a previously created native-stub from memory.
1020 *******************************************************************************/
1022 void removenativestub(u1 *stub)
1024 /* pass size 1 to keep the intern function happy */
1026 CFREE((void *) stub, 1);
1030 /* codegen_reg_of_var **********************************************************
1032 This function determines a register, to which the result of an
1033 operation should go, when it is ultimatively intended to store the
1034 result in pseudoregister v. If v is assigned to an actual
1035 register, this register will be returned. Otherwise (when v is
1036 spilled) this function returns tempregnum. If not already done,
1037 regoff and flags are set in the stack location.
1039 On ARM we have to check if a long/double variable is splitted
1040 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1041 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1042 cases. (michi 2005/07/24)
1044 *******************************************************************************/
1046 s4 codegen_reg_of_var(registerdata *rd, u2 opcode, stackptr v, s4 tempregnum)
1050 /* Do we have to generate a conditional move? Yes, then always
1051 return the temporary register. The real register is identified
1052 during the store. */
1054 if (opcode & ICMD_CONDITION_MASK)
1057 switch (v->varkind) {
1059 if (!(v->flags & INMEMORY))
1064 var = &(rd->interfaces[v->varnum][v->type]);
1065 v->regoff = var->regoff;
1066 if (!(var->flags & INMEMORY))
1067 return(var->regoff);
1071 var = &(rd->locals[v->varnum][v->type]);
1072 v->regoff = var->regoff;
1073 if (!(var->flags & INMEMORY)) {
1074 #if defined(__ARM__) && defined(__ARMEL__)
1075 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1076 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1078 #if defined(__ARM__) && defined(__ARMEB__)
1079 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1080 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1082 return(var->regoff);
1087 if (!(v->flags & INMEMORY)) {
1088 #if defined(__ARM__) && defined(__ARMEL__)
1089 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1090 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1092 #if defined(__ARM__) && defined(__ARMEB__)
1093 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1094 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1101 #if defined(ENABLE_STATISTICS)
1103 count_spills_read++;
1106 v->flags |= INMEMORY;
1112 #if defined(ENABLE_THREADS)
1113 void codegen_threadcritrestart(codegendata *cd, int offset)
1115 cd->threadcritcurrent.mcoderestart = offset;
1119 void codegen_threadcritstart(codegendata *cd, int offset)
1121 cd->threadcritcurrent.mcodebegin = offset;
1125 void codegen_threadcritstop(codegendata *cd, int offset)
1127 cd->threadcritcurrent.next = cd->threadcrit;
1128 cd->threadcritcurrent.mcodeend = offset;
1129 cd->threadcrit = DNEW(codegen_critical_section_t);
1130 *(cd->threadcrit) = cd->threadcritcurrent;
1131 cd->threadcritcount++;
1137 * These are local overrides for various environment variables in Emacs.
1138 * Please do not remove this and leave it at the end of the file, where
1139 * Emacs will automagically detect them.
1140 * ---------------------------------------------------------------------
1143 * indent-tabs-mode: t
1147 * vim:noexpandtab:sw=4:ts=4: