1 /* src/vm/jit/powerpc64/emit.c - PowerPC64 code emitter functions
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 #include "mm/memory.h"
35 #include "vm/jit/powerpc64/codegen.h"
37 #include "threads/lock-common.h"
39 #include "vm/exceptions.h"
42 #include "vm/jit/abi.h"
43 #include "vm/jit/asmpart.h"
44 #include "vm/jit/emit-common.h"
45 #include "vm/jit/jit.h"
46 #include "vm/jit/trace.h"
47 #include "vm/jit/trap.h"
49 #include "vmcore/options.h"
52 /* emit_load *******************************************************************
54 Emits a possible load of an operand.
56 *******************************************************************************/
58 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
64 /* get required compiler data */
68 if (src->flags & INMEMORY) {
71 disp = src->vv.regoff;
73 if (IS_FLT_DBL_TYPE(src->type)) {
74 M_DLD(tempreg, REG_SP, disp);
77 M_LLD(tempreg, REG_SP, disp);
89 /* emit_store ******************************************************************
91 Emits a possible store to a variable.
93 *******************************************************************************/
95 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
99 /* get required compiler data */
103 if (dst->flags & INMEMORY) {
106 if (IS_FLT_DBL_TYPE(dst->type)) {
107 M_DST(d, REG_SP, dst->vv.regoff);
110 M_LST(d, REG_SP, dst->vv.regoff);
116 /* emit_copy *******************************************************************
118 Generates a register/memory to register/memory copy.
120 *******************************************************************************/
122 void emit_copy(jitdata *jd, instruction *iptr)
129 /* get required compiler data */
133 /* get source and destination variables */
135 src = VAROP(iptr->s1);
136 dst = VAROP(iptr->dst);
138 if ((src->vv.regoff != dst->vv.regoff) ||
139 ((src->flags ^ dst->flags) & INMEMORY)) {
141 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
142 /* emit nothing, as the value won't be used anyway */
146 /* If one of the variables resides in memory, we can eliminate
147 the register move from/to the temporary register with the
148 order of getting the destination register and the load. */
150 if (IS_INMEMORY(src->flags)) {
151 d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
152 s1 = emit_load(jd, iptr, src, d);
155 s1 = emit_load(jd, iptr, src, REG_IFTMP);
156 d = codegen_reg_of_var(iptr->opc, dst, s1);
160 if (IS_FLT_DBL_TYPE(src->type))
166 emit_store(jd, iptr, dst, d);
171 /* emit_iconst *****************************************************************
175 *******************************************************************************/
177 void emit_iconst(codegendata *cd, s4 d, s4 value)
181 if ((value >= -32768) && (value <= 32767)) {
182 M_LDA_INTERN(d, REG_ZERO, value);
184 disp = dseg_add_s4(cd, value);
185 M_ILD(d, REG_PV, disp);
189 void emit_lconst(codegendata *cd, s4 d, s8 value)
192 if ((value >= -32768) && (value <= 32767)) {
193 M_LDA_INTERN(d, REG_ZERO, value);
195 disp = dseg_add_s8(cd, value);
196 M_LLD(d, REG_PV, disp);
201 /* emit_verbosecall_enter ******************************************************
203 Generates the code for the call trace.
205 *******************************************************************************/
208 void emit_verbosecall_enter(jitdata *jd)
214 int32_t stackframesize;
218 /* get required compiler data */
225 /* mark trace code */
229 /* align stack to 16-bytes */
231 paramcount = md->paramcount;
233 stackframesize = LA_SIZE + PA_SIZE + md->paramcount * 8;
236 M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
237 M_STDU(REG_SP, REG_SP, -stackframesize);
239 #if defined(__DARWIN__)
240 #warning "emit_verbosecall_enter not implemented"
242 /* save argument registers */
244 for (i = 0; i < md->paramcount; i++) {
245 if (!md->params[i].inmemory) {
246 s = md->params[i].regoff;
248 switch (md->paramtypes[i].type) {
252 M_LST(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
256 M_DST(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
263 disp = dseg_add_address(cd, m);
264 M_ALD(REG_A0, REG_PV, disp);
265 M_AADD_IMM(REG_SP, LA_SIZE+PA_SIZE, REG_A1);
266 M_AADD_IMM(REG_SP, stackframesize + cd->stackframesize * 8, REG_A2);
267 /* call via function descriptor, XXX: what about TOC? */
268 disp = dseg_add_functionptr(cd, trace_java_call_enter);
269 M_ALD(REG_ITMP2, REG_PV, disp);
270 M_ALD(REG_ITMP1, REG_ITMP2, 0);
274 #if defined(__DARWIN__)
275 #warning "emit_verbosecall_enter not implemented"
277 /* restore argument registers */
279 for (i = 0; i < md->paramcount; i++) {
280 if (!md->params[i].inmemory) {
281 s = md->params[i].regoff;
283 switch (md->paramtypes[i].type) {
287 M_LLD(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
291 M_DLD(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
298 M_ALD(REG_ZERO, REG_SP, stackframesize + LA_LR_OFFSET);
300 M_LDA(REG_SP, REG_SP, stackframesize);
302 /* mark trace code */
309 /* emit_verbosecall_exit ******************************************************
311 Generates the code for the call trace.
313 *******************************************************************************/
316 void emit_verbosecall_exit(jitdata *jd)
323 /* get required compiler data */
330 /* mark trace code */
335 M_LDA(REG_SP, REG_SP, -(LA_SIZE+PA_SIZE+10*8));
336 M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+1*8);
338 /* save return value */
340 switch (md->returntype.type) {
344 M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
348 M_DST(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
352 disp = dseg_add_address(cd, m);
353 M_ALD(REG_A0, REG_PV, disp);
354 M_AADD_IMM(REG_SP, LA_SIZE+PA_SIZE, REG_A1);
356 disp = dseg_add_functionptr(cd, trace_java_call_exit);
357 /* call via function descriptor, XXX: what about TOC ? */
358 M_ALD(REG_ITMP2, REG_PV, disp);
359 M_ALD(REG_ITMP2, REG_ITMP2, 0);
363 /* restore return value */
365 switch (md->returntype.type) {
369 M_LLD(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
373 M_DLD(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
377 M_ALD(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+1*8);
378 M_LDA(REG_SP, REG_SP, LA_SIZE+PA_SIZE+10*8);
381 /* mark trace code */
388 /* emit_branch *****************************************************************
390 Emits the code for conditional and unconditional branchs.
392 *******************************************************************************/
394 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
399 /* calculate the different displacements */
401 checkdisp = disp + 4;
402 branchdisp = (disp - 4) >> 2;
404 /* check which branch to generate */
406 if (condition == BRANCH_UNCONDITIONAL) {
407 /* check displacement for overflow */
409 if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
410 /* if the long-branches flag isn't set yet, do it */
412 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
413 cd->flags |= (CODEGENDATA_FLAG_ERROR |
414 CODEGENDATA_FLAG_LONGBRANCHES);
417 vm_abort("emit_branch: emit unconditional long-branch code");
424 /* and displacement for overflow */
426 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
427 /* if the long-branches flag isn't set yet, do it */
429 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
430 cd->flags |= (CODEGENDATA_FLAG_ERROR |
431 CODEGENDATA_FLAG_LONGBRANCHES);
434 branchdisp --; /* we jump from the second instruction */
461 vm_abort("emit_branch: long BRANCH_NAN");
464 vm_abort("emit_branch: unknown condition %d", condition);
492 vm_abort("emit_branch: unknown condition %d", condition);
498 /* emit_arrayindexoutofbounds_check ********************************************
500 Emit a ArrayIndexOutOfBoundsException check.
502 *******************************************************************************/
504 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
507 M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
508 M_CMPU(s2, REG_ITMP3);
510 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
511 M_LWZ(s2, REG_ZERO, TRAP_ArrayIndexOutOfBoundsException);
516 /* emit_arraystore_check *******************************************************
518 Emit an ArrayStoreException check.
520 *******************************************************************************/
522 void emit_arraystore_check(codegendata *cd, instruction *iptr)
524 if (INSTRUCTION_MUST_CHECK(iptr)) {
527 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
528 M_LWZ(REG_ZERO, REG_ZERO, TRAP_ArrayStoreException);
533 /* emit_arithmetic_check *******************************************************
535 Emit an ArithmeticException check.
537 *******************************************************************************/
539 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
541 if (INSTRUCTION_MUST_CHECK(iptr)) {
544 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
545 M_LWZ(REG_ZERO, REG_ZERO, TRAP_ArithmeticException);
550 /* emit_classcast_check ********************************************************
552 Emit a ClassCastException check.
554 *******************************************************************************/
556 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
558 if (INSTRUCTION_MUST_CHECK(iptr)) {
570 vm_abort("emit_classcast_check: unknown condition %d", condition);
573 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
574 M_LWZ(s1, REG_ZERO, TRAP_ClassCastException);
579 /* emit_nullpointer_check ******************************************************
581 Emit a NullPointerException check.
583 *******************************************************************************/
585 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
587 if (INSTRUCTION_MUST_CHECK(iptr)) {
590 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
591 M_LWZ(REG_ZERO, REG_ZERO, TRAP_NullPointerException);
595 /* emit_exception_check ********************************************************
597 Emit an Exception check.
599 *******************************************************************************/
601 void emit_exception_check(codegendata *cd, instruction *iptr)
603 if (INSTRUCTION_MUST_CHECK(iptr)) {
606 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
607 M_LWZ(REG_ZERO, REG_ZERO, TRAP_CHECK_EXCEPTION);
612 /* emit_trap_compiler **********************************************************
614 Emit a trap instruction which calls the JIT compiler.
616 *******************************************************************************/
618 void emit_trap_compiler(codegendata *cd)
620 M_LWZ(REG_METHODPTR, REG_ZERO, TRAP_COMPILER);
624 /* emit_trap *******************************************************************
626 Emit a trap instruction and return the original machine code.
628 *******************************************************************************/
630 uint32_t emit_trap(codegendata *cd)
634 /* Get machine code which is patched back in later. The
635 trap is 1 instruction word long. */
637 mcode = *((uint32_t *) cd->mcodeptr);
639 /* ALD is 4 byte aligned, ILD 2, only LWZ is byte aligned */
640 M_LWZ(REG_ZERO, REG_ZERO, TRAP_PATCHER);
647 * These are local overrides for various environment variables in Emacs.
648 * Please do not remove this and leave it at the end of the file, where
649 * Emacs will automagically detect them.
650 * ---------------------------------------------------------------------
653 * indent-tabs-mode: t
657 * vim:noexpandtab:sw=4:ts=4: