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 5801 2006-10-18 16:55:43Z edwin $
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"
100 #if defined(ENABLE_INTRP)
101 #include "vm/jit/intrp/intrp.h"
105 /* in this tree we store all method addresses *********************************/
107 static avl_tree *methodtree = NULL;
108 static s4 methodtree_comparator(const void *pc, const void *element);
111 /* codegen_init ****************************************************************
115 *******************************************************************************/
117 void codegen_init(void)
119 /* this tree is global, not method specific */
122 #if defined(ENABLE_JIT)
123 methodtree_element *mte;
126 methodtree = avl_create(&methodtree_comparator);
128 #if defined(ENABLE_JIT)
129 /* insert asm_vm_call_method */
131 mte = NEW(methodtree_element);
133 mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
134 mte->endpc = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
136 avl_insert(methodtree, mte);
137 #endif /* defined(ENABLE_JIT) */
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;
186 cd->jumpreferences = NULL;
188 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
189 cd->datareferences = NULL;
192 cd->exceptionrefs = NULL;
193 cd->patchrefs = NULL;
195 cd->linenumberreferences = NULL;
196 cd->linenumbertablesizepos = 0;
197 cd->linenumbertablestartpos = 0;
198 cd->linenumbertab = 0;
202 cd->maxstack = m->maxstack;
203 cd->maxlocals = m->maxlocals;
205 #if defined(ENABLE_THREADS)
206 cd->threadcritcurrent.next = NULL;
207 cd->threadcritcount = 0;
212 /* codegen_close ***************************************************************
216 *******************************************************************************/
218 void codegen_close(void)
220 /* TODO: release avl tree on i386 and x86_64 */
224 /* codegen_increase ************************************************************
228 *******************************************************************************/
230 void codegen_increase(codegendata *cd)
234 /* save old mcodebase pointer */
236 oldmcodebase = cd->mcodebase;
238 /* reallocate to new, doubled memory */
240 cd->mcodebase = DMREALLOC(cd->mcodebase,
245 cd->mcodeend = cd->mcodebase + cd->mcodesize;
247 /* set new mcodeptr */
249 cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
251 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
252 /* adjust the pointer to the last patcher position */
254 if (cd->lastmcodeptr != NULL)
255 cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
260 /* codegen_ncode_increase ******************************************************
264 *******************************************************************************/
266 #if defined(ENABLE_INTRP)
267 u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
271 /* save old ncodebase pointer */
273 oldncodebase = cd->ncodebase;
275 /* reallocate to new, doubled memory */
277 cd->ncodebase = DMREALLOC(cd->ncodebase,
283 /* return the new ncodeptr */
285 return (cd->ncodebase + (ncodeptr - oldncodebase));
290 void codegen_addreference(codegendata *cd, basicblock *target)
294 branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
296 #if defined(ENABLE_JIT)
297 /* Check if the target basicblock has already a start pc, so the
298 jump is backward and we can resolve it immediately. */
300 /* The interpreter uses absolute branches, so we do branch
301 resolving after the code and data segment move. */
304 # if defined(ENABLE_INTRP)
309 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
316 branchref *br = DNEW(branchref);
318 br->branchpos = branchpos;
319 br->next = target->branchrefs;
321 target->branchrefs = br;
326 /* codegen_add_exception_ref ***************************************************
328 Adds an exception branch to the list.
330 *******************************************************************************/
332 static void codegen_add_exception_ref(codegendata *cd, s4 reg,
333 functionptr function)
338 branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
340 eref = DNEW(exceptionref);
342 eref->branchpos = branchpos;
344 eref->function = function;
345 eref->next = cd->exceptionrefs;
347 cd->exceptionrefs = eref;
351 /* codegen_add_arithmeticexception_ref *****************************************
353 Adds an ArithmeticException branch to the list.
355 *******************************************************************************/
357 void codegen_add_arithmeticexception_ref(codegendata *cd)
359 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arithmeticexception);
363 /* codegen_add_arrayindexoutofboundsexception_ref ******************************
365 Adds an ArrayIndexOutOfBoundsException branch to the list.
367 *******************************************************************************/
369 void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd, s4 reg)
371 codegen_add_exception_ref(cd, reg,
372 STACKTRACE_inline_arrayindexoutofboundsexception);
376 /* codegen_add_arraystoreexception_ref *****************************************
378 Adds an ArrayStoreException branch to the list.
380 *******************************************************************************/
382 void codegen_add_arraystoreexception_ref(codegendata *cd)
384 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arraystoreexception);
388 /* codegen_add_classcastexception_ref ******************************************
390 Adds an ClassCastException branch to the list.
392 *******************************************************************************/
394 void codegen_add_classcastexception_ref(codegendata *cd, s4 reg)
396 codegen_add_exception_ref(cd, reg, STACKTRACE_inline_classcastexception);
400 /* codegen_add_nullpointerexception_ref ****************************************
402 Adds an NullPointerException branch to the list.
404 *******************************************************************************/
406 void codegen_add_nullpointerexception_ref(codegendata *cd)
408 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_nullpointerexception);
412 /* codegen_add_fillinstacktrace_ref ********************************************
414 Adds a fillInStackTrace branch to the list.
416 *******************************************************************************/
418 void codegen_add_fillinstacktrace_ref(codegendata *cd)
420 codegen_add_exception_ref(cd, -1, STACKTRACE_inline_fillInStackTrace);
424 /* codegen_addpatchref *********************************************************
426 Adds a new patcher reference to the list of patching positions.
428 *******************************************************************************/
430 void codegen_addpatchref(codegendata *cd, functionptr patcher, voidptr ref,
436 branchpos = cd->mcodeptr - cd->mcodebase;
440 pr->branchpos = branchpos;
441 pr->patcher = patcher;
445 pr->next = cd->patchrefs;
448 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
449 /* On some architectures the patcher stub call instruction might
450 be longer than the actual instruction generated. On this
451 architectures we store the last patcher call position and after
452 the basic block code generation is completed, we check the
453 range and maybe generate some nop's. */
455 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
460 /* methodtree_comparator *******************************************************
462 Comparator function used for the AVL tree of methods.
464 *******************************************************************************/
466 static s4 methodtree_comparator(const void *pc, const void *element)
468 methodtree_element *mte;
469 methodtree_element *mtepc;
471 mte = (methodtree_element *) element;
472 mtepc = (methodtree_element *) pc;
474 /* compare both startpc and endpc of pc, even if they have the same value,
475 otherwise the avl_probe sometimes thinks the element is already in the
478 if ((long) mte->startpc <= (long) mtepc->startpc &&
479 (long) mtepc->startpc <= (long) mte->endpc &&
480 (long) mte->startpc <= (long) mtepc->endpc &&
481 (long) mtepc->endpc <= (long) mte->endpc) {
484 } else if ((long) mtepc->startpc < (long) mte->startpc) {
493 /* codegen_insertmethod ********************************************************
495 Insert the machine code range of a method into the AVL tree of methods.
497 *******************************************************************************/
499 void codegen_insertmethod(u1 *startpc, u1 *endpc)
501 methodtree_element *mte;
503 /* allocate new method entry */
505 mte = NEW(methodtree_element);
507 mte->startpc = startpc;
510 /* this function does not return an error, but asserts for
513 avl_insert(methodtree, mte);
517 /* codegen_get_pv_from_pc ******************************************************
519 Find the PV for the given PC by searching in the AVL tree of
522 *******************************************************************************/
524 u1 *codegen_get_pv_from_pc(u1 *pc)
526 methodtree_element mtepc;
527 methodtree_element *mte;
529 /* allocation of the search structure on the stack is much faster */
534 mte = avl_find(methodtree, &mtepc);
537 /* No method was found. Let's dump a stacktrace. */
539 log_println("We received a SIGSEGV and tried to handle it, but we were");
540 log_println("unable to find a Java method at:");
542 #if SIZEOF_VOID_P == 8
543 log_println("PC=0x%016lx", pc);
545 log_println("PC=0x%08x", pc);
548 log_println("Dumping the current stacktrace:");
550 stacktrace_dump_trace();
552 vm_abort("Exiting...");
559 /* codegen_get_pv_from_pc_nocheck **********************************************
561 Find the PV for the given PC by searching in the AVL tree of
562 methods. This method does not check the return value and is used
565 *******************************************************************************/
567 u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
569 methodtree_element mtepc;
570 methodtree_element *mte;
572 /* allocation of the search structure on the stack is much faster */
577 mte = avl_find(methodtree, &mtepc);
586 /* codegen_finish **************************************************************
588 Finishes the code generation. A new memory, large enough for both
589 data and code, is allocated and data and code are copied together
590 to their final layout, unresolved jumps are resolved, ...
592 *******************************************************************************/
594 void codegen_finish(jitdata *jd)
599 #if defined(ENABLE_INTRP)
608 /* get required compiler data */
613 /* prevent compiler warning */
615 #if defined(ENABLE_INTRP)
619 /* calculate the code length */
621 mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
623 #if defined(ENABLE_THREADS)
624 extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
629 #if defined(ENABLE_STATISTICS)
631 count_code_len += mcodelen;
632 count_data_len += cd->dseglen;
636 alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
638 #if defined(ENABLE_INTRP)
640 ncodelen = cd->ncodeptr - cd->ncodebase;
642 ncodelen = 0; /* avoid compiler warning */
646 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
647 alignedlen = alignedmcodelen + cd->dseglen;
649 #if defined(ENABLE_INTRP)
651 alignedlen += ncodelen;
655 /* allocate new memory */
657 code->mcodelength = mcodelen + cd->dseglen;
658 code->mcode = CNEW(u1, alignedlen + extralen);
660 /* set the entrypoint of the method */
662 assert(code->entrypoint == NULL);
663 code->entrypoint = epoint = (code->mcode + cd->dseglen);
665 /* fill the data segment (code->entrypoint must already be set!) */
669 /* copy code to the new location */
671 MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
673 #if defined(ENABLE_INTRP)
674 /* relocate native dynamic superinstruction code (if any) */
677 cd->mcodebase = code->entrypoint;
680 u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
682 MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
684 /* flush the instruction and data caches */
686 md_cacheflush(ncodebase, ncodelen);
688 /* set some cd variables for dynamic_super_rerwite */
690 cd->ncodebase = ncodebase;
693 cd->ncodebase = NULL;
696 dynamic_super_rewrite(cd);
700 /* jump table resolving */
702 for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
703 *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
704 (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
706 /* line number table resolving */
712 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
714 target = lr->targetmpc;
715 /* if the entry contains an mcode pointer (normal case), resolve it */
716 /* (see doc/inlining_stacktrace.txt for details) */
717 if (lr->linenumber >= -2) {
718 target += (ptrint) epoint;
720 *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
721 (functionptr) target;
724 *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
725 (functionptr) ((ptrint) epoint + cd->linenumbertab);
727 *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
730 /* replacement point resolving */
735 rp = code->rplpoints;
736 for (i=0; i<code->rplpointcount; ++i, ++rp) {
737 rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
738 rp->outcode = (u1*) ((ptrint) epoint + (ptrint) rp->outcode);
742 /* add method into methodtree to find the entrypoint */
744 codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
746 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
747 /* resolve data segment references */
749 dseg_resolve_datareferences(jd);
752 #if defined(ENABLE_THREADS)
754 critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
756 codegen_critical_section_t *nt = cd->threadcrit;
758 for (i = 0; i < cd->threadcritcount; i++) {
759 n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
760 n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
761 n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
762 critical_register_critical_section(n);
769 /* flush the instruction and data caches */
771 md_cacheflush(code->mcode, code->mcodelength);
775 /* codegen_createnativestub ****************************************************
777 Wrapper for createnativestub.
780 the codeinfo representing the stub code.
782 *******************************************************************************/
784 codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
793 /* mark dump memory */
795 dumpsize = dump_size();
800 jd->cd = DNEW(codegendata);
801 jd->rd = DNEW(registerdata);
804 /* Allocate codeinfo memory from the heap as we need to keep them. */
806 jd->code = code_codeinfo_new(m); /* XXX check allocation */
808 /* get required compiler data */
812 /* set the flags for the current JIT run */
815 jd->flags |= JITDATA_FLAG_INSTRUMENT;
818 jd->flags |= JITDATA_FLAG_VERBOSECALL;
820 /* setup code generation stuff */
822 #if defined(ENABLE_JIT)
823 # if defined(ENABLE_INTRP)
831 /* create new method descriptor with additional native parameters */
834 nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
836 nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
837 md->paramcount * sizeof(typedesc) +
838 nativeparams * sizeof(typedesc));
840 nmd->paramcount = md->paramcount + nativeparams;
842 nmd->params = DMNEW(paramdesc, nmd->paramcount);
844 nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
846 if (m->flags & ACC_STATIC)
847 nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
849 MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
852 #if defined(ENABLE_JIT)
853 # if defined(ENABLE_INTRP)
859 /* generate the code */
861 #if defined(ENABLE_JIT)
862 # if defined(ENABLE_INTRP)
864 code->entrypoint = intrp_createnativestub(f, jd, nmd);
867 code->entrypoint = createnativestub(f, jd, nmd);
869 code->entrypoint = intrp_createnativestub(f, jd, nmd);
872 #if defined(ENABLE_STATISTICS)
874 count_nstub_len += code->mcodelength;
878 /* disassemble native stub */
880 if (opt_shownativestub) {
881 #if defined(ENABLE_DISASSEMBLER)
882 codegen_disassemble_nativestub(m,
883 (u1 *) (ptrint) code->entrypoint,
884 (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
887 /* show data segment */
889 if (opt_showddatasegment)
892 #endif /* !defined(NDEBUG) */
896 dump_release(dumpsize);
898 /* return native stub code */
904 /* codegen_disassemble_nativestub **********************************************
906 Disassembles the generated native stub.
908 *******************************************************************************/
910 #if defined(ENABLE_DISASSEMBLER)
911 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
913 printf("Native stub: ");
914 utf_fprint_printable_ascii_classname(stdout, m->class->name);
916 utf_fprint_printable_ascii(stdout, m->name);
917 utf_fprint_printable_ascii(stdout, m->descriptor);
918 printf("\n\nLength: %d\n\n", (s4) (end - start));
920 DISASSEMBLE(start, end);
925 /* codegen_start_native_call ***************************************************
927 Prepares the stuff required for a native (JNI) function call:
929 - adds a stackframe info structure to the chain, for stacktraces
930 - prepares the local references table on the stack
932 The layout of the native stub stackframe should look like this:
934 +---------------------------+ <- SP (of parent Java function)
936 +---------------------------+
938 | stackframe info structure |
940 +---------------------------+
942 | local references table |
944 +---------------------------+
946 | arguments (if any) |
948 +---------------------------+ <- SP (native stub)
950 *******************************************************************************/
952 void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
957 /* get data structures from stack */
959 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
960 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
961 sizeof(localref_table));
963 /* add a stackframeinfo to the chain */
965 stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
967 /* add current JNI local references table to this thread */
969 lrt->capacity = LOCALREFTABLE_CAPACITY;
971 lrt->localframes = 1;
972 lrt->prev = LOCALREFTABLE;
974 /* clear the references array (memset is faster the a for-loop) */
976 MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
982 /* codegen_finish_native_call **************************************************
984 Removes the stuff required for a native (JNI) function call.
985 Additionally it checks for an exceptions and in case, get the
986 exception object and clear the pointer.
988 *******************************************************************************/
990 java_objectheader *codegen_finish_native_call(u1 *datasp)
993 stackframeinfo **psfi;
995 localref_table *plrt;
997 java_objectheader *e;
999 /* get data structures from stack */
1001 sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
1002 lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
1003 sizeof(localref_table));
1005 /* remove current stackframeinfo from chain */
1007 psfi = STACKFRAMEINFO;
1011 /* release JNI local references tables for this thread */
1013 lrt = LOCALREFTABLE;
1015 /* release all current local frames */
1017 for (localframes = lrt->localframes; localframes >= 1; localframes--) {
1018 /* get previous frame */
1022 /* Clear all reference entries (only for tables allocated on
1025 if (localframes > 1)
1026 MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
1030 /* set new local references table */
1035 /* now store the previous local frames in the thread structure */
1037 LOCALREFTABLE = lrt;
1039 /* get the exception and return it */
1041 e = exceptions_get_and_clear_exception();
1047 /* removecompilerstub **********************************************************
1049 Deletes a compilerstub from memory (simply by freeing it).
1051 *******************************************************************************/
1053 void removecompilerstub(u1 *stub)
1055 /* pass size 1 to keep the intern function happy */
1057 CFREE((void *) stub, 1);
1061 /* removenativestub ************************************************************
1063 Removes a previously created native-stub from memory.
1065 *******************************************************************************/
1067 void removenativestub(u1 *stub)
1069 /* pass size 1 to keep the intern function happy */
1071 CFREE((void *) stub, 1);
1075 /* codegen_reg_of_var **********************************************************
1077 This function determines a register, to which the result of an
1078 operation should go, when it is ultimatively intended to store the
1079 result in pseudoregister v. If v is assigned to an actual
1080 register, this register will be returned. Otherwise (when v is
1081 spilled) this function returns tempregnum. If not already done,
1082 regoff and flags are set in the stack location.
1084 On ARM we have to check if a long/double variable is splitted
1085 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1086 register of v for LOW_REG and the tempregnum for HIGH_REG in such
1087 cases. (michi 2005/07/24)
1089 *******************************************************************************/
1091 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
1095 /* Do we have to generate a conditional move? Yes, then always
1096 return the temporary register. The real register is identified
1097 during the store. */
1099 if (opcode & ICMD_CONDITION_MASK)
1103 if (!(v->flags & INMEMORY)) {
1104 #if defined(__ARM__) && defined(__ARMEL__)
1105 if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
1106 return PACK_REGS(GET_LOW_REG(v->vv.regoff),
1107 GET_HIGH_REG(tempregnum));
1109 #if defined(__ARM__) && defined(__ARMEB__)
1110 if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
1111 return PACK_REGS(GET_LOW_REG(tempregnum),
1112 GET_HIGH_REG(v->vv.regoff));
1114 return v->vv.regoff;
1117 #if defined(ENABLE_STATISTICS)
1119 count_spills_read++;
1125 /* codegen_reg_of_dst **********************************************************
1127 This function determines a register, to which the result of an
1128 operation should go, when it is ultimatively intended to store the
1129 result in iptr->dst.var. If dst.var is assigned to an actual
1130 register, this register will be returned. Otherwise (when it is
1131 spilled) this function returns tempregnum. If not already done,
1132 regoff and flags are set in the stack location.
1134 On ARM we have to check if a long/double variable is splitted
1135 across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
1136 register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
1137 cases. (michi 2005/07/24)
1139 *******************************************************************************/
1141 s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
1143 return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
1147 #if defined(ENABLE_THREADS)
1148 void codegen_threadcritrestart(codegendata *cd, int offset)
1150 cd->threadcritcurrent.mcoderestart = offset;
1154 void codegen_threadcritstart(codegendata *cd, int offset)
1156 cd->threadcritcurrent.mcodebegin = offset;
1160 void codegen_threadcritstop(codegendata *cd, int offset)
1162 cd->threadcritcurrent.next = cd->threadcrit;
1163 cd->threadcritcurrent.mcodeend = offset;
1164 cd->threadcrit = DNEW(codegen_critical_section_t);
1165 *(cd->threadcrit) = cd->threadcritcurrent;
1166 cd->threadcritcount++;
1172 * These are local overrides for various environment variables in Emacs.
1173 * Please do not remove this and leave it at the end of the file, where
1174 * Emacs will automagically detect them.
1175 * ---------------------------------------------------------------------
1178 * indent-tabs-mode: t
1182 * vim:noexpandtab:sw=4:ts=4: