1 /* src/vm/jit/powerpc64/emit.c - PowerPC64 code emitter functions
3 Copyright (C) 1996-2005, 2006, 2007 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
34 #include "mm/memory.h"
37 #include "vm/jit/powerpc64/codegen.h"
39 #include "threads/lock-common.h"
41 #include "vm/exceptions.h"
44 #include "vm/jit/abi.h"
45 #include "vm/jit/asmpart.h"
46 #include "vm/jit/emit-common.h"
47 #include "vm/jit/jit.h"
48 #include "vm/jit/trace.h"
50 #include "vmcore/options.h"
53 /* emit_load *******************************************************************
55 Emits a possible load of an operand.
57 *******************************************************************************/
59 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
65 /* get required compiler data */
69 if (src->flags & INMEMORY) {
72 disp = src->vv.regoff;
74 if (IS_FLT_DBL_TYPE(src->type)) {
75 M_DLD(tempreg, REG_SP, disp);
78 M_LLD(tempreg, REG_SP, disp);
90 /* emit_store ******************************************************************
92 Emits a possible store to a variable.
94 *******************************************************************************/
96 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
100 /* get required compiler data */
104 if (dst->flags & INMEMORY) {
107 if (IS_FLT_DBL_TYPE(dst->type)) {
108 M_DST(d, REG_SP, dst->vv.regoff);
111 M_LST(d, REG_SP, dst->vv.regoff);
117 /* emit_copy *******************************************************************
119 Generates a register/memory to register/memory copy.
121 *******************************************************************************/
123 void emit_copy(jitdata *jd, instruction *iptr)
130 /* get required compiler data */
134 /* get source and destination variables */
136 src = VAROP(iptr->s1);
137 dst = VAROP(iptr->dst);
139 if ((src->vv.regoff != dst->vv.regoff) ||
140 ((src->flags ^ dst->flags) & INMEMORY)) {
142 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
143 /* emit nothing, as the value won't be used anyway */
147 /* If one of the variables resides in memory, we can eliminate
148 the register move from/to the temporary register with the
149 order of getting the destination register and the load. */
151 if (IS_INMEMORY(src->flags)) {
152 d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
153 s1 = emit_load(jd, iptr, src, d);
156 s1 = emit_load(jd, iptr, src, REG_IFTMP);
157 d = codegen_reg_of_var(iptr->opc, dst, s1);
161 if (IS_FLT_DBL_TYPE(src->type))
167 emit_store(jd, iptr, dst, d);
172 /* emit_iconst *****************************************************************
176 *******************************************************************************/
178 void emit_iconst(codegendata *cd, s4 d, s4 value)
182 if ((value >= -32768) && (value <= 32767)) {
183 M_LDA_INTERN(d, REG_ZERO, value);
185 disp = dseg_add_s4(cd, value);
186 M_ILD(d, REG_PV, disp);
190 void emit_lconst(codegendata *cd, s4 d, s8 value)
193 if ((value >= -32768) && (value <= 32767)) {
194 M_LDA_INTERN(d, REG_ZERO, value);
196 disp = dseg_add_s8(cd, value);
197 M_LLD(d, REG_PV, disp);
202 /* emit_verbosecall_enter ******************************************************
204 Generates the code for the call trace.
206 *******************************************************************************/
209 void emit_verbosecall_enter(jitdata *jd)
215 int32_t stackframesize;
219 /* get required compiler data */
226 /* mark trace code */
230 /* align stack to 16-bytes */
232 paramcount = md->paramcount;
234 stackframesize = LA_SIZE + PA_SIZE + md->paramcount * 8;
237 M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
238 M_STDU(REG_SP, REG_SP, -stackframesize);
240 #if defined(__DARWIN__)
241 #warning "emit_verbosecall_enter not implemented"
243 /* save argument registers */
245 for (i = 0; i < md->paramcount; i++) {
246 if (!md->params[i].inmemory) {
247 s = md->params[i].regoff;
249 switch (md->paramtypes[i].type) {
253 M_LST(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
257 M_DST(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
264 disp = dseg_add_address(cd, m);
265 M_ALD(REG_A0, REG_PV, disp);
266 M_AADD_IMM(REG_SP, LA_SIZE+PA_SIZE, REG_A1);
267 M_AADD_IMM(REG_SP, stackframesize + cd->stackframesize * 8, REG_A2);
268 /* call via function descriptor, XXX: what about TOC? */
269 disp = dseg_add_functionptr(cd, trace_java_call_enter);
270 M_ALD(REG_ITMP2, REG_PV, disp);
271 M_ALD(REG_ITMP1, REG_ITMP2, 0);
275 #if defined(__DARWIN__)
276 #warning "emit_verbosecall_enter not implemented"
278 /* restore argument registers */
280 for (i = 0; i < md->paramcount; i++) {
281 if (!md->params[i].inmemory) {
282 s = md->params[i].regoff;
284 switch (md->paramtypes[i].type) {
288 M_LLD(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
292 M_DLD(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
299 M_ALD(REG_ZERO, REG_SP, stackframesize + LA_LR_OFFSET);
301 M_LDA(REG_SP, REG_SP, stackframesize);
303 /* mark trace code */
310 /* emit_verbosecall_exit ******************************************************
312 Generates the code for the call trace.
314 *******************************************************************************/
317 void emit_verbosecall_exit(jitdata *jd)
324 /* get required compiler data */
331 /* mark trace code */
336 M_LDA(REG_SP, REG_SP, -(LA_SIZE+PA_SIZE+10*8));
337 M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+1*8);
339 /* save return value */
341 switch (md->returntype.type) {
345 M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
349 M_DST(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
353 disp = dseg_add_address(cd, m);
354 M_ALD(REG_A0, REG_PV, disp);
355 M_AADD_IMM(REG_SP, LA_SIZE+PA_SIZE, REG_A1);
357 disp = dseg_add_functionptr(cd, trace_java_call_exit);
358 /* call via function descriptor, XXX: what about TOC ? */
359 M_ALD(REG_ITMP2, REG_PV, disp);
360 M_ALD(REG_ITMP2, REG_ITMP2, 0);
364 /* restore return value */
366 switch (md->returntype.type) {
370 M_LLD(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
374 M_DLD(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
378 M_ALD(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+1*8);
379 M_LDA(REG_SP, REG_SP, LA_SIZE+PA_SIZE+10*8);
382 /* mark trace code */
389 /* emit_branch *****************************************************************
391 Emits the code for conditional and unconditional branchs.
393 *******************************************************************************/
395 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
400 /* calculate the different displacements */
402 checkdisp = disp + 4;
403 branchdisp = (disp - 4) >> 2;
405 /* check which branch to generate */
407 if (condition == BRANCH_UNCONDITIONAL) {
408 /* check displacement for overflow */
410 if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
411 /* if the long-branches flag isn't set yet, do it */
413 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
414 cd->flags |= (CODEGENDATA_FLAG_ERROR |
415 CODEGENDATA_FLAG_LONGBRANCHES);
418 vm_abort("emit_branch: emit unconditional long-branch code");
425 /* and displacement for overflow */
427 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
428 /* if the long-branches flag isn't set yet, do it */
430 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
431 cd->flags |= (CODEGENDATA_FLAG_ERROR |
432 CODEGENDATA_FLAG_LONGBRANCHES);
435 branchdisp --; /* we jump from the second instruction */
462 vm_abort("emit_branch: long BRANCH_NAN");
465 vm_abort("emit_branch: unknown condition %d", condition);
493 vm_abort("emit_branch: unknown condition %d", condition);
499 /* emit_arrayindexoutofbounds_check ********************************************
501 Emit a ArrayIndexOutOfBoundsException check.
503 *******************************************************************************/
505 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
510 M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
511 M_CMPU(s2, REG_ITMP3);
512 codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
515 M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
516 M_CMPU(s2, REG_ITMP3);
518 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
519 M_LWZ(s2, REG_ZERO, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
525 /* emit_arraystore_check *******************************************************
527 Emit an ArrayStoreException check.
529 *******************************************************************************/
531 void emit_arraystore_check(codegendata *cd, instruction *iptr)
533 if (INSTRUCTION_MUST_CHECK(iptr)) {
536 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
537 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARRAYSTORE);
542 /* emit_arithmetic_check *******************************************************
544 Emit an ArithmeticException check.
546 *******************************************************************************/
548 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
550 if (INSTRUCTION_MUST_CHECK(iptr)) {
553 codegen_add_arithmeticexception_ref(cd);
558 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
559 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
565 /* emit_arraystore_check *******************************************************
567 Emit an ArrayStoreException check.
569 *******************************************************************************/
571 void emit_arraystore_check(codegendata *cd, instruction *iptr, s4 reg)
573 if (INSTRUCTION_MUST_CHECK(iptr)) {
575 codegen_add_arraystoreexception_ref(cd);
581 /* emit_classcast_check ********************************************************
583 Emit a ClassCastException check.
585 *******************************************************************************/
587 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
589 if (INSTRUCTION_MUST_CHECK(iptr)) {
591 codegen_add_classcastexception_ref(cd, condition, s1);
606 vm_abort("emit_classcast_check: unknown condition %d", condition);
608 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
609 M_LWZ(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
615 /* emit_nullpointer_check ******************************************************
617 Emit a NullPointerException check.
619 *******************************************************************************/
621 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
623 if (INSTRUCTION_MUST_CHECK(iptr)) {
626 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
627 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
631 /* emit_exception_check ********************************************************
633 Emit an Exception check.
635 *******************************************************************************/
637 void emit_exception_check(codegendata *cd, instruction *iptr)
639 if (INSTRUCTION_MUST_CHECK(iptr)) {
641 M_CMPI(REG_RESULT, 0);
642 codegen_add_fillinstacktrace_ref(cd);
647 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
648 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
654 /* emit_trap_compiler **********************************************************
656 Emit a trap instruction which calls the JIT compiler.
658 *******************************************************************************/
660 void emit_trap_compiler(codegendata *cd)
662 M_LWZ(REG_METHODPTR, REG_ZERO, EXCEPTION_HARDWARE_COMPILER);
666 /* emit_trap *******************************************************************
668 Emit a trap instruction and return the original machine code.
670 *******************************************************************************/
672 uint32_t emit_trap(codegendata *cd)
676 /* Get machine code which is patched back in later. The
677 trap is 1 instruction word long. */
679 mcode = *((uint32_t *) cd->mcodeptr);
681 /* ALD is 4 byte aligned, ILD 2, only LWZ is byte aligned */
682 M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_PATCHER);
689 * These are local overrides for various environment variables in Emacs.
690 * Please do not remove this and leave it at the end of the file, where
691 * Emacs will automagically detect them.
692 * ---------------------------------------------------------------------
695 * indent-tabs-mode: t
699 * vim:noexpandtab:sw=4:ts=4: