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 4775 2006-04-14 11:57:04Z 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(USE_THREADS)
80 # if defined(NATIVE_THREADS)
81 # include "threads/native/threads.h"
83 # include "threads/green/threads.h"
87 #include "vm/exceptions.h"
88 #include "vm/method.h"
89 #include "vm/options.h"
90 #include "vm/statistics.h"
91 #include "vm/stringlocal.h"
92 #include "vm/jit/asmpart.h"
93 #include "vm/jit/codegen-common.h"
95 #if defined(ENABLE_DISASSEMBLER)
96 # include "vm/jit/disass.h"
99 #include "vm/jit/dseg.h"
100 #include "vm/jit/jit.h"
101 #include "vm/jit/stacktrace.h"
102 #include "vm/jit/replace.h"
105 /* in this tree we store all method addresses *********************************/
107 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
108 static avl_tree *methodtree = NULL;
109 static s4 methodtree_comparator(const void *pc, const void *element);
113 /* codegen_init ****************************************************************
117 *******************************************************************************/
119 void codegen_init(void)
121 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
122 /* this tree is global, not method specific */
125 #if defined(ENABLE_JIT)
126 methodtree_element *mte;
129 methodtree = avl_create(&methodtree_comparator);
131 #if defined(ENABLE_JIT)
132 /* insert asm_vm_call_method */
134 mte = NEW(methodtree_element);
136 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
137 mte->endpc = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
139 avl_insert(methodtree, mte);
140 #endif /* defined(ENABLE_JIT) */
142 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
146 /* codegen_setup ***************************************************************
148 Allocates and initialises code area, data area and references.
150 *******************************************************************************/
152 void codegen_setup(jitdata *jd)
157 /* get required compiler data */
162 cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
163 cd->mcodeend = cd->mcodebase + MCODEINITSIZE;
164 cd->mcodesize = MCODEINITSIZE;
166 /* initialize mcode variables */
168 #if defined(__I386__) || defined(__X86_64__)
169 cd->mcodeptr = cd->mcodebase;
171 cd->mcodeptr = (u4 *) cd->mcodebase;
174 cd->lastmcodeptr = cd->mcodebase;
176 #if defined(ENABLE_INTRP)
177 /* native dynamic superinstructions variables */
180 cd->ncodebase = DMNEW(u1, NCODEINITSIZE);
181 cd->ncodesize = NCODEINITSIZE;
183 /* initialize ncode variables */
185 cd->ncodeptr = cd->ncodebase;
187 cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */
188 cd->superstarts = NULL;
192 cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
193 cd->dsegsize = DSEGINITSIZE;
194 cd->dsegtop += cd->dsegsize;
197 cd->jumpreferences = NULL;
199 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
200 cd->datareferences = NULL;
203 cd->exceptionrefs = NULL;
204 cd->patchrefs = NULL;
206 cd->linenumberreferences = NULL;
207 cd->linenumbertablesizepos = 0;
208 cd->linenumbertablestartpos = 0;
209 cd->linenumbertab = 0;
212 cd->exceptiontable = 0;
213 cd->exceptiontablelength = 0;
215 if (m->exceptiontablelength > 0) {
216 cd->exceptiontablelength = m->exceptiontablelength;
217 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
220 cd->maxstack = m->maxstack;
221 cd->maxlocals = m->maxlocals;
223 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
224 cd->threadcritcurrent.next = NULL;
225 cd->threadcritcount = 0;
230 /* codegen_close ***************************************************************
234 *******************************************************************************/
236 void codegen_close(void)
238 /* TODO: release avl tree on i386 and x86_64 */
242 /* codegen_increase ************************************************************
246 *******************************************************************************/
248 s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
252 /* save old mcodebase pointer */
254 oldmcodebase = cd->mcodebase;
256 /* reallocate to new, doubled memory */
258 cd->mcodebase = DMREALLOC(cd->mcodebase,
263 cd->mcodeend = cd->mcodebase + cd->mcodesize;
265 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
266 /* adjust the pointer to the last patcher position */
268 if (cd->lastmcodeptr != NULL)
269 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
272 /* return the new mcodeptr */
274 return (s4 *) (cd->mcodebase + (mcodeptr - oldmcodebase));
278 /* codegen_ncode_increase ******************************************************
282 *******************************************************************************/
284 #if defined(ENABLE_INTRP)
285 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
289 /* save old ncodebase pointer */
291 oldncodebase = cd->ncodebase;
293 /* reallocate to new, doubled memory */
295 cd->ncodebase = DMREALLOC(cd->ncodebase,
301 /* return the new ncodeptr */
303 return (cd->ncodebase + (ncodeptr - oldncodebase));
308 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
312 branchpos = (u1 *) branchptr - cd->mcodebase;
314 #if defined(ENABLE_JIT)
315 /* Check if the target basicblock has already a start pc, so the
316 jump is backward and we can resolve it immediately. */
318 /* The interpreter uses absolute branches, so we do branch
319 resolving after the code and data segment move. */
322 # if defined(ENABLE_INTRP)
327 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
334 branchref *br = DNEW(branchref);
336 br->branchpos = branchpos;
337 br->next = target->branchrefs;
339 target->branchrefs = br;
344 /* codegen_add_exception_ref ***************************************************
346 Adds an exception branch to the list.
348 *******************************************************************************/
350 static void codegen_add_exception_ref(codegendata *cd, void *branchptr, s4 reg,
351 functionptr function)
356 branchpos = (u1 *) branchptr - cd->mcodebase;
358 eref = DNEW(exceptionref);
360 eref->branchpos = branchpos;
362 eref->function = function;
363 eref->next = cd->exceptionrefs;
365 cd->exceptionrefs = eref;
369 /* codegen_add_arithmeticexception_ref *****************************************
371 Adds an ArithmeticException branch to the list.
373 *******************************************************************************/
375 void codegen_add_arithmeticexception_ref(codegendata *cd, void *branchptr)
377 codegen_add_exception_ref(cd, branchptr, -1,
378 STACKTRACE_inline_arithmeticexception);
382 /* codegen_add_arrayindexoutofboundsexception_ref ******************************
384 Adds an ArrayIndexOutOfBoundsException branch to the list.
386 *******************************************************************************/
388 void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd,
389 void *branchptr, s4 reg)
391 codegen_add_exception_ref(cd, branchptr, reg,
392 STACKTRACE_inline_arrayindexoutofboundsexception);
396 /* codegen_add_arraystoreexception_ref *****************************************
398 Adds an ArrayStoreException branch to the list.
400 *******************************************************************************/
402 void codegen_add_arraystoreexception_ref(codegendata *cd, void *branchptr)
404 codegen_add_exception_ref(cd, branchptr, -1,
405 STACKTRACE_inline_arraystoreexception);
409 /* codegen_add_classcastexception_ref ******************************************
411 Adds an ClassCastException branch to the list.
413 *******************************************************************************/
415 void codegen_add_classcastexception_ref(codegendata *cd, void *branchptr)
417 codegen_add_exception_ref(cd, branchptr, -1,
418 STACKTRACE_inline_classcastexception);
422 /* codegen_add_nullpointerexception_ref ****************************************
424 Adds an NullPointerException branch to the list.
426 *******************************************************************************/
428 void codegen_add_nullpointerexception_ref(codegendata *cd, void *branchptr)
430 codegen_add_exception_ref(cd, branchptr, -1,
431 STACKTRACE_inline_nullpointerexception);
435 /* codegen_add_fillinstacktrace_ref ********************************************
437 Adds a fillInStackTrace branch to the list.
439 *******************************************************************************/
441 void codegen_add_fillinstacktrace_ref(codegendata *cd, void *branchptr)
443 codegen_add_exception_ref(cd, branchptr, -1,
444 STACKTRACE_inline_fillInStackTrace);
448 /* codegen_addpatchref *********************************************************
450 Adds a new patcher reference to the list of patching positions.
452 *******************************************************************************/
454 void codegen_addpatchref(codegendata *cd, voidptr branchptr,
455 functionptr patcher, voidptr ref, s4 disp)
460 branchpos = (u1 *) branchptr - cd->mcodebase;
464 pr->branchpos = branchpos;
465 pr->patcher = patcher;
469 pr->next = cd->patchrefs;
472 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
473 /* On some architectures the patcher stub call instruction might
474 be longer than the actual instruction generated. On this
475 architectures we store the last patcher call position and after
476 the basic block code generation is completed, we check the
477 range and maybe generate some nop's. */
479 cd->lastmcodeptr = ((u1 *) branchptr) + PATCHER_CALL_SIZE;
484 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
485 /* methodtree_comparator *******************************************************
489 *******************************************************************************/
491 static s4 methodtree_comparator(const void *pc, const void *element)
493 methodtree_element *mte;
494 methodtree_element *mtepc;
496 mte = (methodtree_element *) element;
497 mtepc = (methodtree_element *) pc;
499 /* compare both startpc and endpc of pc, even if they have the same value,
500 otherwise the avl_probe sometimes thinks the element is already in the
503 if ((long) mte->startpc <= (long) mtepc->startpc &&
504 (long) mtepc->startpc <= (long) mte->endpc &&
505 (long) mte->startpc <= (long) mtepc->endpc &&
506 (long) mtepc->endpc <= (long) mte->endpc) {
509 } else if ((long) mtepc->startpc < (long) mte->startpc) {
518 /* codegen_insertmethod ********************************************************
522 *******************************************************************************/
524 void codegen_insertmethod(u1 *startpc, u1 *endpc)
526 methodtree_element *mte;
528 /* allocate new method entry */
530 mte = NEW(methodtree_element);
532 mte->startpc = startpc;
535 /* this function does not return an error, but asserts for
538 avl_insert(methodtree, mte);
542 /* codegen_findmethod **********************************************************
546 *******************************************************************************/
548 u1 *codegen_findmethod(u1 *pc)
550 methodtree_element mtepc;
551 methodtree_element *mte;
553 /* allocation of the search structure on the stack is much faster */
558 mte = avl_find(methodtree, &mtepc);
561 printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
564 throw_cacao_exception_exit(string_java_lang_InternalError,
565 "Cannot find Java function at %p", pc);
570 #endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
573 /* codegen_finish **************************************************************
575 Finishes the code generation. A new memory, large enough for both
576 data and code, is allocated and data and code are copied together
577 to their final layout, unresolved jumps are resolved, ...
579 *******************************************************************************/
581 void codegen_finish(jitdata *jd, s4 mcodelen)
588 #if defined(ENABLE_INTRP)
597 /* get required compiler data */
602 /* prevent compiler warning */
604 #if defined(ENABLE_INTRP)
608 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
609 extralen = sizeof(threadcritnode) * cd->threadcritcount;
614 #if defined(ENABLE_STATISTICS)
616 count_code_len += mcodelen;
617 count_data_len += cd->dseglen;
622 mcodelen = cd->mcodeptr - cd->mcodebase;
624 alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
626 #if defined(ENABLE_INTRP)
628 ncodelen = cd->ncodeptr - cd->ncodebase;
630 ncodelen = 0; /* avoid compiler warning */
634 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
635 alignedlen = alignedmcodelen + cd->dseglen;
637 #if defined(ENABLE_INTRP)
639 alignedlen += ncodelen;
643 /* allocate new memory */
645 code->mcodelength = mcodelen + cd->dseglen;
646 code->mcode = CNEW(u1, alignedlen + extralen);
648 /* copy data and code to their new location */
650 MCOPY((void *) code->mcode, cd->dsegtop - cd->dseglen, u1, cd->dseglen);
651 MCOPY((void *) (code->mcode + cd->dseglen), cd->mcodebase, u1, mcodelen);
653 /* set the entrypoint of the method */
655 assert(code->entrypoint == NULL);
656 code->entrypoint = epoint = (code->mcode + cd->dseglen);
658 #if defined(ENABLE_INTRP)
659 /* relocate native dynamic superinstruction code (if any) */
662 cd->mcodebase = code->entrypoint;
665 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
667 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
669 /* flush the instruction and data caches */
671 md_cacheflush(ncodebase, ncodelen);
673 /* set some cd variables for dynamic_super_rerwite */
675 cd->ncodebase = ncodebase;
678 cd->ncodebase = NULL;
681 dynamic_super_rewrite(cd);
685 /* jump table resolving */
687 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
688 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
689 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
691 /* line number table resolving */
697 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
699 target = lr->targetmpc;
700 /* if the entry contains an mcode pointer (normal case), resolve it */
701 /* (see doc/inlining_stacktrace.txt for details) */
702 if (lr->linenumber >= -2) {
703 target += (ptrint) epoint;
705 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
706 (functionptr) target;
709 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
710 (functionptr) ((ptrint) epoint + cd->linenumbertab);
712 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
715 /* replacement point resolving */
720 rp = code->rplpoints;
721 for (i=0; i<code->rplpointcount; ++i, ++rp) {
722 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
723 rp->outcode = (u1*) ((ptrint) epoint + (ptrint) rp->outcode);
727 #if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
728 /* add method into methodtree to find the entrypoint */
730 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
734 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
735 /* resolve data segment references */
737 dseg_resolve_datareferences(jd);
741 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
743 threadcritnode *n = (threadcritnode *) ((ptrint) code->mcode + alignedlen);
745 threadcritnodetemp *nt = cd->threadcrit;
747 for (i = 0; i < cd->threadcritcount; i++) {
748 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
749 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
750 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
751 thread_registercritical(n);
758 /* flush the instruction and data caches */
760 md_cacheflush(code->mcode, code->mcodelength);
764 /* codegen_createnativestub ****************************************************
766 Wrapper for createnativestub.
769 the codeinfo representing the stub code.
771 *******************************************************************************/
773 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
782 /* mark dump memory */
784 dumpsize = dump_size();
789 jd->cd = DNEW(codegendata);
790 jd->rd = DNEW(registerdata);
792 /* Allocate codeinfo memory from the heap as we need to keep them. */
794 jd->code = code_codeinfo_new(m); /* XXX check allocation */
796 /* get required compiler data */
800 /* setup code generation stuff */
802 #if defined(ENABLE_JIT)
803 # if defined(ENABLE_INTRP)
811 /* create new method descriptor with additional native parameters */
814 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
816 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
817 md->paramcount * sizeof(typedesc) +
818 nativeparams * sizeof(typedesc));
820 nmd->paramcount = md->paramcount + nativeparams;
822 nmd->params = DMNEW(paramdesc, nmd->paramcount);
824 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
826 if (m->flags & ACC_STATIC)
827 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
829 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
832 #if defined(ENABLE_JIT)
833 # if defined(ENABLE_INTRP)
839 /* generate the code */
841 #if defined(ENABLE_JIT)
842 # if defined(ENABLE_INTRP)
844 code->entrypoint = intrp_createnativestub(f, jd, nmd);
847 code->entrypoint = createnativestub(f, jd, nmd);
849 code->entrypoint = intrp_createnativestub(f, jd, nmd);
852 #if defined(ENABLE_STATISTICS)
854 count_nstub_len += code->mcodelength;
858 /* disassemble native stub */
860 if (opt_shownativestub) {
861 #if defined(ENABLE_DISASSEMBLER)
862 codegen_disassemble_nativestub(m,
863 (u1 *) (ptrint) code->entrypoint,
864 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
867 /* show data segment */
869 if (opt_showddatasegment)
872 #endif /* !defined(NDEBUG) */
876 dump_release(dumpsize);
878 /* return native stub code */
884 /* codegen_disassemble_nativestub **********************************************
886 Disassembles the generated native stub.
888 *******************************************************************************/
890 #if defined(ENABLE_DISASSEMBLER)
891 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
893 printf("Native stub: ");
894 utf_fprint_classname(stdout, m->class->name);
896 utf_fprint(stdout, m->name);
897 utf_fprint(stdout, m->descriptor);
898 printf("\n\nLength: %d\n\n", (s4) (end - start));
900 DISASSEMBLE(start, end);
905 /* codegen_start_native_call ***************************************************
907 Prepares the stuff required for a native (JNI) function call:
909 - adds a stackframe info structure to the chain, for stacktraces
910 - prepares the local references table on the stack
912 The layout of the native stub stackframe should look like this:
914 +---------------------------+ <- SP (of parent Java function)
916 +---------------------------+
918 | stackframe info structure |
920 +---------------------------+
922 | local references table |
924 +---------------------------+
926 | arguments (if any) |
928 +---------------------------+ <- SP (native stub)
930 *******************************************************************************/
932 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
937 /* get data structures from stack */
939 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
940 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
941 sizeof(localref_table));
943 /* add a stackframeinfo to the chain */
945 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
947 /* add current JNI local references table to this thread */
949 lrt->capacity = LOCALREFTABLE_CAPACITY;
951 lrt->localframes = 1;
952 lrt->prev = LOCALREFTABLE;
954 /* clear the references array (memset is faster the a for-loop) */
956 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
962 /* codegen_finish_native_call **************************************************
964 Removes the stuff required for a native (JNI) function call.
966 *******************************************************************************/
968 void codegen_finish_native_call(u1 *datasp)
971 stackframeinfo **psfi;
973 localref_table *plrt;
976 /* get data structures from stack */
978 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
979 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
980 sizeof(localref_table));
982 /* remove current stackframeinfo from chain */
984 psfi = STACKFRAMEINFO;
988 /* release JNI local references tables for this thread */
992 /* release all current local frames */
994 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
995 /* get previous frame */
999 /* Clear all reference entries (only for tables allocated on
1002 if (localframes > 1)
1003 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1007 /* set new local references table */
1012 /* now store the previous local frames in the thread structure */
1014 LOCALREFTABLE = lrt;
1018 /* removecompilerstub **********************************************************
1020 Deletes a compilerstub from memory (simply by freeing it).
1022 *******************************************************************************/
1024 void removecompilerstub(u1 *stub)
1026 /* pass size 1 to keep the intern function happy */
1028 CFREE((void *) stub, 1);
1032 /* removenativestub ************************************************************
1034 Removes a previously created native-stub from memory.
1036 *******************************************************************************/
1038 void removenativestub(u1 *stub)
1040 /* pass size 1 to keep the intern function happy */
1042 CFREE((void *) stub, 1);
1046 /* codegen_reg_of_var **********************************************************
1048 This function determines a register, to which the result of an
1049 operation should go, when it is ultimatively intended to store the
1050 result in pseudoregister v. If v is assigned to an actual
1051 register, this register will be returned. Otherwise (when v is
1052 spilled) this function returns tempregnum. If not already done,
1053 regoff and flags are set in the stack location.
1055 On ARM we have to check if a long/double variable is splitted
1056 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1057 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1058 cases. (michi 2005/07/24)
1060 *******************************************************************************/
1062 s4 codegen_reg_of_var(registerdata *rd, u2 opcode, stackptr v, s4 tempregnum)
1066 /* Do we have to generate a conditional move? Yes, then always
1067 return the temporary register. The real register is identified
1068 during the store. */
1070 if (opcode & ICMD_CONDITION_MASK)
1073 switch (v->varkind) {
1075 if (!(v->flags & INMEMORY))
1080 var = &(rd->interfaces[v->varnum][v->type]);
1081 v->regoff = var->regoff;
1082 if (!(var->flags & INMEMORY))
1083 return(var->regoff);
1087 var = &(rd->locals[v->varnum][v->type]);
1088 v->regoff = var->regoff;
1089 if (!(var->flags & INMEMORY)) {
1090 #if defined(__ARM__) && defined(__ARMEL__)
1091 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
1092 return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
1094 #if defined(__ARM__) && defined(__ARMEB__)
1095 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
1096 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
1098 return(var->regoff);
1103 if (!(v->flags & INMEMORY)) {
1104 #if defined(__ARM__) && defined(__ARMEL__)
1105 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
1106 return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
1108 #if defined(__ARM__) && defined(__ARMEB__)
1109 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
1110 return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
1117 #if defined(ENABLE_STATISTICS)
1119 count_spills_read++;
1122 v->flags |= INMEMORY;
1128 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1129 void codegen_threadcritrestart(codegendata *cd, int offset)
1131 cd->threadcritcurrent.mcoderestart = offset;
1135 void codegen_threadcritstart(codegendata *cd, int offset)
1137 cd->threadcritcurrent.mcodebegin = offset;
1141 void codegen_threadcritstop(codegendata *cd, int offset)
1143 cd->threadcritcurrent.next = cd->threadcrit;
1144 cd->threadcritcurrent.mcodeend = offset;
1145 cd->threadcrit = DNEW(threadcritnodetemp);
1146 *(cd->threadcrit) = cd->threadcritcurrent;
1147 cd->threadcritcount++;
1153 * These are local overrides for various environment variables in Emacs.
1154 * Please do not remove this and leave it at the end of the file, where
1155 * Emacs will automagically detect them.
1156 * ---------------------------------------------------------------------
1159 * indent-tabs-mode: t
1163 * vim:noexpandtab:sw=4:ts=4: