From: pm Date: Tue, 16 Jan 2007 22:18:57 +0000 (+0000) Subject: Initial import of s390 codegen, codebase is copyed from x86_64. X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=48a98d167eb6b2bb826a0317b9924fbdc8303062;p=cacao.git Initial import of s390 codegen, codebase is copyed from x86_64. --HG-- rename : src/vm/jit/x86_64/.cvsignore => src/vm/jit/s390/.cvsignore rename : src/vm/jit/x86_64/Makefile.am => src/vm/jit/s390/Makefile.am rename : src/vm/jit/x86_64/arch.h => src/vm/jit/s390/arch.h rename : src/vm/jit/x86_64/asmpart.S => src/vm/jit/s390/asmpart.S rename : src/vm/jit/x86_64/codegen.c => src/vm/jit/s390/codegen.c rename : src/vm/jit/x86_64/codegen.h => src/vm/jit/s390/codegen.h rename : src/vm/jit/x86_64/disass.c => src/vm/jit/s390/disass.c rename : src/vm/jit/x86_64/emit.c => src/vm/jit/s390/emit.c rename : src/vm/jit/x86_64/emit.h => src/vm/jit/s390/emit.h rename : src/vm/jit/x86_64/machine-instr.h => src/vm/jit/s390/machine-instr.h rename : src/vm/jit/x86_64/md-abi.c => src/vm/jit/s390/md-abi.c rename : src/vm/jit/x86_64/md-abi.h => src/vm/jit/s390/md-abi.h rename : src/vm/jit/x86_64/md-asm.h => src/vm/jit/s390/md-asm.h rename : src/vm/jit/x86_64/md.c => src/vm/jit/s390/md.c rename : src/vm/jit/x86_64/patcher.c => src/vm/jit/s390/patcher.c --- diff --git a/configure.ac b/configure.ac index 3d5348993..6de3d7a35 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA dnl 02110-1301, USA. dnl -dnl $Id: configure.ac 6595 2007-01-11 14:19:48Z twisti $ +dnl $Id: configure.ac 7219 2007-01-16 22:18:57Z pm $ dnl Process this file with autoconf to produce a configure script. @@ -105,6 +105,12 @@ xdspcore ) USE_SCHEDULER="1" ;; +s390 ) + ARCH_DIR="s390" + ARCH_CFLAGS="-D__S390__" + ;; + + * ) AC_MSG_ERROR($host_cpu systems are not supported at this time) ;; @@ -475,7 +481,7 @@ if test x"${ENABLE_DISASSEMBLER}" = "xyes"; then dnl check for binutils headers and libraries on some architectures for the dnl disassembler case "${ARCH_DIR}" in - arm | i386 | powerpc | x86_64 | sparc64 | powerpc64) + arm | i386 | powerpc | x86_64 | sparc64 | powerpc64 | s390) AC_CHECK_HEADER([ansidecl.h],, [AC_MSG_ERROR(cannot find ansidecl.h)]) AC_CHECK_HEADER([symcat.h],, [AC_MSG_ERROR(cannot find symcat.h)]) AC_CHECK_HEADER([bfd.h],, [AC_MSG_ERROR(cannot find bfd.h)]) @@ -1059,6 +1065,7 @@ AC_CONFIG_FILES([Makefile] [src/vm/jit/tools/Makefile] [src/vm/jit/verify/Makefile] [src/vm/jit/x86_64/Makefile] + [src/vm/jit/s390/Makefile] [tests/Makefile] [tests/regression/Makefile] [tests/regression/codepatching/Makefile] diff --git a/src/vm/jit/Makefile.am b/src/vm/jit/Makefile.am index 0dfa665f9..9cfb3b0a6 100644 --- a/src/vm/jit/Makefile.am +++ b/src/vm/jit/Makefile.am @@ -28,7 +28,7 @@ ## ## Changes: Edwin Steiner ## -## $Id: Makefile.am 6595 2007-01-11 14:19:48Z twisti $ +## $Id: Makefile.am 7219 2007-01-16 22:18:57Z pm $ ## Process this file with automake to produce Makefile.in @@ -54,7 +54,8 @@ DIST_SUBDIRS = \ powerpc \ powerpc64 \ sparc64 \ - x86_64 + x86_64 \ + s390 SUBDIRS = \ optimizing \ diff --git a/src/vm/jit/disass-common.c b/src/vm/jit/disass-common.c index 78e74f50c..e87c704a8 100644 --- a/src/vm/jit/disass-common.c +++ b/src/vm/jit/disass-common.c @@ -28,7 +28,7 @@ Changes: - $Id: disass-common.c 4844 2006-04-25 18:02:15Z edwin $ + $Id: disass-common.c 7219 2007-01-16 22:18:57Z pm $ */ @@ -59,7 +59,7 @@ bool disass_initialized = false; /* We need this on i386 and x86_64 since we don't know the byte length of currently printed instructions. 512 bytes should be enough. */ -#if defined(__I386__) || defined(__X86_64__) +#if defined(__I386__) || defined(__X86_64__) || defined(__S390__) char disass_buf[512]; s4 disass_len; #endif @@ -99,7 +99,7 @@ void disass_printf(PTR p, const char *fmt, ...) va_start(ap, fmt); -#if defined(__I386__) || defined(__X86_64__) +#if defined(__I386__) || defined(__X86_64__) || defined(__S390__) disass_len += vsprintf(disass_buf + disass_len, fmt, ap); #else vprintf(fmt, ap); diff --git a/src/vm/jit/disass.h b/src/vm/jit/disass.h index 269e834a5..f5192658a 100644 --- a/src/vm/jit/disass.h +++ b/src/vm/jit/disass.h @@ -28,7 +28,7 @@ Changes: - $Id: disass.h 4709 2006-03-30 10:14:22Z twisti $ + $Id: disass.h 7219 2007-01-16 22:18:57Z pm $ */ @@ -96,7 +96,7 @@ extern bool disass_initialized; extern char *regs[]; -#if defined(__I386__) || defined(__X86_64__) +#if defined(__I386__) || defined(__X86_64__) || defined(__S390__) extern char disass_buf[512]; extern s4 disass_len; #endif diff --git a/src/vm/jit/s390/.cvsignore b/src/vm/jit/s390/.cvsignore new file mode 100644 index 000000000..1f83cf9ad --- /dev/null +++ b/src/vm/jit/s390/.cvsignore @@ -0,0 +1,10 @@ +*.a +*.o +*.la +*.lo +.deps +.libs +Makefile +Makefile.in +TAGS +offsets.h diff --git a/src/vm/jit/s390/Makefile.am b/src/vm/jit/s390/Makefile.am new file mode 100644 index 000000000..1bac4da27 --- /dev/null +++ b/src/vm/jit/s390/Makefile.am @@ -0,0 +1,82 @@ +## src/vm/jit/x86_64/Makefile.am +## +## Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, +## C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, +## E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, +## J. Wenninger, Institut f. Computersprachen - TU Wien +## +## This file is part of CACAO. +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License as +## published by the Free Software Foundation; either version 2, or (at +## your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +## 02110-1301, USA. +## +## Contact: cacao@cacaojvm.org +## +## Authors: Christian Thalinger +## +## Changes: +## +## $Id: Makefile.am 5830 2006-10-26 11:04:31Z twisti $ + +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir) -I$(top_builddir)/src +AM_CCASFLAGS = $(AM_CPPFLAGS) $(AM_LDFLAGS) + +LIBS = + +BUILT_SOURCES = offsets.h + +CLEANFILES = offsets.h + +noinst_HEADERS = \ + arch.h \ + machine-instr.h \ + \ + md-asm.h + +noinst_LTLIBRARIES = libarch.la + +if ENABLE_DISASSEMBLER +DISASS_SOURCES = \ + disass.c +endif + +libarch_la_SOURCES = \ + asmpart.S \ + codegen.c \ + codegen.h \ + $(DISASS_SOURCES) \ + emit.c \ + emit.h \ + patcher.c \ + \ + md-abi.c \ + md-abi.h \ + md.c + +$(srcdir)/asmpart.S: $(top_builddir)/config.h offsets.h + +offsets.h: $(top_builddir)/src/vm/jit/tools/genoffsets $(top_builddir)/config.h + $(top_builddir)/src/vm/jit/tools/genoffsets > offsets.h + + +## Local variables: +## mode: Makefile +## indent-tabs-mode: t +## c-basic-offset: 4 +## tab-width: 8 +## compile-command: "automake --add-missing" +## End: diff --git a/src/vm/jit/s390/arch.h b/src/vm/jit/s390/arch.h new file mode 100644 index 000000000..dfdaa9ad6 --- /dev/null +++ b/src/vm/jit/s390/arch.h @@ -0,0 +1,97 @@ +/* src/vm/jit/x86_64/arch.h - architecture defines for x86_64 + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + + Changes: + + $Id: arch.h 7219 2007-01-16 22:18:57Z pm $ + +*/ + + +#ifndef _ARCH_H +#define _ARCH_H + +/* define architecture features ***********************************************/ + +#define U8_AVAILABLE 1 + +/* #define USEBUILTINTABLE */ + +#define SUPPORT_DIVISION 1 +#define SUPPORT_LONG 1 +#define SUPPORT_FLOAT 1 +#define SUPPORT_DOUBLE 1 + +#define SUPPORT_I2F 1 +#define SUPPORT_I2D 1 +#define SUPPORT_L2F 1 +#define SUPPORT_L2D 1 + +/* ATTENTION: x86_64 architectures support these conversions, but we + need the builtin functions in corner cases */ +#define SUPPORT_F2I 0 +#define SUPPORT_F2L 0 +#define SUPPORT_D2I 0 +#define SUPPORT_D2L 0 + +#define SUPPORT_LONG_ADD 1 +#define SUPPORT_LONG_CMP 1 +#define SUPPORT_LONG_CMP_CONST 1 +#define SUPPORT_LONG_LOGICAL 1 +#define SUPPORT_LONG_SHIFT 1 +#define SUPPORT_LONG_MUL 1 +#define SUPPORT_LONG_DIV 1 + +#define SUPPORT_LONG_DIV_POW2 1 +#define SUPPORT_LONG_REM_POW2 1 + +#define SUPPORT_CONST_LOGICAL 1 /* AND, OR, XOR with immediates */ +#define SUPPORT_CONST_MUL 1 /* mutiply with immediate */ + +#define SUPPORT_CONST_STORE 1 /* do we support const stores */ +#define SUPPORT_CONST_STORE_ZERO_ONLY 0 /* on some risc machines we can */ + /* only store REG_ZERO */ + +#define CONSECUTIVE_INTEGER_ARGS +#define CONSECUTIVE_FLOAT_ARGS + +#endif /* _ARCH_H */ + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/vm/jit/s390/asmpart.S b/src/vm/jit/s390/asmpart.S new file mode 100644 index 000000000..05585a378 --- /dev/null +++ b/src/vm/jit/s390/asmpart.S @@ -0,0 +1,1252 @@ +/* src/vm/jit/x86_64/asmpart.S - Java-C interface functions for x86_64 + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Andreas Krall + Reinhard Grafl + Christian Thalinger + + Changes: Edwin Steiner + + $Id: asmpart.S 7219 2007-01-16 22:18:57Z pm $ + +*/ + + +#include "config.h" + +#include "vm/jit/s390/arch.h" +#include "vm/jit/s390/md-abi.h" +#include "vm/jit/s390/md-asm.h" +#include "vm/jit/s390/offsets.h" + +#include "vm/jit/abi-asm.h" +#include "vm/jit/methodheader.h" + +/* Copy a call to a PIC function from gcc -S + * We setup a temporary literal pool pointer. + */ + +#define PIC_CALL(fun, magic) \ + bras itmp3, L_##magic##_lp_end ; \ +L_##magic##_lp: ; \ +L_##magic##_lp_5: ; \ + .long fun@PLTOFF ; \ +L_##magic##_lp_4: ; \ + .long _GLOBAL_OFFSET_TABLE_-L_##magic##_lp ; \ +L_##magic##_lp_end: ; \ + l itmp2,L_##magic##_lp_4-L_##magic##_lp(itmp3) ; \ + la itmp2,0(itmp2,itmp3) ; \ + l itmp1,L_##magic##_lp_5-L_##magic##_lp(itmp3) ; \ + bas %r14,0(itmp1,itmp2) + + .text + + +/* export functions ***********************************************************/ + + .globl asm_vm_call_method + .globl asm_vm_call_method_int + .globl asm_vm_call_method_long + .globl asm_vm_call_method_float + .globl asm_vm_call_method_double + .globl asm_vm_call_method_exception_handler + + .globl asm_call_jit_compiler + + .globl asm_handle_exception + .globl asm_handle_nat_exception + + .globl asm_abstractmethoderror + + .globl asm_patcher_wrapper + + .globl asm_replacement_out + .globl asm_replacement_in + + .globl asm_builtin_f2i + .globl asm_builtin_f2l + .globl asm_builtin_d2i + .globl asm_builtin_d2l + + .globl asm_criticalsections + .globl asm_getclassvalues_atomic + + +#if 0 +asm_vm_call_method: +asm_vm_call_method_int: +asm_vm_call_method_long: +asm_vm_call_method_float: +asm_vm_call_method_double: +#endif +asm_vm_call_method_exception_handler: +#if 0 +asm_call_jit_compiler: +#endif +asm_handle_exception: +asm_handle_nat_exception: +asm_abstractmethoderror: +asm_patcher_wrapper: +asm_replacement_out: +asm_replacement_in: +asm_builtin_f2i: +asm_builtin_f2l: +asm_builtin_d2i: +asm_builtin_d2l: +asm_criticalsections: +asm_getclassvalues_atomic: + .long 0 + +/********************* function asm_calljavafunction *************************** +* * +* This function calls a Java-method (which possibly needs compilation) * +* with up to 4 address parameters. * +* * +* This functions calls the JIT-compiler which eventually translates the * +* method into machine code. * +* * +* C-prototype: * +* javaobject_header *asm_calljavamethod (methodinfo *m, * +* void *arg1, void *arg2, void *arg3, void *arg4); * +* * +*******************************************************************************/ + .align 8 + + .quad 0 /* catch type all */ + .quad 0 /* handler pc */ + .quad 0 /* end pc */ + .quad 0 /* start pc */ + .long 1 /* extable size */ + .long 0 /* ALIGNMENT PADDING */ + .quad 0 /* line number table start */ + .quad 0 /* line number table size */ + .long 0 /* ALIGNMENT PADDING */ + .long 0 /* fltsave */ + .long 0 /* intsave */ + .long 0 /* isleaf */ + .long 0 /* IsSync */ + .long 0 /* frame size */ + .quad 0 /* codeinfo pointer */ + + +asm_vm_call_method: +asm_vm_call_method_int: +asm_vm_call_method_long: +asm_vm_call_method_float: +asm_vm_call_method_double: + +/* + +a0: methodinfo *m +a1: s4 vmargscount ---> v0: java_objectheader * +a2: vm_arg *vmargs +r14: return address + +96 ... on stack parameters (none) +0 - 96 register save area +-------------------------------------------------- <- SP on asm_vm_... entry + arguments on stack +---------------------------------------------------- <- SP on JIT code entry + saved return address (callee saved) + +*/ + + +/* + Regiser usage: + itmp1: argument block pointer + itmp2: argument counter + s0: integer argument counter + s1: float argument counter + s2: integer register counter + s3: backup argument block pointer + s4: backup argument count +*/ + + stm %r6, %r15, 24(sp) /* save callers regiters */ + ahi sp, -16 /* allocate stack space for local variables */ + stm a0, a2, 0(sp) /* save arguments */ + + ltr a1, a1 /* maybe we have no args... */ + je L_no_args + + lr itmp2, a1 /* load arg count */ + lr itmp1, a2 /* load arg pointer */ + + ahi itmp1, -sizevmarg /* initialize arg pointer */ + ahi itmp2, 1 /* initialize arg count */ + lhi s0, 0 /* initialize integer arg counter */ + lhi s2, 0 /* initialize integer register counter */ + lhi s1, 0 /* initialize float arg counter */ + + lr s4, a1 /* backup arg count */ + lr s3, a2 /* backup arg pointer */ + +L_register_copy: + + ahi itmp1, sizevmarg /* forward arg pointer */ + ahi itmp2, -1 /* decrement arg count */ + je L_register_copy_done /* no arguments left */ + + tm offvmargtype(itmp1), 0x02 /* is this a float/double type? */ + jne L_register_handle_float + +L_register_handle_int: + + chi s2, INT_ARG_CNT /* are we out of integer arg registers ? */ + je L_register_copy /* yes, next loop */ + + tm offvmargtype(itmp1), 0x01 /* is this a 2 word type ? */ + jne L_register_handle_long + + ahi s0, 1 /* increment integer arg counter */ + ahi s2, 1 /* increment integer register counter */ + + /* handle argument */ + + chi s2, 1 + je L_handle_i0 + chi s2, 2 + je L_handle_i1 + chi s2, 3 + je L_handle_i2 + chi s2, 4 + je L_handle_i3 + chi s2, 5 + je L_handle_i4 + +L_register_handle_long: + + chi s2, (INT_ARG_CNT - 1) /* are there 2 integer arg registers left ? */ + jl L_register_handle_long_continue /* yes */ + lhi s2, INT_ARG_CNT /* no, drop last register */ + j L_register_copy + +L_register_handle_long_continue: + + ahi s0, 1 /* increment integer arg counter */ + ahi s2, 2 /* consume 2 integer arg registers */ + + /* handle argument */ + + chi s2, 1 + je L_handle_l0 + chi s2, 2 + je L_handle_l1 + chi s2, 3 + je L_handle_l2 + chi s2, 4 + je L_handle_l3 + +L_register_handle_float: + + chi s1, FLT_ARG_CNT /* are we out of float arg registers */ + je L_register_copy /* no arg regisers left */ + + ahi s1, 1 /* increment float argument counter */ + + tm offvmargtype(itmp1), 0x01 /* is this a 2 word type ? */ + jne L_register_handle_double + + /* handle argument */ + + chi s1, 1 + je L_handle_f0 + chi s1, 2 + je L_handle_f1 + +L_register_handle_double: + + /* handle argument */ + + chi s1, 1 + je L_handle_d0 + chi s1, 2 + je L_handle_d1 + +L_register_copy_done: + +/* + Regiser usage: + itmp1: argument block pointer + itmp2: argument counter + s0: integer argument counter (initialized by previous code) + s1: float argument counter (initialized by previous code) + s2: pointer to current argument on stack + s3: backup argument block pointer (used to initialize itmp1) + after used as backup of original stack pointer + s4: backup argument count (used to initialize itmp2) + after used as size of parameters on stack +*/ + + lr itmp2, s4 /* restore argument counter */ + lr itmp1, s3 /* restore argument block pointer */ + + /* calculate remaining arguments */ + sr s4, s0 /* - integer arguments in registers */ + sr s4, s1 /* - float arguments in registers */ + + je L_copy_done /* no arguments left for stack */ + + sll s4, 3 /* allocate 8 bytes per parameter on stack */ + lr s3, sp /* backup stack pointer */ + sr sp, s4 /* allocate stack space for arguments */ + + lr s2, sp /* points now to current argument on stack */ + + ahi itmp1, -sizevmarg /* initialize argument block pointer */ + ahi itmp2, 1 /* initialize argument counter */ + +L_stack_copy_loop: + + ahi itmp1, sizevmarg /* forward argument block pointer */ + ahi itmp2, -1 /* decrement argument counter */ + je L_copy_done /* all arguments done */ + + tm offvmargtype(itmp1), 0x0 /* is this a float/double type? */ + jne L_stack_handle_float + +L_stack_handle_int: + + ahi s0, -1 /* decrement number of integer arguments in regs */ + jhe L_stack_copy_loop /* argument is in register */ + + tm offvmargtype(itmp1), 0x01 /* is this a 2 word type ? */ + jne L_stack_handle_long + + mvc 0(4, s2), offvmargdata(itmp1) /* copy integer value */ + ahi s2, 4 + j L_stack_copy_loop + +L_stack_handle_long: + + mvc 0(8, s2), offvmargdata(itmp1) /* copy long value */ + ahi s2, 8 + j L_stack_copy_loop + +L_stack_handle_float: + + ahi s1, -1 /* decrement number of float arguments in regs */ + jhe L_stack_copy_loop /* argument is in register */ + + tm offvmargtype(itmp1), 0x01 /* is this a 2 word type ? */ + jne L_stack_handle_double + + mvc 0(4, s2), offvmargdata(itmp1) /* copy float value */ + ahi s2, 4 + j L_stack_copy_loop + +L_stack_handle_double: + + mvc 0(8, s2), offvmargdata(itmp1) /* copy double value */ + ahi s2, 8 + j L_stack_copy_loop + +L_copy_done: + + /* Now we call the compiler in a rather questionable way i needed + * some days to understand: + * + * We can't simply call asm_call_jit_compiler, but we have to call an + * address loaded from memory like it is done in JIT code. + * + * This is because the compiler will intercept the instruction before + * the call instruction, extract the address where the function pointer + * has been loaded from and overwrite it with the code entry. + * + * Arguments are passed in temporary registers. + */ + + /* load address of L_asm_call_jit_compiler into memory */ + + basr mptr, 0 /* store PC */ +L_basr: + la mptr, L_asm_call_jit_compiler-L_basr(mptr) /* add offset to PC */ + st mptr, 12(s3) /* store on stack */ + + l itmp1, 0(s3) /* load methodinfo for compiler */ + la mptr, 12(s3) /* store **function in mptr for compiler */ + + /* call L_asm_call_jit_compiler like JIT code would do */ + + l itmp3, 12(s3) /* load address of target from memory */ + basr %r14, itmp3 /* jump to target */ + + /* todo will s4 survive the call? */ + ar sp, s4 /* remove stack space for arguments */ + +L_asm_vm_call_method_return: + + ahi sp, 16 /* remove stack space for local variables */ + lm %r6, %r15, 24(sp) /* restore callers registers */ + br %r14 /* return */ + +/* .... */ + +L_no_args: + lr s3, sp + j L_copy_done + +L_handle_i0: + l a0, offvmargdata(itmp1) + j L_register_copy +L_handle_i1: + l a1, offvmargdata(itmp1) + j L_register_copy +L_handle_i2: + l a2, offvmargdata(itmp1) + j L_register_copy +L_handle_i3: + l a3, offvmargdata(itmp1) + j L_register_copy +L_handle_i4: + l a4, offvmargdata(itmp1) + j L_register_copy + +L_handle_l0: + lm a0, a1, offvmargdata(itmp1) + j L_register_copy +L_handle_l1: + lm a1, a2, offvmargdata(itmp1) + j L_register_copy +L_handle_l2: + lm a2, a3, offvmargdata(itmp1) + j L_register_copy +L_handle_l3: + lm a3, a4, offvmargdata(itmp1) + j L_register_copy + +L_handle_f0: + le fa0, offvmargdata(itmp1) + j L_register_copy +L_handle_f1: + le fa1, offvmargdata(itmp1) + j L_register_copy + +L_handle_d0: + ld fa0, offvmargdata(itmp1) + j L_register_copy +L_handle_d1: + ld fa1, offvmargdata(itmp1) + j L_register_copy + + +/* .... */ + +#if 0 + + .align 8 + + .quad 0 /* catch type all */ + .quad 0 /* handler pc */ + .quad 0 /* end pc */ + .quad 0 /* start pc */ + .long 1 /* extable size */ + .long 0 /* ALIGNMENT PADDING */ + .quad 0 /* line number table start */ + .quad 0 /* line number table size */ + .long 0 /* ALIGNMENT PADDING */ + .long 0 /* fltsave */ + .long 0 /* intsave */ + .long 0 /* isleaf */ + .long 0 /* IsSync */ + .long 0 /* frame size */ + .quad 0 /* codeinfo pointer */ + +asm_vm_call_method: +asm_vm_call_method_int: +asm_vm_call_method_long: +asm_vm_call_method_float: +asm_vm_call_method_double: + + stm %r6,%r15,24(sp) /* save callers regiters */ + + ahi sp, -12 /* allocate space on stack for local variables */ + + st a0, 0(sp) /* store method info */ + st a1, 4(sp) /* store arg count */ + st a2, 8(sp) /* store args */ + + +# define r_methodinfo itmp1 +# define r_vmargscount itmp2 +# define r_vmargs s0 + +# define r_arg_ctr s1 +# define r_arg_ptr s2 + +# define r_int_ctr s3 +# define r_float_ctr s4 +# define r_int_extra_ctr itmp3 + + /* save arguments */ + + lr r_methodinfo,a0 /* move method pointer for compiler */ + lr r_vmargscount,a1 + lr r_vmargs,a2 + + ltr a1,a1 /* maybe we have no args... */ + je L_copy_done + + lr r_arg_ctr,r_vmargscount /* arg count */ + lr r_arg_ptr,r_vmargs /* pointer to arg block */ + + ahi r_arg_ptr,-sizevmarg /* initialize pointer (smaller code) */ + ahi r_arg_ctr,1 /* initialize argument count */ + + lhi r_int_ctr,0 /* initialize integer argument counter*/ + lhi r_float_ctr,0 /* initialize float argument counter */ + lhi r_int_extra_ctr,0 + +L_register_copy: + ahi r_arg_ptr,sizevmarg /* goto next argument block */ + ahi r_arg_ctr,-1 /* argument count - 1 */ + je L_register_copy_done + + tm offvmargtype(r_arg_ptr),0x02 /* is this a float/double type? */ + jne L_register_handle_float /* yes, handle it */ + + cli offvmargtype(r_arg_ptr),0x01 + je L_register_handle_long + +L_register_handle_int: + + chi r_int_ctr,INT_ARG_CNT /* are we out of integer argument */ + je L_register_copy /* register? yes, next loop */ + + ahi r_int_ctr,1 + + chi r_int_ctr,1 + je L_handle_a0 + chi r_int_ctr,2 + je L_handle_a1 + chi r_int_ctr,3 + je L_handle_a2 + chi r_int_ctr,4 + je L_handle_a3 + chi r_int_ctr,5 + je L_handle_a4 + +L_register_handle_long: + + chi r_int_ctr,INT_ARG_CNT-1 /* only one integer register left ? */ + je L_register_handle_long_last_reg + + chi r_int_ctr,INT_ARG_CNT /* no registers left */ + je L_register_copy + + ahi r_int_ctr,2 + ahi r_int_extra_ctr,1 + + chi r_int_ctr,2 + je L_handle_al0 + chi r_int_ctr,3 + je L_handle_al1 + chi r_int_ctr,4 + je L_handle_al2 + chi r_int_ctr,5 + je L_handle_al3 + +L_register_handle_long_last_reg: + ahi r_int_ctr,1 /* skip the integer register */ + ahi r_int_extra_ctr,1 + j L_register_copy + +L_register_handle_float: + chi r_float_ctr,FLT_ARG_CNT /* are we out of float argument */ + je L_register_copy /* register? yes, next loop */ + + ahi r_float_ctr,1 + + chi r_int_ctr,1 + je L_handle_af0 + chi r_int_ctr,2 + je L_handle_af1 + +L_register_copy_done: + + lr r_arg_ctr, r_vmargscount + sr r_arg_ctr, r_int_ctr + ar r_arg_ctr, r_int_extra_ctr + sr r_arg_ctr, r_float_ctr + jle L_copy_done + + /* now allocate the parameter area on the stack + * the register save area will be allocated later + */ + +# define r_arg_stack_ptr r_arg_ptr + + sll r_arg_ctr, 3 /* 8 bytes per parameter on stack */ + sr sp,r_arg_ctr /* allocate stack space for parameters */ + lr r_arg_stack_ptr,sp /* points now to arguments on stack */ + + ahi r_vmargs,-sizevmarg /* initialize pointer (smaller code) */ + ahi r_vmargscount,1 /* initialize argument count */ + +L_stack_copy_loop: + ahi r_vmargs,sizevmarg /* goto next argument block */ + ahi r_vmargscount,-1 /* argument count - 1 */ + jz L_copy_done /* no test needed after dec */ + + tm offvmargtype(r_vmargs),0x02 /* is this a float/double type? */ + jne L_stack_handle_float /* yes, handle it */ + + cli offvmargtype(r_vmargs),0x01 + je L_stack_handle_long + +L_stack_handle_int: + + ahi r_int_ctr,-1 /* arguments assigned to registers */ + jhe L_stack_copy_loop + j L_stack_copy + +L_stack_handle_long: + + ahi r_int_ctr,-2 + jhe L_stack_copy_loop + j L_stack_copy + +L_stack_handle_float: + ahi r_float_ctr,-1 /* arguments assigned to registers */ + jhe L_stack_copy_loop + +L_stack_copy: + mvc 0(8,r_arg_stack_ptr),offvmargdata(r_vmargs) /* copy s8 argument onto stack */ + + ahi r_arg_stack_ptr,8 /* increase sp to next argument */ + j L_stack_copy_loop + +L_copy_done: +#if 0 + /* itmp1 still contains method pointer*/ + lea L_asm_call_jit_compiler(%rip),mptr + mov sp,itmp3 /* calculate the old stack pointer */ + add bp,itmp3 + mov mptr,6*8(itmp3) /* store mptr on stack */ + lea (6*8-256)(itmp3),mptr /* We subtract 256 to force the next */ + /* move instruction to have a 32-bit */ + /* offset. */ + + mov (0*8+256)(mptr),itmp3 /* method call as in Java */ + call *itmp3 /* call JIT compiler */ + + add bp,sp /* remove argument stack frame if any */ +#endif + + /* itmp1 still contains method pointer*/ + + bras %r14, L_asm_call_jit_compiler + ar sp,r_arg_ctr /* r_arg_ctr in callee saved regiter */ + +L_asm_vm_call_method_return: + + ahi sp, 12 /* free stack space */ + lm %r6,%r15,24(sp) /* restore registers */ + br %r14 /* branch to return address */ + +#if 0 +asm_vm_call_method_exception_handler: + mov xptr,a0 /* pass exception pointer */ + call builtin_throw_exception@PLT + jmp L_asm_vm_call_method_return +#endif + +L_handle_a0: + l a0,offvmargdata(r_arg_ptr) + j L_register_copy +L_handle_a1: + l a1,offvmargdata(r_arg_ptr) + j L_register_copy +L_handle_a2: + l a2,offvmargdata(r_arg_ptr) + j L_register_copy +L_handle_a3: + l a3,offvmargdata(r_arg_ptr) + j L_register_copy +L_handle_a4: + l a4,offvmargdata(r_arg_ptr) + j L_register_copy + +L_handle_al0: + l a0,offvmargdata(r_arg_ptr) + l a1,offvmargdata+4(r_arg_ptr) + j L_register_copy +L_handle_al1: + l a1,offvmargdata(r_arg_ptr) + l a2,offvmargdata+4(r_arg_ptr) + j L_register_copy +L_handle_al2: + l a2,offvmargdata(r_arg_ptr) + l a3,offvmargdata+4(r_arg_ptr) + j L_register_copy +L_handle_al3: + l a3,offvmargdata(r_arg_ptr) + l a4,offvmargdata+4(r_arg_ptr) + j L_register_copy + +L_handle_af0: + ld fa0,offvmargdata(r_arg_ptr) + j L_register_copy +L_handle_af1: + ld fa1,offvmargdata(r_arg_ptr) + j L_register_copy + +#endif + +/****************** function asm_call_jit_compiler ***************************** +* * +* invokes the compiler for untranslated JavaVM methods. * +* * +* itmp1: methodinfo pointer * +* itmp2: method pointer * +* * +*******************************************************************************/ + +/* + +argument registers: arguments (like in JIT) + + arguments on stack (like in JIT) +------------------------------------------------------------- <- SP on entry + + saved return address \ + stored volatile (in terms of C ABI) floag argument registers | +96 stored volatile (in terms of C ABI) integer argument registers | ACJC_STACKFRAME +0 - 96 register save area (C ABI) / +-------------------------------------------------- <- SP for jit_asm_compile +*/ + +/* This is called from a compiler stub. + * Arguments are already in registers and the stack is setup like in CACAO. + */ + +asm_call_jit_compiler: +L_asm_call_jit_compiler: + +# define ACJC_STACKFRAME (4 + (4 * 4) + (2 * 8) + 96) + + ahi sp,-ACJC_STACKFRAME /* allocate stack space */ + + stm %r2,%r5,96(sp) /* store volatile int arg regs */ + std %f0,96+16(sp) /* store volatile float arg regs */ + std %f2,96+24(sp) + st %r14,96+32(sp) /* store return address */ + + /* load arguments */ + + lr a0,itmp1 /* pass methodinfo pointer */ + lr a1,itmp2 /* pass method pointer */ + la a2,ACJC_STACKFRAME(sp) /* pass java sp */ + la a3,0(%r14) /* pass return address, make sure bit 32 is 0 */ + + /* call jit_asm_compile in a PIC way */ + + bras itmp3, L_bras_jac + .long jit_asm_compile +L_bras_jac: + l itmp3, 0(itmp3) + basr %r14, itmp3 + + lm %r2,%r5,96(sp) /* restore volatile int arg regs */ + ld %f0,96+16(sp) /* store volatile float arg regs */ + ld %f2,96+24(sp) /* store volatile float arg regs */ + ld %r14,96+32(sp) /* restore return address */ + +#if 0 + ltr v0,v0 + je L_asm_call_jit_compiler_exception +#endif + + b 0(v0) /* call the method, it will return to the caller */ + + +L_asm_call_jit_compiler_exception: +#if 0 + call exceptions_get_and_clear_exception@PLT + pop xpc /* delete return address */ + sub $3,xpc /* faulting address is ra - 3 */ + jmp L_asm_handle_exception +#endif + .long 0 + + +#if 0 +/* asm_handle_exception ******************************************************** +* * +* This function handles an exception. It does not use the usual calling * +* conventions. The exception pointer is passed in REG_ITMP1 and the * +* pc from the exception raising position is passed in REG_ITMP2. It searches * +* the local exception table for a handler. If no one is found, it unwinds * +* stacks and continues searching the callers. * +* * +*******************************************************************************/ + +asm_handle_nat_exception: + add $8,sp /* clear return address of native stub*/ + +asm_handle_exception: +L_asm_handle_exception: /* required for PIC code */ + sub $((ARG_CNT+TMP_CNT)*8),sp /* create maybe-leaf stackframe */ + + SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */ + SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */ + + mov $((ARG_CNT+TMP_CNT)*8),a3 /* prepare a3 for handle_exception */ + mov $1,t0 /* set maybe-leaf flag */ + +L_asm_handle_exception_stack_loop: + sub $(6*8),sp + mov xptr,0*8(sp) /* save exception pointer */ + mov xpc,1*8(sp) /* save exception pc */ + add sp,a3 /* calculate Java sp into a3... */ + add $(6*8),a3 + mov a3,3*8(sp) /* ...and save it */ + mov t0,4*8(sp) /* save maybe-leaf flag */ + + mov xpc,a0 /* exception pc */ + call codegen_get_pv_from_pc@PLT + mov v0,2*8(sp) /* save data segment pointer */ + + mov 0*8(sp),a0 /* pass exception pointer */ + mov 1*8(sp),a1 /* pass exception pc */ + mov v0,a2 /* pass data segment pointer */ + mov 3*8(sp),a3 /* pass Java stack pointer */ + call exceptions_handle_exception@PLT + + test v0,v0 + jz L_asm_handle_exception_not_catched + + mov v0,xpc /* move handlerpc into xpc */ + mov 0*8(sp),xptr /* restore exception pointer */ + mov 4*8(sp),t0 /* get maybe-leaf flag */ + add $(6*8),sp /* free stack frame */ + + test t0,t0 /* test for maybe-leaf flag */ + jz L_asm_handle_exception_no_leaf + + RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */ + RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */ + + add $((ARG_CNT+TMP_CNT)*8),sp /* remove maybe-leaf stackframe */ + +L_asm_handle_exception_no_leaf: + jmp *xpc /* jump to the handler */ + +L_asm_handle_exception_not_catched: + mov 0*8(sp),xptr /* restore exception pointer */ + mov 2*8(sp),itmp3 /* restore data segment pointer */ + mov 4*8(sp),t0 /* get maybe-leaf flag */ + add $(6*8),sp + + test t0,t0 + jz L_asm_handle_exception_no_leaf_stack + + add $((ARG_CNT+TMP_CNT)*8),sp /* remove maybe-leaf stackframe */ + xor t0,t0 /* clear the isleaf flags */ + +L_asm_handle_exception_no_leaf_stack: + mov FrameSize(itmp3),itmp2l /* get frame size */ + add sp,itmp2 /* pointer to save area */ + + mov IntSave(itmp3),a0l /* a0l = saved int register count */ + test a0l,a0l + je noint + + cmp $1,a0l + je int1 + cmp $2,a0l + je int2 + cmp $3,a0l + je int3 + cmp $4,a0l + je int4 + + mov -5*8(itmp2),s0 +int4: + mov -4*8(itmp2),s1 +int3: + mov -3*8(itmp2),s2 +int2: + mov -2*8(itmp2),s3 +int1: + mov -1*8(itmp2),s4 + + shl $3,a0l /* multiply by 8 bytes */ + sub a0,itmp2 + +noint: +#if 0 + mov FltSave(itmp3),a0l /* a0l = saved flt register count */ + test a0l,a0l + je noflt + + cmpl $1,a0l + je flt1 + cmpl $2,a0l + je flt2 + cmpl $3,a0l + je flt3 + cmpl $4,a0l + je flt4 + + movq -5*8(itmp2),%xmm11 +flt4: + movq -4*8(itmp2),%xmm12 +flt3: + movq -3*8(itmp2),%xmm13 +flt2: + movq -2*8(itmp2),%xmm14 +flt1: + movq -1*8(itmp2),%xmm15 + +noflt: +#endif + mov FrameSize(itmp3),itmp2l /* get frame size */ + add itmp2,sp /* unwind stack */ + + /* exception pointer is still set */ + pop xpc /* the new xpc is return address */ + sub $3,xpc /* subtract 3 bytes for call */ + + xor a3,a3 /* prepare a3 for handle_exception */ + + jmp L_asm_handle_exception_stack_loop + + +/* asm_abstractmethoderror ***************************************************** + + Creates and throws an AbstractMethodError. + +*******************************************************************************/ + +asm_abstractmethoderror: + mov sp,a0 /* pass java sp */ + add $1*8,a0 + mov 0*8(sp),a1 /* pass exception address */ + sub $3,a1 + call exceptions_asm_new_abstractmethoderror@PLT + /* exception pointer is return value */ + pop xpc /* get exception address */ + sub $3,xpc /* exception address is ra - 3 */ + jmp L_asm_handle_exception + + +/* asm_patcher_wrapper ********************************************************* + + XXX + + Stack layout: + 40 return address + 32 pointer to virtual java_objectheader + 24 machine code (which is patched back later) + 16 unresolved class/method/field reference + 8 data segment displacement from load instructions + 0 pointer to patcher function + -8 bp + +*******************************************************************************/ + +asm_patcher_wrapper: + push bp /* save base pointer */ + mov sp,bp /* move actual sp to bp */ + sub $((3+ARG_CNT+TMP_CNT)*8+sizestackframeinfo),sp + and $0xfffffffffffffff0,sp /* align sp to 16-byte (this is for */ + /* leaf functions) */ + + SAVE_ARGUMENT_REGISTERS(3) + SAVE_TEMPORARY_REGISTERS(3+ARG_CNT) + + mov itmp1,0*8(sp) /* save itmp1 and itmp2 */ + mov itmp2,1*8(sp) /* can be used by some instructions */ + + mov bp,a0 /* pass SP of patcher stub */ + add $(1*8),a0 + mov $0,a1 /* pass PV (if NULL, use findmethod) */ + mov $0,a2 /* pass RA (it's on the stack) */ + call patcher_wrapper@PLT + mov v0,2*8(sp) /* save return value */ + + RESTORE_ARGUMENT_REGISTERS(3) + RESTORE_TEMPORARY_REGISTERS(3+ARG_CNT) + + mov 0*8(sp),itmp1 /* restore itmp1 and itmp2 */ + mov 1*8(sp),itmp2 /* can be used by some instructions */ + mov 2*8(sp),itmp3 /* restore return value */ + + mov bp,sp /* restore original sp */ + pop bp /* restore bp */ + add $(5*8),sp /* remove patcher stackframe, keep RA */ + + test itmp3,itmp3 /* exception thrown? */ + jne L_asm_patcher_wrapper_exception + ret /* call new patched code */ + +L_asm_patcher_wrapper_exception: + mov itmp3,xptr /* get exception */ + pop xpc /* get and remove return address */ + jmp L_asm_handle_exception + + +/* asm_replacement_out ********************************************************* + + This code is jumped to from the replacement-out stubs that are executed + when a thread reaches an activated replacement point. + + The purpose of asm_replacement_out is to read out the parts of the + execution state that cannot be accessed from C code, store this state, + and then call the C function replace_me. + + Stack layout: + 8 start of stack inside method to replace + 0 rplpoint * info on the replacement point that was reached + +*******************************************************************************/ + +/* some room to accomodate changes of the stack frame size during replacement */ + /* XXX we should find a cleaner solution here */ +#define REPLACEMENT_ROOM 512 + +asm_replacement_out: + /* create stack frame */ + sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp + + /* save registers in execution state */ + mov %rax,(RAX*8+offes_intregs)(sp) + mov %rbx,(RBX*8+offes_intregs)(sp) + mov %rcx,(RCX*8+offes_intregs)(sp) + mov %rdx,(RDX*8+offes_intregs)(sp) + mov %rsi,(RSI*8+offes_intregs)(sp) + mov %rdi,(RDI*8+offes_intregs)(sp) + mov %rbp,(RBP*8+offes_intregs)(sp) + movq $0 ,(RSP*8+offes_intregs)(sp) /* not used */ + mov %r8 ,(R8 *8+offes_intregs)(sp) + mov %r9 ,(R9 *8+offes_intregs)(sp) + mov %r10,(R10*8+offes_intregs)(sp) + mov %r11,(R11*8+offes_intregs)(sp) + mov %r12,(R12*8+offes_intregs)(sp) + mov %r13,(R13*8+offes_intregs)(sp) + mov %r14,(R14*8+offes_intregs)(sp) + mov %r15,(R15*8+offes_intregs)(sp) + + movq %xmm0 ,(XMM0 *8+offes_fltregs)(sp) + movq %xmm1 ,(XMM1 *8+offes_fltregs)(sp) + movq %xmm2 ,(XMM2 *8+offes_fltregs)(sp) + movq %xmm3 ,(XMM3 *8+offes_fltregs)(sp) + movq %xmm4 ,(XMM4 *8+offes_fltregs)(sp) + movq %xmm5 ,(XMM5 *8+offes_fltregs)(sp) + movq %xmm6 ,(XMM6 *8+offes_fltregs)(sp) + movq %xmm7 ,(XMM7 *8+offes_fltregs)(sp) + movq %xmm8 ,(XMM8 *8+offes_fltregs)(sp) + movq %xmm9 ,(XMM9 *8+offes_fltregs)(sp) + movq %xmm10,(XMM10*8+offes_fltregs)(sp) + movq %xmm11,(XMM11*8+offes_fltregs)(sp) + movq %xmm12,(XMM12*8+offes_fltregs)(sp) + movq %xmm13,(XMM13*8+offes_fltregs)(sp) + movq %xmm14,(XMM14*8+offes_fltregs)(sp) + movq %xmm15,(XMM15*8+offes_fltregs)(sp) + + /* calculate sp of method */ + mov sp,itmp1 + add $(sizeexecutionstate + REPLACEMENT_ROOM + 8),itmp1 + mov itmp1,(offes_sp)(sp) + + /* pv must be looked up via AVL tree */ + movq $0,(offes_pv)(sp) + + /* call replace_me */ + mov -8(itmp1),a0 /* rplpoint * */ + mov sp,a1 /* arg1: execution state */ + call replace_me@PLT /* call C function replace_me */ + call abort@PLT /* NEVER REACHED */ + +/* asm_replacement_in ********************************************************** + + This code writes the given execution state and jumps to the replacement + code. + + This function never returns! + + C prototype: + void asm_replacement_in(executionstate *es); + +*******************************************************************************/ + +asm_replacement_in: + mov a0,%rbp /* executionstate *es */ + + /* set new sp */ + mov (offes_sp)(%rbp),%rsp + + /* store address of new code */ + push (offes_pc)(%rbp) + + /* copy registers from execution state */ + movq (XMM0 *8+offes_fltregs)(%rbp),%xmm0 + movq (XMM1 *8+offes_fltregs)(%rbp),%xmm1 + movq (XMM2 *8+offes_fltregs)(%rbp),%xmm2 + movq (XMM3 *8+offes_fltregs)(%rbp),%xmm3 + movq (XMM4 *8+offes_fltregs)(%rbp),%xmm4 + movq (XMM5 *8+offes_fltregs)(%rbp),%xmm5 + movq (XMM6 *8+offes_fltregs)(%rbp),%xmm6 + movq (XMM7 *8+offes_fltregs)(%rbp),%xmm7 + movq (XMM8 *8+offes_fltregs)(%rbp),%xmm8 + movq (XMM9 *8+offes_fltregs)(%rbp),%xmm9 + movq (XMM10*8+offes_fltregs)(%rbp),%xmm10 + movq (XMM11*8+offes_fltregs)(%rbp),%xmm11 + movq (XMM12*8+offes_fltregs)(%rbp),%xmm12 + movq (XMM13*8+offes_fltregs)(%rbp),%xmm13 + movq (XMM14*8+offes_fltregs)(%rbp),%xmm14 + movq (XMM15*8+offes_fltregs)(%rbp),%xmm15 + + mov (RAX*8+offes_intregs)(%rbp),%rax + mov (RBX*8+offes_intregs)(%rbp),%rbx + mov (RCX*8+offes_intregs)(%rbp),%rcx + mov (RDX*8+offes_intregs)(%rbp),%rdx + mov (RSI*8+offes_intregs)(%rbp),%rsi + mov (RDI*8+offes_intregs)(%rbp),%rdi + mov (R8 *8+offes_intregs)(%rbp),%r8 + mov (R9 *8+offes_intregs)(%rbp),%r9 + mov (R10*8+offes_intregs)(%rbp),%r10 + mov (R11*8+offes_intregs)(%rbp),%r11 + mov (R12*8+offes_intregs)(%rbp),%r12 + mov (R13*8+offes_intregs)(%rbp),%r13 + mov (R14*8+offes_intregs)(%rbp),%r14 + mov (R15*8+offes_intregs)(%rbp),%r15 + + mov (RBP*8+offes_intregs)(%rbp),%rbp + + /* jump to new code */ + ret + + +/* asm_builtin_x2x ************************************************************* +* * +* Wrapper functions for float to int corner cases * +* * +*******************************************************************************/ + +asm_builtin_f2i: + sub $(ARG_CNT*8),sp + + SAVE_ARGUMENT_REGISTERS(0) + + movq ftmp1,fa0 + call builtin_f2i@PLT + + RESTORE_ARGUMENT_REGISTERS(0) + + add $(ARG_CNT*8),sp + ret + + +asm_builtin_f2l: + sub $(ARG_CNT*8),sp + + SAVE_ARGUMENT_REGISTERS(0) + + movq ftmp1,fa0 + call builtin_f2l@PLT + + RESTORE_ARGUMENT_REGISTERS(0) + + add $(ARG_CNT*8),sp + ret + + +asm_builtin_d2i: + sub $(ARG_CNT*8),sp + + SAVE_ARGUMENT_REGISTERS(0) + + movq ftmp1,fa0 + call builtin_d2i@PLT + + RESTORE_ARGUMENT_REGISTERS(0) + + add $(ARG_CNT*8),sp + ret + + +asm_builtin_d2l: + sub $(ARG_CNT*8),sp + + SAVE_ARGUMENT_REGISTERS(0) + + movq ftmp1,fa0 + call builtin_d2l@PLT + + RESTORE_ARGUMENT_REGISTERS(0) + + add $(ARG_CNT*8),sp + ret + + +asm_getclassvalues_atomic: +_crit_restart: +_crit_begin: + movl offbaseval(a0),itmp1l + movl offdiffval(a0),itmp2l + movl offbaseval(a1),itmp3l +_crit_end: + movl itmp1l,offcast_super_baseval(a2) + movl itmp2l,offcast_super_diffval(a2) + movl itmp3l,offcast_sub_baseval(a2) + ret + + .data + +asm_criticalsections: +#if defined(ENABLE_THREADS) + .quad _crit_begin + .quad _crit_end + .quad _crit_restart +#endif + .quad 0 + + +/* Disable exec-stacks, required for Gentoo ***********************************/ + +#if defined(__GCC__) && defined(__ELF__) + .section .note.GNU-stack,"",@progbits +#endif + + +#endif /* if 0 */ + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: asm + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/s390/codegen.c b/src/vm/jit/s390/codegen.c new file mode 100644 index 000000000..ff8e83c33 --- /dev/null +++ b/src/vm/jit/s390/codegen.c @@ -0,0 +1,4088 @@ +/* src/vm/jit/x86_64/codegen.c - machine code generator for x86_64 + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Andreas Krall + Christian Thalinger + Christian Ullrich + Edwin Steiner + + $Id: codegen.c 7219 2007-01-16 22:18:57Z pm $ + +*/ + + +#include "config.h" + +#include +#include + +#include "vm/types.h" + +#include "md-abi.h" + +#include "vm/jit/s390/arch.h" +#include "vm/jit/s390/codegen.h" +#include "vm/jit/s390/emit.h" + +#include "mm/memory.h" +#include "native/jni.h" +#include "native/native.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#endif + +#include "vm/builtin.h" +#include "vm/exceptions.h" +#include "vm/global.h" +#include "vm/loader.h" +#include "vm/options.h" +#include "vm/statistics.h" +#include "vm/stringlocal.h" +#include "vm/vm.h" +#include "vm/jit/asmpart.h" +#include "vm/jit/codegen-common.h" +#include "vm/jit/dseg.h" +#include "vm/jit/emit-common.h" +#include "vm/jit/jit.h" +#include "vm/jit/methodheader.h" +#include "vm/jit/parse.h" +#include "vm/jit/patcher.h" +#include "vm/jit/reg.h" +#include "vm/jit/replace.h" + +#if defined(ENABLE_LSRA) +# include "vm/jit/allocator/lsra.h" +#endif + +#define OOPS() assert(0); + +#if 0 +u1 *createcompilerstub(methodinfo *m) { + OOPS(); + u1 *stub = malloc(8); + bzero(stub, 8); + return stub; +} +#endif + +#if 0 +u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd) { + OOPS(); + return createcompilerstub(NULL); +} +#endif + + + +/* codegen ********************************************************************* + + Generates machine code. + +*******************************************************************************/ + + +bool codegen(jitdata *jd) +{ + methodinfo *m; + codeinfo *code; + codegendata *cd; + registerdata *rd; + s4 len, s1, s2, s3, d, disp; + u2 currentline; + ptrint a; + varinfo *var, *var1, *var2, *dst; + basicblock *bptr; + instruction *iptr; + exception_entry *ex; + constant_classref *cr; + unresolved_class *uc; + methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ + unresolved_method *um; + builtintable_entry *bte; + methoddesc *md; + fieldinfo *fi; + unresolved_field *uf; + s4 fieldtype; + rplpoint *replacementpoint; + s4 varindex; + + /* get required compiler data */ + + m = jd->m; + code = jd->code; + cd = jd->cd; + rd = jd->rd; + + /* prevent compiler warnings */ + + d = 0; + lm = NULL; + um = NULL; + bte = NULL; + + { + s4 i, p, t, l; + s4 savedregs_num; + + savedregs_num = 0; + + /* space to save used callee saved registers */ + + savedregs_num += (INT_SAV_CNT - rd->savintreguse); + savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); + + cd->stackframesize = rd->memuse + savedregs_num; + +#if defined(ENABLE_THREADS) + /* space to save argument of monitor_enter */ + + if (checksync && (m->flags & ACC_SYNCHRONIZED)) + cd->stackframesize++; +#endif + + /* Keep stack of non-leaf functions 16-byte aligned for calls into + native code e.g. libc or jni (alignment problems with + movaps). */ + + if (!jd->isleafmethod || opt_verbosecall) + cd->stackframesize |= 0x1; + + /* create method header */ + + (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ + (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* FrameSize */ + +#if defined(ENABLE_THREADS) + /* IsSync contains the offset relative to the stack pointer for the + argument of monitor_exit used in the exception handler. Since the + offset could be zero and give a wrong meaning of the flag it is + offset by one. + */ + + if (checksync && (m->flags & ACC_SYNCHRONIZED)) + (void) dseg_add_unique_s4(cd, (rd->memuse + 1) * 8); /* IsSync */ + else +#endif + (void) dseg_add_unique_s4(cd, 0); /* IsSync */ + + (void) dseg_add_unique_s4(cd, jd->isleafmethod); /* IsLeaf */ + (void) dseg_add_unique_s4(cd, INT_SAV_CNT - rd->savintreguse); /* IntSave */ + (void) dseg_add_unique_s4(cd, FLT_SAV_CNT - rd->savfltreguse); /* FltSave */ + + (void) dseg_addlinenumbertablesize(cd); + + (void) dseg_add_unique_s4(cd, jd->exceptiontablelength); /* ExTableSize */ + + /* create exception table */ + + for (ex = jd->exceptiontable; ex != NULL; ex = ex->down) { + dseg_add_target(cd, ex->start); + dseg_add_target(cd, ex->end); + dseg_add_target(cd, ex->handler); + (void) dseg_add_unique_address(cd, ex->catchtype.any); + } + + /* generate method profiling code */ + + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { + /* count frequency */ + + M_MOV_IMM(code, REG_ITMP3); + M_IINC_MEMBASE(REG_ITMP3, OFFSET(codeinfo, frequency)); + + PROFILE_CYCLE_START; + } + + /* create stack frame (if necessary) */ + + if (cd->stackframesize) + M_ASUB_IMM(cd->stackframesize * 8, REG_SP); + + /* save used callee saved registers */ + + p = cd->stackframesize; + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_LST(rd->savintregs[i], REG_SP, p * 8); + } + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p--; M_DST(rd->savfltregs[i], REG_SP, p * 8); + } + + /* take arguments out of register or stack frame */ + + md = m->parseddesc; + + for (p = 0, l = 0; p < md->paramcount; p++) { + t = md->paramtypes[p].type; + + varindex = jd->local_map[l * 5 + t]; + + l++; + if (IS_2_WORD_TYPE(t)) /* increment local counter for 2 word types */ + l++; + + if (varindex == UNUSED) + continue; + + var = VAR(varindex); + + s1 = md->params[p].regoff; + + if (IS_INT_LNG_TYPE(t)) { /* integer args */ + s2 = rd->argintregs[s1]; + if (!md->params[p].inmemory) { /* register arguments */ + if (!IS_INMEMORY(var->flags)) { /* reg arg -> register */ + M_INTMOVE(s2, var->vv.regoff); + + } else { /* reg arg -> spilled */ + M_LST(s2, REG_SP, var->vv.regoff * 8); + } + + } else { /* stack arguments */ + if (!IS_INMEMORY(var->flags)) { /* stack arg -> register */ + /* + 8 for return address */ + M_LLD(var->vv.regoff, REG_SP, (cd->stackframesize + s1) * 8 + 8); + + } else { /* stack arg -> spilled */ + var->vv.regoff = cd->stackframesize + s1 + 1; + } + } + + } else { /* floating args */ + if (!md->params[p].inmemory) { /* register arguments */ + s2 = rd->argfltregs[s1]; + if (!IS_INMEMORY(var->flags)) { /* reg arg -> register */ + M_FLTMOVE(s2, var->vv.regoff); + + } else { /* reg arg -> spilled */ + M_DST(s2, REG_SP, var->vv.regoff * 8); + } + + } else { /* stack arguments */ + if (!IS_INMEMORY(var->flags)) { /* stack-arg -> register */ + M_DLD(var->vv.regoff, REG_SP, (cd->stackframesize + s1) * 8 + 8); + + } else { + var->vv.regoff = cd->stackframesize + s1 + 1; + } + } + } + } /* end for */ + + /* save monitorenter argument */ + +#if defined(ENABLE_THREADS) + if (checksync && (m->flags & ACC_SYNCHRONIZED)) { + /* stack offset for monitor argument */ + + s1 = rd->memuse; + + if (opt_verbosecall) { + M_LSUB_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); + + for (p = 0; p < INT_ARG_CNT; p++) + M_LST(rd->argintregs[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DST(rd->argfltregs[p], REG_SP, (INT_ARG_CNT + p) * 8); + + s1 += INT_ARG_CNT + FLT_ARG_CNT; + } + + /* decide which monitor enter function to call */ + + if (m->flags & ACC_STATIC) { + M_MOV_IMM(&m->class->object.header, REG_A0); + } + else { + M_TEST(REG_A0); + M_BEQ(0); + codegen_add_nullpointerexception_ref(cd); + } + + M_AST(REG_A0, REG_SP, s1 * 8); + M_MOV_IMM(LOCK_monitor_enter, REG_ITMP1); + M_CALL(REG_ITMP1); + + if (opt_verbosecall) { + for (p = 0; p < INT_ARG_CNT; p++) + M_LLD(rd->argintregs[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DLD(rd->argfltregs[p], REG_SP, (INT_ARG_CNT + p) * 8); + + M_LADD_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); + } + } +#endif + +#if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + emit_verbosecall_enter(jd); +#endif /* !defined(NDEBUG) */ + + } + + /* end of header generation */ + + replacementpoint = jd->code->rplpoints; + + /* walk through all basic blocks */ + + for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { + + bptr->mpc = (u4) ((u1 *) cd->mcodeptr - cd->mcodebase); + + if (bptr->flags >= BBREACHED) { + + /* branch resolving */ + + codegen_resolve_branchrefs(cd, bptr); + + /* handle replacement points */ + +#if 0 + if (bptr->bitflags & BBFLAG_REPLACEMENT) { + replacementpoint->pc = (u1*)(ptrint)bptr->mpc; /* will be resolved later */ + + replacementpoint++; + + assert(cd->lastmcodeptr <= cd->mcodeptr); + cd->lastmcodeptr = cd->mcodeptr + 5; /* 5 byte jmp patch */ + } +#endif + + /* copy interface registers to their destination */ + + len = bptr->indepth; + MCODECHECK(512); + + /* generate basicblock profiling code */ + + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { + /* count frequency */ + + M_MOV_IMM(code->bbfrequency, REG_ITMP3); + M_IINC_MEMBASE(REG_ITMP3, bptr->nr * 4); + + /* if this is an exception handler, start profiling again */ + + if (bptr->type == BBTYPE_EXH) + PROFILE_CYCLE_START; + } + +#if defined(ENABLE_LSRA) + if (opt_lsra) { + while (len) { + len--; + src = bptr->invars[len]; + if ((len == bptr->indepth-1) && (bptr->type != BBTYPE_STD)) { + if (bptr->type == BBTYPE_EXH) { +/* d = reg_of_var(rd, src, REG_ITMP1); */ + if (!IS_INMEMORY(src->flags)) + d= src->vv.regoff; + else + d=REG_ITMP1; + M_INTMOVE(REG_ITMP1, d); + emit_store(jd, NULL, src, d); + } + } + } + + } else { +#endif + + while (len) { + len--; + var = VAR(bptr->invars[len]); + if ((len == bptr->indepth-1) && (bptr->type != BBTYPE_STD)) { + if (bptr->type == BBTYPE_EXH) { + d = codegen_reg_of_var(0, var, REG_ITMP1); + M_INTMOVE(REG_ITMP1, d); + emit_store(jd, NULL, var, d); + } + } + else { + assert((var->flags & INOUT)); + } + } +#if defined(ENABLE_LSRA) + } +#endif + /* walk through all instructions */ + + len = bptr->icount; + currentline = 0; + + for (iptr = bptr->iinstr; len > 0; len--, iptr++) { + if (iptr->line != currentline) { + dseg_addlinenumber(cd, iptr->line); + currentline = iptr->line; + } + + MCODECHECK(1024); /* 1KB should be enough */ + + switch (iptr->opc) { + case ICMD_NOP: /* ... ==> ... */ + case ICMD_POP: /* ..., value ==> ... */ + case ICMD_POP2: /* ..., value, value ==> ... */ + case ICMD_INLINE_START: /* internal ICMDs */ + case ICMD_INLINE_END: + break; + + case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_TEST(s1); + M_BEQ(0); + codegen_add_nullpointerexception_ref(cd); +#endif + break; + + /* constant operations ************************************************/ + + case ICMD_ICONST: /* ... ==> ..., constant */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + ICONST(d, iptr->sx.val.i); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LCONST: /* ... ==> ..., constant */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + LCONST(d, iptr->sx.val.l); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_FCONST: /* ... ==> ..., constant */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + disp = dseg_add_float(cd, iptr->sx.val.f); + emit_movdl_membase_reg(cd, RIP, -((cd->mcodeptr + ((d > 7) ? 9 : 8)) - cd->mcodebase) + disp, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_DCONST: /* ... ==> ..., constant */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + disp = dseg_add_double(cd, iptr->sx.val.d); + emit_movd_membase_reg(cd, RIP, -((cd->mcodeptr + 9) - cd->mcodebase) + disp, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_ACONST: /* ... ==> ..., constant */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + cr = iptr->sx.val.c.ref; + +/* PROFILE_CYCLE_STOP; */ + + codegen_add_patch_ref(cd, PATCHER_aconst, cr, 0); + +/* PROFILE_CYCLE_START; */ + + M_MOV_IMM(NULL, d); + + } else { + if (iptr->sx.val.anyptr == 0) + M_CLR(d); + else + M_MOV_IMM(iptr->sx.val.anyptr, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + + /* load/store/copy/move operations ************************************/ + + case ICMD_ILOAD: /* ... ==> ..., content of local variable */ + case ICMD_ALOAD: /* s1 = local variable */ + case ICMD_LLOAD: + case ICMD_FLOAD: + case ICMD_DLOAD: + case ICMD_ISTORE: /* ..., value ==> ... */ + case ICMD_LSTORE: + case ICMD_FSTORE: + case ICMD_DSTORE: + case ICMD_COPY: + case ICMD_MOVE: + OOPS(); +#if 0 + emit_copy(jd, iptr, VAROP(iptr->s1), VAROP(iptr->dst)); +#endif + break; + + case ICMD_ASTORE: + OOPS(); +#if 0 + if (!(iptr->flags.bits & INS_FLAG_RETADDR)) + emit_copy(jd, iptr, VAROP(iptr->s1), VAROP(iptr->dst)); +#endif + break; + + /* integer operations *************************************************/ + + case ICMD_INEG: /* ..., value ==> ..., - value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + M_INEG(d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LNEG: /* ..., value ==> ..., - value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + M_LNEG(d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_I2L: /* ..., value ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_ISEXT(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_L2I: /* ..., value ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_IMOV(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_INT2BYTE: /* ..., value ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_BSEXT(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_INT2CHAR: /* ..., value ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_CZEXT(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_INT2SHORT: /* ..., value ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_SSEXT(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + + case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) + M_IADD(s1, d); + else { + M_INTMOVE(s1, d); + M_IADD(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IINC: + case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + + /* Using inc and dec is not faster than add (tested with + sieve). */ + + M_INTMOVE(s1, d); + M_IADD_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) + M_LADD(s1, d); + else { + M_INTMOVE(s1, d); + M_LADD(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */ + /* sx.val.l = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + if (IS_IMM32(iptr->sx.val.l)) + M_LADD_IMM(iptr->sx.val.l, d); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LADD(REG_ITMP2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) { + M_INTMOVE(s1, REG_ITMP1); + M_ISUB(s2, REG_ITMP1); + M_INTMOVE(REG_ITMP1, d); + } else { + M_INTMOVE(s1, d); + M_ISUB(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + M_ISUB_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) { + M_INTMOVE(s1, REG_ITMP1); + M_LSUB(s2, REG_ITMP1); + M_INTMOVE(REG_ITMP1, d); + } else { + M_INTMOVE(s1, d); + M_LSUB(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */ + /* sx.val.l = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + if (IS_IMM32(iptr->sx.val.l)) + M_LSUB_IMM(iptr->sx.val.l, d); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LSUB(REG_ITMP2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) + M_IMUL(s1, d); + else { + M_INTMOVE(s1, d); + M_IMUL(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + if (iptr->sx.val.i == 2) { + M_INTMOVE(s1, d); + M_ISLL_IMM(1, d); + } else + M_IMUL_IMM(s1, iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) + M_LMUL(s1, d); + else { + M_INTMOVE(s1, d); + M_LMUL(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */ + /* sx.val.l = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + if (IS_IMM32(iptr->sx.val.l)) + M_LMUL_IMM(s1, iptr->sx.val.l, d); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_INTMOVE(s1, d); + M_LMUL(REG_ITMP2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + OOPS(); +#if 0 + var1 = VAROP(iptr->s1); + var2 = VAROP(iptr->sx.s23.s2); + dst = VAROP(iptr->dst); + + d = codegen_reg_of_dst(jd, iptr, REG_NULL); + if (IS_INMEMORY(var1->flags)) + M_ILD(RAX, REG_SP, var1->vv.regoff * 8); + else + M_INTMOVE(var1->vv.regoff, RAX); + + if (IS_INMEMORY(var2->flags)) + M_ILD(REG_ITMP3, REG_SP, var2->vv.regoff * 8); + else + M_INTMOVE(var2->vv.regoff, REG_ITMP3); + + if (checknull) { + M_ITEST(REG_ITMP3); + M_BEQ(0); + codegen_add_arithmeticexception_ref(cd); + } + + emit_alul_imm_reg(cd, ALU_CMP, 0x80000000, RAX); /* check as described in jvm spec */ + emit_jcc(cd, CC_NE, 4 + 6); + emit_alul_imm_reg(cd, ALU_CMP, -1, REG_ITMP3); /* 4 bytes */ + emit_jcc(cd, CC_E, 3 + 1 + 3); /* 6 bytes */ + + emit_mov_reg_reg(cd, RDX, REG_ITMP2); /* save %rdx, cause it's an argument register */ + emit_cltd(cd); + emit_idivl_reg(cd, REG_ITMP3); + + if (IS_INMEMORY(dst->flags)) { + emit_mov_reg_membase(cd, RAX, REG_SP, dst->vv.regoff * 8); + emit_mov_reg_reg(cd, REG_ITMP2, RDX); /* restore %rdx */ + + } else { + M_INTMOVE(RAX, dst->vv.regoff); + + if (dst->vv.regoff != RDX) { + emit_mov_reg_reg(cd, REG_ITMP2, RDX); /* restore %rdx */ + } + } +#endif + break; + + case ICMD_IREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + OOPS(); +#if 0 + var1 = VAROP(iptr->s1); + var2 = VAROP(iptr->sx.s23.s2); + dst = VAROP(iptr->dst); + + d = codegen_reg_of_dst(jd, iptr, REG_NULL); + if (IS_INMEMORY(var1->flags)) + M_ILD(RAX, REG_SP, var1->vv.regoff * 8); + else + M_INTMOVE(var1->vv.regoff, RAX); + + if (IS_INMEMORY(var2->flags)) + M_ILD(REG_ITMP3, REG_SP, var2->vv.regoff * 8); + else + M_INTMOVE(var2->vv.regoff, REG_ITMP3); + + if (checknull) { + M_ITEST(REG_ITMP3); + M_BEQ(0); + codegen_add_arithmeticexception_ref(cd); + } + + emit_mov_reg_reg(cd, RDX, REG_ITMP2); /* save %rdx, cause it's an argument register */ + + emit_alul_imm_reg(cd, ALU_CMP, 0x80000000, RAX); /* check as described in jvm spec */ + emit_jcc(cd, CC_NE, 2 + 4 + 6); + + + emit_alul_reg_reg(cd, ALU_XOR, RDX, RDX); /* 2 bytes */ + emit_alul_imm_reg(cd, ALU_CMP, -1, REG_ITMP3); /* 4 bytes */ + emit_jcc(cd, CC_E, 1 + 3); /* 6 bytes */ + + emit_cltd(cd); + emit_idivl_reg(cd, REG_ITMP3); + + if (IS_INMEMORY(dst->flags)) { + emit_mov_reg_membase(cd, RDX, REG_SP, dst->vv.regoff * 8); + emit_mov_reg_reg(cd, REG_ITMP2, RDX); /* restore %rdx */ + + } else { + M_INTMOVE(RDX, dst->vv.regoff); + + if (dst->vv.regoff != RDX) { + emit_mov_reg_reg(cd, REG_ITMP2, RDX); /* restore %rdx */ + } + } +#endif + break; + + case ICMD_IDIVPOW2: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_INTMOVE(s1, REG_ITMP1); + emit_alul_imm_reg(cd, ALU_CMP, -1, REG_ITMP1); + emit_leal_membase_reg(cd, REG_ITMP1, (1 << iptr->sx.val.i) - 1, REG_ITMP2); + emit_cmovccl_reg_reg(cd, CC_LE, REG_ITMP2, REG_ITMP1); + emit_shiftl_imm_reg(cd, SHIFT_SAR, iptr->sx.val.i, REG_ITMP1); + emit_mov_reg_reg(cd, REG_ITMP1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_INTMOVE(s1, REG_ITMP1); + emit_alul_imm_reg(cd, ALU_CMP, -1, REG_ITMP1); + emit_leal_membase_reg(cd, REG_ITMP1, iptr->sx.val.i, REG_ITMP2); + emit_cmovccl_reg_reg(cd, CC_G, REG_ITMP1, REG_ITMP2); + emit_alul_imm_reg(cd, ALU_AND, -1 - (iptr->sx.val.i), REG_ITMP2); + emit_alul_reg_reg(cd, ALU_SUB, REG_ITMP2, REG_ITMP1); + emit_mov_reg_reg(cd, REG_ITMP1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + + case ICMD_LDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + OOPS(); +#if 0 + var1 = VAROP(iptr->s1); + var2 = VAROP(iptr->sx.s23.s2); + dst = VAROP(iptr->dst); + + d = codegen_reg_of_dst(jd, iptr, REG_NULL); + + if (IS_INMEMORY(var1->flags)) + M_LLD(RAX, REG_SP, var1->vv.regoff * 8); + else + M_INTMOVE(var1->vv.regoff, RAX); + + if (IS_INMEMORY(var2->flags)) + M_LLD(REG_ITMP3, REG_SP, var2->vv.regoff * 8); + else + M_INTMOVE(var2->vv.regoff, REG_ITMP3); + + if (checknull) { + M_TEST(REG_ITMP3); + M_BEQ(0); + codegen_add_arithmeticexception_ref(cd); + } + + /* check as described in jvm spec */ + disp = dseg_add_s8(cd, 0x8000000000000000LL); + M_LCMP_MEMBASE(RIP, -((cd->mcodeptr + 7) - cd->mcodebase) + disp, RAX); + M_BNE(4 + 6); + M_LCMP_IMM(-1, REG_ITMP3); /* 4 bytes */ + M_BEQ(3 + 2 + 3); /* 6 bytes */ + + M_MOV(RDX, REG_ITMP2); /* save %rdx, cause it's an argument register */ + emit_cqto(cd); + emit_idiv_reg(cd, REG_ITMP3); + + if (IS_INMEMORY(dst->flags)) { + M_LST(RAX, REG_SP, dst->vv.regoff * 8); + M_MOV(REG_ITMP2, RDX); /* restore %rdx */ + + } else { + M_INTMOVE(RAX, dst->vv.regoff); + + if (dst->vv.regoff != RDX) { + M_MOV(REG_ITMP2, RDX); /* restore %rdx */ + } + } +#endif + break; + + case ICMD_LREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + OOPS(); +#if 0 + var1 = VAROP(iptr->s1); + var2 = VAROP(iptr->sx.s23.s2); + dst = VAROP(iptr->dst); + + d = codegen_reg_of_dst(jd, iptr, REG_NULL); + + if (IS_INMEMORY(var1->flags)) + M_LLD(REG_ITMP1, REG_SP, var1->vv.regoff * 8); + else + M_INTMOVE(var1->vv.regoff, REG_ITMP1); + + if (IS_INMEMORY(var2->flags)) + M_LLD(REG_ITMP3, REG_SP, var2->vv.regoff * 8); + else + M_INTMOVE(var2->vv.regoff, REG_ITMP3); + /* + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP3); + M_INTMOVE(s2, REG_ITMP3); + */ + if (checknull) { + M_ITEST(REG_ITMP3); + M_BEQ(0); + codegen_add_arithmeticexception_ref(cd); + } + + M_MOV(RDX, REG_ITMP2); /* save %rdx, cause it's an argument register */ + + /* check as described in jvm spec */ + disp = dseg_add_s8(cd, 0x8000000000000000LL); + M_LCMP_MEMBASE(RIP, -((cd->mcodeptr + 7) - cd->mcodebase) + disp, REG_ITMP1); + M_BNE(3 + 4 + 6); + +#if 0 + emit_alul_reg_reg(cd, ALU_XOR, RDX, RDX); /* 2 bytes */ +#endif + M_LXOR(RDX, RDX); /* 3 bytes */ + M_LCMP_IMM(-1, REG_ITMP3); /* 4 bytes */ + M_BEQ(2 + 3); /* 6 bytes */ + + emit_cqto(cd); + emit_idiv_reg(cd, REG_ITMP3); + + if (IS_INMEMORY(dst->flags)) { + M_LST(RDX, REG_SP, dst->vv.regoff * 8); + M_MOV(REG_ITMP2, RDX); /* restore %rdx */ + + } else { + M_INTMOVE(RDX, dst->vv.regoff); + + if (dst->vv.regoff != RDX) { + M_MOV(REG_ITMP2, RDX); /* restore %rdx */ + } + } +#endif + break; + + case ICMD_LDIVPOW2: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_INTMOVE(s1, REG_ITMP1); + emit_alu_imm_reg(cd, ALU_CMP, -1, REG_ITMP1); + emit_lea_membase_reg(cd, REG_ITMP1, (1 << iptr->sx.val.i) - 1, REG_ITMP2); + emit_cmovcc_reg_reg(cd, CC_LE, REG_ITMP2, REG_ITMP1); + emit_shift_imm_reg(cd, SHIFT_SAR, iptr->sx.val.i, REG_ITMP1); + emit_mov_reg_reg(cd, REG_ITMP1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */ + /* sx.val.l = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_INTMOVE(s1, REG_ITMP1); + emit_alu_imm_reg(cd, ALU_CMP, -1, REG_ITMP1); + emit_lea_membase_reg(cd, REG_ITMP1, iptr->sx.val.i, REG_ITMP2); + emit_cmovcc_reg_reg(cd, CC_G, REG_ITMP1, REG_ITMP2); + emit_alu_imm_reg(cd, ALU_AND, -1 - (iptr->sx.val.i), REG_ITMP2); + emit_alu_reg_reg(cd, ALU_SUB, REG_ITMP2, REG_ITMP1); + emit_mov_reg_reg(cd, REG_ITMP1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_NULL); + emit_ishift(jd, SHIFT_SHL, iptr); +#endif + break; + + case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + M_ISLL_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_NULL); + emit_ishift(jd, SHIFT_SAR, iptr); +#endif + break; + + case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + M_INTMOVE(s1, d); + M_ISRA_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_NULL); + emit_ishift(jd, SHIFT_SHR, iptr); +#endif + break; + + case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + M_INTMOVE(s1, d); + M_ISRL_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_NULL); + emit_lshift(jd, SHIFT_SHL, iptr); +#endif + break; + + case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + M_LSLL_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_NULL); + emit_lshift(jd, SHIFT_SAR, iptr); +#endif + break; + + case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + M_INTMOVE(s1, d); + M_LSRA_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */ + OOPS(); +#if 0 + d = codegen_reg_of_dst(jd, iptr, REG_NULL); + emit_lshift(jd, SHIFT_SHR, iptr); +#endif + break; + + case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */ + /* sx.val.l = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + M_INTMOVE(s1, d); + M_LSRL_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) + M_IAND(s1, d); + else { + M_INTMOVE(s1, d); + M_IAND(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + M_IAND_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LAND: /* ..., val1, val2 ==> ..., val1 & val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) + M_LAND(s1, d); + else { + M_INTMOVE(s1, d); + M_LAND(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */ + /* sx.val.l = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + if (IS_IMM32(iptr->sx.val.l)) + M_LAND_IMM(iptr->sx.val.l, d); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LAND(REG_ITMP2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) + M_IOR(s1, d); + else { + M_INTMOVE(s1, d); + M_IOR(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IORCONST: /* ..., value ==> ..., value | constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + M_IOR_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LOR: /* ..., val1, val2 ==> ..., val1 | val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) + M_LOR(s1, d); + else { + M_INTMOVE(s1, d); + M_LOR(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LORCONST: /* ..., value ==> ..., value | constant */ + /* sx.val.l = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + if (IS_IMM32(iptr->sx.val.l)) + M_LOR_IMM(iptr->sx.val.l, d); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LOR(REG_ITMP2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) + M_IXOR(s1, d); + else { + M_INTMOVE(s1, d); + M_IXOR(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */ + /* sx.val.i = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + M_IXOR_IMM(iptr->sx.val.i, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s2 == d) + M_LXOR(s1, d); + else { + M_INTMOVE(s1, d); + M_LXOR(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */ + /* sx.val.l = constant */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, d); + if (IS_IMM32(iptr->sx.val.l)) + M_LXOR_IMM(iptr->sx.val.l, d); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LXOR(REG_ITMP2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + + /* floating operations ************************************************/ + + case ICMD_FNEG: /* ..., value ==> ..., - value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + disp = dseg_add_s4(cd, 0x80000000); + M_FLTMOVE(s1, d); + emit_movss_membase_reg(cd, RIP, -((cd->mcodeptr + 9) - cd->mcodebase) + disp, REG_FTMP2); + emit_xorps_reg_reg(cd, REG_FTMP2, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_DNEG: /* ..., value ==> ..., - value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + disp = dseg_add_s8(cd, 0x8000000000000000); + M_FLTMOVE(s1, d); + emit_movd_membase_reg(cd, RIP, -((cd->mcodeptr + 9) - cd->mcodebase) + disp, REG_FTMP2); + emit_xorpd_reg_reg(cd, REG_FTMP2, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + if (s2 == d) + M_FADD(s1, d); + else { + M_FLTMOVE(s1, d); + M_FADD(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + if (s2 == d) + M_DADD(s1, d); + else { + M_FLTMOVE(s1, d); + M_DADD(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + if (s2 == d) { + M_FLTMOVE(s2, REG_FTMP2); + s2 = REG_FTMP2; + } + M_FLTMOVE(s1, d); + M_FSUB(s2, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + if (s2 == d) { + M_FLTMOVE(s2, REG_FTMP2); + s2 = REG_FTMP2; + } + M_FLTMOVE(s1, d); + M_DSUB(s2, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + if (s2 == d) + M_FMUL(s1, d); + else { + M_FLTMOVE(s1, d); + M_FMUL(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + if (s2 == d) + M_DMUL(s1, d); + else { + M_FLTMOVE(s1, d); + M_DMUL(s2, d); + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + if (s2 == d) { + M_FLTMOVE(s2, REG_FTMP2); + s2 = REG_FTMP2; + } + M_FLTMOVE(s1, d); + M_FDIV(s2, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + if (s2 == d) { + M_FLTMOVE(s2, REG_FTMP2); + s2 = REG_FTMP2; + } + M_FLTMOVE(s1, d); + M_DDIV(s2, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_I2F: /* ..., value ==> ..., (float) value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_CVTIF(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_I2D: /* ..., value ==> ..., (double) value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_CVTID(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_L2F: /* ..., value ==> ..., (float) value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_CVTLF(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_L2D: /* ..., value ==> ..., (double) value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_CVTLD(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_F2I: /* ..., value ==> ..., (int) value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_CVTFI(s1, d); + M_ICMP_IMM(0x80000000, d); /* corner cases */ + disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 + + ((REG_RESULT == d) ? 0 : 3); + M_BNE(disp); + M_FLTMOVE(s1, REG_FTMP1); + M_MOV_IMM(asm_builtin_f2i, REG_ITMP2); + M_CALL(REG_ITMP2); + M_INTMOVE(REG_RESULT, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_D2I: /* ..., value ==> ..., (int) value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_CVTDI(s1, d); + M_ICMP_IMM(0x80000000, d); /* corner cases */ + disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 + + ((REG_RESULT == d) ? 0 : 3); + M_BNE(disp); + M_FLTMOVE(s1, REG_FTMP1); + M_MOV_IMM(asm_builtin_d2i, REG_ITMP2); + M_CALL(REG_ITMP2); + M_INTMOVE(REG_RESULT, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_F2L: /* ..., value ==> ..., (long) value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_CVTFL(s1, d); + M_MOV_IMM(0x8000000000000000, REG_ITMP2); + M_LCMP(REG_ITMP2, d); /* corner cases */ + disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 + + ((REG_RESULT == d) ? 0 : 3); + M_BNE(disp); + M_FLTMOVE(s1, REG_FTMP1); + M_MOV_IMM(asm_builtin_f2l, REG_ITMP2); + M_CALL(REG_ITMP2); + M_INTMOVE(REG_RESULT, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_D2L: /* ..., value ==> ..., (long) value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_CVTDL(s1, d); + M_MOV_IMM(0x8000000000000000, REG_ITMP2); + M_LCMP(REG_ITMP2, d); /* corner cases */ + disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 + + ((REG_RESULT == d) ? 0 : 3); + M_BNE(disp); + M_FLTMOVE(s1, REG_FTMP1); + M_MOV_IMM(asm_builtin_d2l, REG_ITMP2); + M_CALL(REG_ITMP2); + M_INTMOVE(REG_RESULT, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_F2D: /* ..., value ==> ..., (double) value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + M_CVTFD(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_D2F: /* ..., value ==> ..., (float) value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + M_CVTDF(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_FCMPL: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */ + /* == => 0, < => 1, > => -1 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_CLR(d); + M_MOV_IMM(1, REG_ITMP1); + M_MOV_IMM(-1, REG_ITMP2); + emit_ucomiss_reg_reg(cd, s1, s2); + M_CMOVB(REG_ITMP1, d); + M_CMOVA(REG_ITMP2, d); + M_CMOVP(REG_ITMP2, d); /* treat unordered as GT */ + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_FCMPG: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */ + /* == => 0, < => 1, > => -1 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_CLR(d); + M_MOV_IMM(1, REG_ITMP1); + M_MOV_IMM(-1, REG_ITMP2); + emit_ucomiss_reg_reg(cd, s1, s2); + M_CMOVB(REG_ITMP1, d); + M_CMOVA(REG_ITMP2, d); + M_CMOVP(REG_ITMP1, d); /* treat unordered as LT */ + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_DCMPL: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */ + /* == => 0, < => 1, > => -1 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_CLR(d); + M_MOV_IMM(1, REG_ITMP1); + M_MOV_IMM(-1, REG_ITMP2); + emit_ucomisd_reg_reg(cd, s1, s2); + M_CMOVB(REG_ITMP1, d); + M_CMOVA(REG_ITMP2, d); + M_CMOVP(REG_ITMP2, d); /* treat unordered as GT */ + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_DCMPG: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */ + /* == => 0, < => 1, > => -1 */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, REG_FTMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + M_CLR(d); + M_MOV_IMM(1, REG_ITMP1); + M_MOV_IMM(-1, REG_ITMP2); + emit_ucomisd_reg_reg(cd, s1, s2); + M_CMOVB(REG_ITMP1, d); + M_CMOVA(REG_ITMP2, d); + M_CMOVP(REG_ITMP1, d); /* treat unordered as LT */ + emit_store_dst(jd, iptr, d); +#endif + break; + + + /* memory operations **************************************************/ + + case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., (int) length */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + gen_nullptr_check(s1); + M_ILD(d, s1, OFFSET(java_arrayheader, size)); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_movsbq_memindex_reg(cd, OFFSET(java_bytearray, data[0]), s1, s2, 0, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_movzwq_memindex_reg(cd, OFFSET(java_chararray, data[0]), s1, s2, 1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_movswq_memindex_reg(cd, OFFSET(java_shortarray, data[0]), s1, s2, 1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_movl_memindex_reg(cd, OFFSET(java_intarray, data[0]), s1, s2, 2, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_mov_memindex_reg(cd, OFFSET(java_longarray, data[0]), s1, s2, 3, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_movss_memindex_reg(cd, OFFSET(java_floatarray, data[0]), s1, s2, 2, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_movsd_memindex_reg(cd, OFFSET(java_doublearray, data[0]), s1, s2, 3, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */ + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + emit_array_checks(cd, iptr, s1, s2); + M_SAADDQ(s2, s1, REG_ITMP1); + M_ALD(d, REG_ITMP1, OFFSET(java_objectarray, data[0])); + emit_store_dst(jd, iptr, d); + break; + + case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, REG_ITMP3); + emit_movb_reg_memindex(cd, s3, OFFSET(java_bytearray, data[0]), s1, s2, 0); +#endif + break; + + case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, REG_ITMP3); + emit_movw_reg_memindex(cd, s3, OFFSET(java_chararray, data[0]), s1, s2, 1); +#endif + break; + + case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, REG_ITMP3); + emit_movw_reg_memindex(cd, s3, OFFSET(java_shortarray, data[0]), s1, s2, 1); +#endif + break; + + case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, REG_ITMP3); + emit_movl_reg_memindex(cd, s3, OFFSET(java_intarray, data[0]), s1, s2, 2); +#endif + break; + + case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, REG_ITMP3); + emit_mov_reg_memindex(cd, s3, OFFSET(java_longarray, data[0]), s1, s2, 3); +#endif + break; + + case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, REG_FTMP3); + emit_movss_reg_memindex(cd, s3, OFFSET(java_floatarray, data[0]), s1, s2, 2); +#endif + break; + + case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, REG_FTMP3); + emit_movsd_reg_memindex(cd, s3, OFFSET(java_doublearray, data[0]), s1, s2, 3); +#endif + break; + + case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, REG_ITMP3); + + M_MOV(s1, REG_A0); + M_MOV(s3, REG_A1); + M_MOV_IMM(BUILTIN_canstore, REG_ITMP1); + M_CALL(REG_ITMP1); + M_TEST(REG_RESULT); + M_BEQ(0); + codegen_add_arraystoreexception_ref(cd); + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + s3 = emit_load_s3(jd, iptr, REG_ITMP3); + emit_mov_reg_memindex(cd, s3, OFFSET(java_objectarray, data[0]), s1, s2, 3); +#endif + break; + + + case ICMD_BASTORECONST: /* ..., arrayref, index ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_movb_imm_memindex(cd, iptr->sx.s23.s3.constval, OFFSET(java_bytearray, data[0]), s1, s2, 0); +#endif + break; + + case ICMD_CASTORECONST: /* ..., arrayref, index ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_movw_imm_memindex(cd, iptr->sx.s23.s3.constval, OFFSET(java_chararray, data[0]), s1, s2, 1); +#endif + break; + + case ICMD_SASTORECONST: /* ..., arrayref, index ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_movw_imm_memindex(cd, iptr->sx.s23.s3.constval, OFFSET(java_shortarray, data[0]), s1, s2, 1); +#endif + break; + + case ICMD_IASTORECONST: /* ..., arrayref, index ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_movl_imm_memindex(cd, iptr->sx.s23.s3.constval, OFFSET(java_intarray, data[0]), s1, s2, 2); +#endif + break; + + case ICMD_LASTORECONST: /* ..., arrayref, index ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + + if (IS_IMM32(iptr->sx.s23.s3.constval)) { + emit_mov_imm_memindex(cd, (u4) (iptr->sx.s23.s3.constval & 0x00000000ffffffff), OFFSET(java_longarray, data[0]), s1, s2, 3); + } else { + emit_movl_imm_memindex(cd, (u4) (iptr->sx.s23.s3.constval & 0x00000000ffffffff), OFFSET(java_longarray, data[0]), s1, s2, 3); + emit_movl_imm_memindex(cd, (u4) (iptr->sx.s23.s3.constval >> 32), OFFSET(java_longarray, data[0]) + 4, s1, s2, 3); + } +#endif + break; + + case ICMD_AASTORECONST: /* ..., arrayref, index ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + if (INSTRUCTION_MUST_CHECK(iptr)) { + gen_nullptr_check(s1); + gen_bound_check; + } + emit_mov_imm_memindex(cd, 0, OFFSET(java_objectarray, data[0]), s1, s2, 3); +#endif + break; + + + case ICMD_GETSTATIC: /* ... ==> ..., value */ + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + uf = iptr->sx.s23.s3.uf; + fieldtype = uf->fieldref->parseddesc.fd->type; + disp = dseg_add_unique_address(cd, NULL); + + /* must be calculated before codegen_add_patch_ref */ + + if (opt_shownops) + disp -= PATCHER_CALL_SIZE; + +/* PROFILE_CYCLE_STOP; */ + + codegen_add_patch_ref(cd, PATCHER_get_putstatic, uf, disp); + +/* PROFILE_CYCLE_START; */ + } + else { + fi = iptr->sx.s23.s3.fmiref->p.field; + fieldtype = fi->type; + disp = dseg_add_address(cd, &(fi->value)); + + if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) { + PROFILE_CYCLE_STOP; + + codegen_add_patch_ref(cd, PATCHER_clinit, fi->class, 0); + + if (opt_shownops) + disp -= PATCHER_CALL_SIZE; + + PROFILE_CYCLE_START; + } + } + + M_ALD(REG_ITMP1, REG_PV, disp); + + switch (fieldtype) { + case TYPE_INT: + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + M_ILD(d, REG_ITMP1, 0); + break; + case TYPE_LNG: + d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED); + M_LLD(d, REG_ITMP1, 0); + break; + case TYPE_ADR: + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + M_ALD(d, REG_ITMP1, 0); + break; + case TYPE_FLT: + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_FLD(d, REG_ITMP1, 0); + break; + case TYPE_DBL: + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_DLD(d, REG_ITMP1, 0); + break; + } + + emit_store_dst(jd, iptr, d); + + break; + + case ICMD_PUTSTATIC: /* ..., value ==> ... */ + OOPS(); +#if 0 + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + uf = iptr->sx.s23.s3.uf; + fieldtype = uf->fieldref->parseddesc.fd->type; + disp = dseg_add_unique_address(cd, NULL); + disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp; + + /* must be calculated before codegen_add_patch_ref */ + + if (opt_shownops) + disp -= PATCHER_CALL_SIZE; + +/* PROFILE_CYCLE_STOP; */ + + codegen_add_patch_ref(cd, PATCHER_get_putstatic, uf, disp); + +/* PROFILE_CYCLE_START; */ + } + else { + fi = iptr->sx.s23.s3.fmiref->p.field; + fieldtype = fi->type; + disp = dseg_add_address(cd, &(fi->value)); + disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp; + + if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) { + PROFILE_CYCLE_STOP; + + codegen_add_patch_ref(cd, PATCHER_clinit, fi->class, 0); + + if (opt_shownops) + disp -= PATCHER_CALL_SIZE; + + PROFILE_CYCLE_START; + } + } + + /* This approach is much faster than moving the field + address inline into a register. */ + + M_ALD(REG_ITMP1, RIP, disp); + + switch (fieldtype) { + case TYPE_INT: + s1 = emit_load_s1(jd, iptr, REG_ITMP2); + M_IST(s1, REG_ITMP1, 0); + break; + case TYPE_LNG: + case TYPE_ADR: + s1 = emit_load_s1(jd, iptr, REG_ITMP2); + M_LST(s1, REG_ITMP1, 0); + break; + case TYPE_FLT: + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + M_FST(s1, REG_ITMP1, 0); + break; + case TYPE_DBL: + s1 = emit_load_s1(jd, iptr, REG_FTMP1); + M_DST(s1, REG_ITMP1, 0); + break; + } +#endif + break; + + case ICMD_PUTSTATICCONST: /* ... ==> ... */ + /* val = value (in current instruction) */ + /* following NOP) */ + OOPS(); +#if 0 + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + uf = iptr->sx.s23.s3.uf; + fieldtype = uf->fieldref->parseddesc.fd->type; + disp = dseg_add_unique_address(cd, NULL); + disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp; + + /* must be calculated before codegen_add_patch_ref */ + + if (opt_shownops) + disp -= PATCHER_CALL_SIZE; + + +/* PROFILE_CYCLE_STOP; */ + + codegen_add_patch_ref(cd, PATCHER_get_putstatic, uf, disp); + +/* PROFILE_CYCLE_START; */ + } + else { + fi = iptr->sx.s23.s3.fmiref->p.field; + fieldtype = fi->type; + disp = dseg_add_address(cd, &(fi->value)); + disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp; + + if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) { + PROFILE_CYCLE_STOP; + + codegen_add_patch_ref(cd, PATCHER_clinit, fi->class, 0); + + if (opt_shownops) + disp -= PATCHER_CALL_SIZE; + + PROFILE_CYCLE_START; + } + } + + /* This approach is much faster than moving the field + address inline into a register. */ + + M_ALD(REG_ITMP1, RIP, disp); + + switch (fieldtype) { + case TYPE_INT: + case TYPE_FLT: + M_IST_IMM(iptr->sx.s23.s2.constval, REG_ITMP1, 0); + break; + case TYPE_LNG: + case TYPE_ADR: + case TYPE_DBL: + if (IS_IMM32(iptr->sx.s23.s2.constval)) + M_LST_IMM32(iptr->sx.s23.s2.constval, REG_ITMP1, 0); + else { + M_IST_IMM(iptr->sx.s23.s2.constval, REG_ITMP1, 0); + M_IST_IMM(iptr->sx.s23.s2.constval >> 32, REG_ITMP1, 4); + } + break; + } +#endif + break; + + case ICMD_GETFIELD: /* ... ==> ..., value */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + gen_nullptr_check(s1); + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + uf = iptr->sx.s23.s3.uf; + fieldtype = uf->fieldref->parseddesc.fd->type; + disp = 0; + +/* PROFILE_CYCLE_STOP; */ + + codegen_add_patch_ref(cd, PATCHER_get_putfield, uf, 0); + +/* PROFILE_CYCLE_START; */ + } + else { + fi = iptr->sx.s23.s3.fmiref->p.field; + fieldtype = fi->type; + disp = fi->offset; + } + + switch (fieldtype) { + case TYPE_INT: + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_ILD32(d, s1, disp); + break; + case TYPE_LNG: + case TYPE_ADR: + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + M_LLD32(d, s1, disp); + break; + case TYPE_FLT: + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_FLD32(d, s1, disp); + break; + case TYPE_DBL: + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_DLD32(d, s1, disp); + break; + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_PUTFIELD: /* ..., objectref, value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + gen_nullptr_check(s1); + + s2 = emit_load_s2(jd, iptr, REG_IFTMP); + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + uf = iptr->sx.s23.s3.uf; + fieldtype = uf->fieldref->parseddesc.fd->type; + disp = 0; + +/* PROFILE_CYCLE_STOP; */ + + codegen_add_patch_ref(cd, PATCHER_get_putfield, uf, 0); + +/* PROFILE_CYCLE_START; */ + } + else { + fi = iptr->sx.s23.s3.fmiref->p.field; + fieldtype = fi->type; + disp = fi->offset; + } + + switch (fieldtype) { + case TYPE_INT: + M_IST32(s2, s1, disp); + break; + case TYPE_LNG: + case TYPE_ADR: + M_LST32(s2, s1, disp); + break; + case TYPE_FLT: + M_FST32(s2, s1, disp); + break; + case TYPE_DBL: + M_DST32(s2, s1, disp); + break; + } +#endif + break; + + case ICMD_PUTFIELDCONST: /* ..., objectref, value ==> ... */ + /* val = value (in current instruction) */ + /* following NOP) */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + gen_nullptr_check(s1); + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + uf = iptr->sx.s23.s3.uf; + fieldtype = uf->fieldref->parseddesc.fd->type; + disp = 0; + +/* PROFILE_CYCLE_STOP; */ + + codegen_add_patch_ref(cd, PATCHER_putfieldconst, uf, 0); + +/* PROFILE_CYCLE_START; */ + } + else { + fi = iptr->sx.s23.s3.fmiref->p.field; + fieldtype = fi->type; + disp = fi->offset; + } + + switch (fieldtype) { + case TYPE_INT: + case TYPE_FLT: + M_IST32_IMM(iptr->sx.s23.s2.constval, s1, disp); + break; + case TYPE_LNG: + case TYPE_ADR: + case TYPE_DBL: + /* XXX why no check for IS_IMM32? */ + M_IST32_IMM(iptr->sx.s23.s2.constval, s1, disp); + M_IST32_IMM(iptr->sx.s23.s2.constval >> 32, s1, disp + 4); + break; + } +#endif + break; + + + /* branch operations **************************************************/ + + case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, REG_ITMP1_XPTR); + + PROFILE_CYCLE_STOP; + +#ifdef ENABLE_VERIFIER + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + uc = iptr->sx.s23.s2.uc; + + codegen_add_patch_ref(cd, PATCHER_athrow_areturn, uc, 0); + } +#endif /* ENABLE_VERIFIER */ + + M_CALL_IMM(0); /* passing exception pc */ + M_POP(REG_ITMP2_XPC); + + M_MOV_IMM(asm_handle_exception, REG_ITMP3); + M_JMP(REG_ITMP3); +#endif + break; + + case ICMD_GOTO: /* ... ==> ... */ + case ICMD_RET: /* ... ==> ... */ + OOPS(); +#if 0 + M_JMP_IMM(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_JSR: /* ... ==> ... */ + OOPS(); +#if 0 + M_JMP_IMM(0); + codegen_add_branch_ref(cd, iptr->sx.s23.s3.jsrtarget.block); +#endif + break; + + case ICMD_IFNULL: /* ..., value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_TEST(s1); + M_BEQ(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IFNONNULL: /* ..., value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_TEST(s1); + M_BNE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IFEQ: /* ..., value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_ICMP_IMM(iptr->sx.val.i, s1); + M_BEQ(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IFLT: /* ..., value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_ICMP_IMM(iptr->sx.val.i, s1); + M_BLT(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IFLE: /* ..., value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_ICMP_IMM(iptr->sx.val.i, s1); + M_BLE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IFNE: /* ..., value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_ICMP_IMM(iptr->sx.val.i, s1); + M_BNE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IFGT: /* ..., value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_ICMP_IMM(iptr->sx.val.i, s1); + M_BGT(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IFGE: /* ..., value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_ICMP_IMM(iptr->sx.val.i, s1); + M_BGE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LEQ: /* ..., value ==> ... */ + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + if (IS_IMM32(iptr->sx.val.l)) + M_LCMP_IMM(iptr->sx.val.l, s1); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LCMP(REG_ITMP2, s1); + } + M_BEQ(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LLT: /* ..., value ==> ... */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + if (IS_IMM32(iptr->sx.val.l)) + M_LCMP_IMM(iptr->sx.val.l, s1); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LCMP(REG_ITMP2, s1); + } + M_BLT(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LLE: /* ..., value ==> ... */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + if (IS_IMM32(iptr->sx.val.l)) + M_LCMP_IMM(iptr->sx.val.l, s1); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LCMP(REG_ITMP2, s1); + } + M_BLE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LNE: /* ..., value ==> ... */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + if (IS_IMM32(iptr->sx.val.l)) + M_LCMP_IMM(iptr->sx.val.l, s1); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LCMP(REG_ITMP2, s1); + } + M_BNE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LGT: /* ..., value ==> ... */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + if (IS_IMM32(iptr->sx.val.l)) + M_LCMP_IMM(iptr->sx.val.l, s1); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LCMP(REG_ITMP2, s1); + } + M_BGT(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LGE: /* ..., value ==> ... */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + if (IS_IMM32(iptr->sx.val.l)) + M_LCMP_IMM(iptr->sx.val.l, s1); + else { + M_MOV_IMM(iptr->sx.val.l, REG_ITMP2); + M_LCMP(REG_ITMP2, s1); + } + M_BGE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_ICMP(s2, s1); + M_BEQ(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LCMPEQ: /* ..., value, value ==> ... */ + case ICMD_IF_ACMPEQ: /* op1 = target JavaVM pc */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_LCMP(s2, s1); + M_BEQ(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_ICMPNE: /* ..., value, value ==> ... */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_ICMP(s2, s1); + M_BNE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LCMPNE: /* ..., value, value ==> ... */ + case ICMD_IF_ACMPNE: /* op1 = target JavaVM pc */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_LCMP(s2, s1); + M_BNE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_ICMP(s2, s1); + M_BLT(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LCMPLT: /* ..., value, value ==> ... */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_LCMP(s2, s1); + M_BLT(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */ + OOPS(); +#if 0 + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_ICMP(s2, s1); + M_BGT(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LCMPGT: /* ..., value, value ==> ... */ + + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_LCMP(s2, s1); + M_BGT(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */ + + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_ICMP(s2, s1); + M_BLE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LCMPLE: /* ..., value, value ==> ... */ + + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_LCMP(s2, s1); + M_BLE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */ + + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_ICMP(s2, s1); + M_BGE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IF_LCMPGE: /* ..., value, value ==> ... */ + + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + M_LCMP(s2, s1); + M_BGE(0); + codegen_add_branch_ref(cd, iptr->dst.block); +#endif + break; + + case ICMD_IRETURN: /* ..., retvalue ==> ... */ + case ICMD_LRETURN: + + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_RESULT); + M_INTMOVE(s1, REG_RESULT); +#endif + goto nowperformreturn; + + case ICMD_ARETURN: /* ..., retvalue ==> ... */ + + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_RESULT); + M_INTMOVE(s1, REG_RESULT); + +#ifdef ENABLE_VERIFIER + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + uc = iptr->sx.s23.s2.uc; + + PROFILE_CYCLE_STOP; + + codegen_add_patch_ref(cd, PATCHER_athrow_areturn, uc, 0); + + PROFILE_CYCLE_START; + } +#endif /* ENABLE_VERIFIER */ +#endif + goto nowperformreturn; + + case ICMD_FRETURN: /* ..., retvalue ==> ... */ + case ICMD_DRETURN: + + OOPS(); +#if 0 + s1 = emit_load_s1(jd, iptr, REG_FRESULT); + M_FLTMOVE(s1, REG_FRESULT); +#endif + goto nowperformreturn; + + case ICMD_RETURN: /* ... ==> ... */ + +nowperformreturn: + OOPS(); +#if 0 + { + s4 i, p; + + p = cd->stackframesize; + +#if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + emit_verbosecall_exit(jd); +#endif /* !defined(NDEBUG) */ + +#if defined(ENABLE_THREADS) + if (checksync && (m->flags & ACC_SYNCHRONIZED)) { + M_ALD(REG_A0, REG_SP, rd->memuse * 8); + + /* we need to save the proper return value */ + switch (iptr->opc) { + case ICMD_IRETURN: + case ICMD_ARETURN: + case ICMD_LRETURN: + M_LST(REG_RESULT, REG_SP, rd->memuse * 8); + break; + case ICMD_FRETURN: + case ICMD_DRETURN: + M_DST(REG_FRESULT, REG_SP, rd->memuse * 8); + break; + } + + M_MOV_IMM(LOCK_monitor_exit, REG_ITMP1); + M_CALL(REG_ITMP1); + + /* and now restore the proper return value */ + switch (iptr->opc) { + case ICMD_IRETURN: + case ICMD_ARETURN: + case ICMD_LRETURN: + M_LLD(REG_RESULT, REG_SP, rd->memuse * 8); + break; + case ICMD_FRETURN: + case ICMD_DRETURN: + M_DLD(REG_FRESULT, REG_SP, rd->memuse * 8); + break; + } + } +#endif + + /* restore saved registers */ + + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_LLD(rd->savintregs[i], REG_SP, p * 8); + } + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); + } + + /* deallocate stack */ + + if (cd->stackframesize) + M_AADD_IMM(cd->stackframesize * 8, REG_SP); + + /* generate method profiling code */ + + PROFILE_CYCLE_STOP; + + M_RET; + } +#endif + break; + + + case ICMD_TABLESWITCH: /* ..., index ==> ... */ + OOPS(); +#if 0 + { + s4 i, l; + branch_target_t *table; + + table = iptr->dst.table; + + l = iptr->sx.s23.s2.tablelow; + i = iptr->sx.s23.s3.tablehigh; + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_INTMOVE(s1, REG_ITMP1); + + if (l != 0) + M_ISUB_IMM(l, REG_ITMP1); + + /* number of targets */ + i = i - l + 1; + + /* range check */ + M_ICMP_IMM(i - 1, REG_ITMP1); + M_BA(0); + + codegen_add_branch_ref(cd, table[0].block); /* default target */ + + /* build jump table top down and use address of lowest entry */ + + table += i; + + while (--i >= 0) { + dseg_add_target(cd, table->block); + --table; + } + + /* length of dataseg after last dseg_add_target is used + by load */ + + M_MOV_IMM(0, REG_ITMP2); + dseg_adddata(cd); + emit_mov_memindex_reg(cd, -(cd->dseglen), REG_ITMP2, REG_ITMP1, 3, REG_ITMP1); + M_JMP(REG_ITMP1); + } +#endif + break; + + + case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ + OOPS(); +#if 0 + { + s4 i; + lookup_target_t *lookup; + + lookup = iptr->dst.lookup; + + i = iptr->sx.s23.s2.lookupcount; + + MCODECHECK(8 + ((7 + 6) * i) + 5); + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + + while (--i >= 0) { + M_ICMP_IMM(lookup->value, s1); + M_BEQ(0); + codegen_add_branch_ref(cd, lookup->target.block); + lookup++; + } + + M_JMP_IMM(0); + + codegen_add_branch_ref(cd, iptr->sx.s23.s3.lookupdefault.block); + } +#endif + break; + + + case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ + OOPS(); +#if 0 + + bte = iptr->sx.s23.s3.bte; + md = bte->md; +#endif + goto gen_method; + + case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ + case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ + case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ + case ICMD_INVOKEINTERFACE: + OOPS(); +#if 0 + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + lm = NULL; + um = iptr->sx.s23.s3.um; + md = um->methodref->parseddesc.md; + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + um = NULL; + md = lm->parseddesc; + } +#endif +gen_method: +#if 0 + s3 = md->paramcount; + + MCODECHECK((20 * s3) + 128); + + /* copy arguments to registers or stack location */ + + for (s3 = s3 - 1; s3 >= 0; s3--) { + var = VAR(iptr->sx.s23.s2.args[s3]); + + /* Already Preallocated (ARGVAR) ? */ + if (var->flags & PREALLOC) + continue; + + if (IS_INT_LNG_TYPE(var->type)) { + if (!md->params[s3].inmemory) { + s1 = rd->argintregs[md->params[s3].regoff]; + d = emit_load(jd, iptr, var, s1); + M_INTMOVE(d, s1); + } + else { + d = emit_load(jd, iptr, var, REG_ITMP1); + M_LST(d, REG_SP, md->params[s3].regoff * 8); + } + } + else { + if (!md->params[s3].inmemory) { + s1 = rd->argfltregs[md->params[s3].regoff]; + d = emit_load(jd, iptr, var, s1); + M_FLTMOVE(d, s1); + } + else { + d = emit_load(jd, iptr, var, REG_FTMP1); + + if (IS_2_WORD_TYPE(var->type)) + M_DST(d, REG_SP, md->params[s3].regoff * 8); + else + M_FST(d, REG_SP, md->params[s3].regoff * 8); + } + } + } + + /* generate method profiling code */ + + PROFILE_CYCLE_STOP; + + switch (iptr->opc) { + case ICMD_BUILTIN: + M_MOV_IMM(bte->fp, REG_ITMP1); + M_CALL(REG_ITMP1); + + if (INSTRUCTION_MUST_CHECK(iptr)) { + M_TEST(REG_RESULT); + M_BEQ(0); + codegen_add_fillinstacktrace_ref(cd); + } + break; + + case ICMD_INVOKESPECIAL: + M_TEST(REG_A0); + M_BEQ(0); + codegen_add_nullpointerexception_ref(cd); + + /* fall through */ + + case ICMD_INVOKESTATIC: + if (lm == NULL) { + disp = dseg_add_unique_address(cd, NULL); + disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp; + + /* must be calculated before codegen_add_patch_ref */ + + if (opt_shownops) + disp -= PATCHER_CALL_SIZE; + + codegen_add_patch_ref(cd, PATCHER_invokestatic_special, + um, disp); + +/* a = 0; */ + } + else { + disp = dseg_add_functionptr(cd, lm->stubroutine); + disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp; + +/* a = (ptrint) lm->stubroutine; */ + } + +/* M_MOV_IMM(a, REG_ITMP2); */ + M_ALD(REG_ITMP2, RIP, disp); + M_CALL(REG_ITMP2); + break; + + case ICMD_INVOKEVIRTUAL: + gen_nullptr_check(REG_A0); + + if (lm == NULL) { + codegen_add_patch_ref(cd, PATCHER_invokevirtual, um, 0); + + s1 = 0; + } + else + s1 = OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * lm->vftblindex; + + M_ALD(REG_METHODPTR, REG_A0, + OFFSET(java_objectheader, vftbl)); + M_ALD32(REG_ITMP3, REG_METHODPTR, s1); + M_CALL(REG_ITMP3); + break; + + case ICMD_INVOKEINTERFACE: + gen_nullptr_check(REG_A0); + + if (lm == NULL) { + codegen_add_patch_ref(cd, PATCHER_invokeinterface, um, 0); + + s1 = 0; + s2 = 0; + } + else { + s1 = OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr) * lm->class->index; + + s2 = sizeof(methodptr) * (lm - lm->class->methods); + } + + M_ALD(REG_METHODPTR, REG_A0, + OFFSET(java_objectheader, vftbl)); + M_ALD32(REG_METHODPTR, REG_METHODPTR, s1); + M_ALD32(REG_ITMP3, REG_METHODPTR, s2); + M_CALL(REG_ITMP3); + break; + } + + /* generate method profiling code */ + + PROFILE_CYCLE_START; + + /* store return value */ + + d = md->returntype.type; + + if (d != TYPE_VOID) { + if (IS_INT_LNG_TYPE(d)) { + s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); + M_INTMOVE(REG_RESULT, s1); + } + else { + s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); + M_FLTMOVE(REG_FRESULT, s1); + } + emit_store_dst(jd, iptr, s1); + } +#endif + break; + + + case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ + OOPS(); +#if 0 + + /* val.a: (classinfo *) superclass */ + + /* superclass is an interface: + * + * OK if ((sub == NULL) || + * (sub->vftbl->interfacetablelength > super->index) && + * (sub->vftbl->interfacetable[-super->index] != NULL)); + * + * superclass is a class: + * + * OK if ((sub == NULL) || (0 + * <= (sub->vftbl->baseval - super->vftbl->baseval) <= + * super->vftbl->diffval)); + */ + + if (!(iptr->flags.bits & INS_FLAG_ARRAY)) { + /* object type cast-check */ + + classinfo *super; + vftbl_t *supervftbl; + s4 superindex; + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + super = NULL; + superindex = 0; + supervftbl = NULL; + } + else { + super = iptr->sx.s23.s3.c.cls; + superindex = super->index; + supervftbl = super->vftbl; + } + +#if defined(ENABLE_THREADS) + codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase); +#endif + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + + /* calculate interface checkcast code size */ + + s2 = 3; /* mov_membase_reg */ + CALCOFFSETBYTES(s2, s1, OFFSET(java_objectheader, vftbl)); + + s2 += 3 + 4 /* movl_membase32_reg */ + 3 + 4 /* sub imm32 */ + + 3 /* test */ + 6 /* jcc */ + 3 + 4 /* mov_membase32_reg */ + + 3 /* test */ + 6 /* jcc */; + + if (super == NULL) + s2 += (opt_shownops ? 5 : 0); + + /* calculate class checkcast code size */ + + s3 = 3; /* mov_membase_reg */ + CALCOFFSETBYTES(s3, s1, OFFSET(java_objectheader, vftbl)); + s3 += 10 /* mov_imm_reg */ + 3 + 4 /* movl_membase32_reg */; + +#if 0 + if (s1 != REG_ITMP1) { + a += 3; /* movl_membase_reg - only if REG_ITMP3 == R11 */ + CALCOFFSETBYTES(a, REG_ITMP3, OFFSET(vftbl_t, baseval)); + a += 3; /* movl_membase_reg - only if REG_ITMP3 == R11 */ + CALCOFFSETBYTES(a, REG_ITMP3, OFFSET(vftbl_t, diffval)); + a += 3; /* sub */ + + } else +#endif + { + s3 += 3 + 4 /* movl_membase32_reg */ + 3 /* sub */ + + 10 /* mov_imm_reg */ + 3 /* movl_membase_reg */; + CALCOFFSETBYTES(s3, REG_ITMP3, OFFSET(vftbl_t, diffval)); + } + + s3 += 3 /* cmp */ + 6 /* jcc */; + + if (super == NULL) + s3 += (opt_shownops ? 5 : 0); + + /* if class is not resolved, check which code to call */ + + if (super == NULL) { + M_TEST(s1); + M_BEQ(6 + (opt_shownops ? 5 : 0) + 7 + 6 + s2 + 5 + s3); + + codegen_add_patch_ref(cd, PATCHER_checkcast_instanceof_flags, + iptr->sx.s23.s3.c.ref, 0); + + M_IMOV_IMM(0, REG_ITMP2); /* super->flags */ + M_IAND_IMM(ACC_INTERFACE, REG_ITMP2); + M_BEQ(s2 + 5); + } + + /* interface checkcast code */ + + if ((super == NULL) || (super->flags & ACC_INTERFACE)) { + if (super != NULL) { + M_TEST(s1); + M_BEQ(s2); + } + + M_ALD(REG_ITMP2, s1, OFFSET(java_objectheader, vftbl)); + + if (super == NULL) { + codegen_add_patch_ref(cd, + PATCHER_checkcast_instanceof_interface, + iptr->sx.s23.s3.c.ref, + 0); + } + + emit_movl_membase32_reg(cd, REG_ITMP2, + OFFSET(vftbl_t, interfacetablelength), + REG_ITMP3); + /* XXX TWISTI: should this be int arithmetic? */ + M_LSUB_IMM32(superindex, REG_ITMP3); + M_TEST(REG_ITMP3); + M_BLE(0); + codegen_add_classcastexception_ref(cd, s1); + emit_mov_membase32_reg(cd, REG_ITMP2, + OFFSET(vftbl_t, interfacetable[0]) - + superindex * sizeof(methodptr*), + REG_ITMP3); + M_TEST(REG_ITMP3); + M_BEQ(0); + codegen_add_classcastexception_ref(cd, s1); + + if (super == NULL) + M_JMP_IMM(s3); + } + + /* class checkcast code */ + + if ((super == NULL) || !(super->flags & ACC_INTERFACE)) { + if (super != NULL) { + M_TEST(s1); + M_BEQ(s3); + } + + M_ALD(REG_ITMP2, s1, OFFSET(java_objectheader, vftbl)); + + if (super == NULL) { + codegen_add_patch_ref(cd, PATCHER_checkcast_class, + iptr->sx.s23.s3.c.ref, + 0); + } + + M_MOV_IMM(supervftbl, REG_ITMP3); +#if defined(ENABLE_THREADS) + codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase); +#endif + emit_movl_membase32_reg(cd, REG_ITMP2, + OFFSET(vftbl_t, baseval), + REG_ITMP2); + /* if (s1 != REG_ITMP1) { */ + /* emit_movl_membase_reg(cd, REG_ITMP3, */ + /* OFFSET(vftbl_t, baseval), */ + /* REG_ITMP1); */ + /* emit_movl_membase_reg(cd, REG_ITMP3, */ + /* OFFSET(vftbl_t, diffval), */ + /* REG_ITMP3); */ + /* #if defined(ENABLE_THREADS) */ + /* codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); */ + /* #endif */ + /* emit_alu_reg_reg(cd, ALU_SUB, REG_ITMP1, REG_ITMP2); */ + + /* } else { */ + emit_movl_membase32_reg(cd, REG_ITMP3, + OFFSET(vftbl_t, baseval), + REG_ITMP3); + M_LSUB(REG_ITMP3, REG_ITMP2); + M_MOV_IMM(supervftbl, REG_ITMP3); + M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval)); + /* } */ +#if defined(ENABLE_THREADS) + codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); +#endif + M_LCMP(REG_ITMP3, REG_ITMP2); + M_BA(0); /* (u) REG_ITMP1 > (u) REG_ITMP2 -> jump */ + codegen_add_classcastexception_ref(cd, s1); + } + + d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); + } + else { + /* array type cast-check */ + + s1 = emit_load_s1(jd, iptr, REG_ITMP2); + M_INTMOVE(s1, REG_A0); + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + codegen_add_patch_ref(cd, PATCHER_builtin_arraycheckcast, + iptr->sx.s23.s3.c.ref, 0); + } + + M_MOV_IMM(iptr->sx.s23.s3.c.cls, REG_A1); + M_MOV_IMM(BUILTIN_arraycheckcast, REG_ITMP1); + M_CALL(REG_ITMP1); + + /* s1 may have been destroyed over the function call */ + s1 = emit_load_s1(jd, iptr, REG_ITMP2); + M_TEST(REG_RESULT); + M_BEQ(0); + codegen_add_classcastexception_ref(cd, s1); + + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + } + + M_INTMOVE(s1, d); + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */ + OOPS(); +#if 0 + + /* val.a: (classinfo *) superclass */ + + /* superclass is an interface: + * + * return (sub != NULL) && + * (sub->vftbl->interfacetablelength > super->index) && + * (sub->vftbl->interfacetable[-super->index] != NULL); + * + * superclass is a class: + * + * return ((sub != NULL) && (0 + * <= (sub->vftbl->baseval - super->vftbl->baseval) <= + * super->vftbl->diffvall)); + */ + + { + classinfo *super; + vftbl_t *supervftbl; + s4 superindex; + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + super = NULL; + superindex = 0; + supervftbl = NULL; + + } else { + super = iptr->sx.s23.s3.c.cls; + superindex = super->index; + supervftbl = super->vftbl; + } + +#if defined(ENABLE_THREADS) + codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase); +#endif + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + if (s1 == d) { + M_INTMOVE(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + + /* calculate interface instanceof code size */ + + s2 = 3; /* mov_membase_reg */ + CALCOFFSETBYTES(s2, s1, OFFSET(java_objectheader, vftbl)); + s2 += 3 + 4 /* movl_membase32_reg */ + 3 + 4 /* sub_imm32 */ + + 3 /* test */ + 6 /* jcc */ + 3 + 4 /* mov_membase32_reg */ + + 3 /* test */ + 4 /* setcc */; + + if (!super) + s2 += (opt_shownops ? 5 : 0); + + /* calculate class instanceof code size */ + + s3 = 3; /* mov_membase_reg */ + CALCOFFSETBYTES(s3, s1, OFFSET(java_objectheader, vftbl)); + s3 += 10; /* mov_imm_reg */ + s3 += 2; /* movl_membase_reg - only if REG_ITMP1 == RAX */ + CALCOFFSETBYTES(s3, REG_ITMP1, OFFSET(vftbl_t, baseval)); + s3 += 3; /* movl_membase_reg - only if REG_ITMP2 == R10 */ + CALCOFFSETBYTES(s3, REG_ITMP2, OFFSET(vftbl_t, baseval)); + s3 += 3; /* movl_membase_reg - only if REG_ITMP2 == R10 */ + CALCOFFSETBYTES(s3, REG_ITMP2, OFFSET(vftbl_t, diffval)); + s3 += 3 /* sub */ + 3 /* xor */ + 3 /* cmp */ + 4 /* setcc */; + + if (super == NULL) + s3 += (opt_shownops ? 5 : 0); + + emit_alu_reg_reg(cd, ALU_XOR, d, d); + + /* if class is not resolved, check which code to call */ + + if (super == NULL) { + emit_test_reg_reg(cd, s1, s1); + emit_jcc(cd, CC_Z, (6 + (opt_shownops ? 5 : 0) + + 7 + 6 + s2 + 5 + s3)); + + codegen_add_patch_ref(cd, PATCHER_checkcast_instanceof_flags, + iptr->sx.s23.s3.c.ref, 0); + + emit_movl_imm_reg(cd, 0, REG_ITMP3); /* super->flags */ + emit_alul_imm_reg(cd, ALU_AND, ACC_INTERFACE, REG_ITMP3); + emit_jcc(cd, CC_Z, s2 + 5); + } + + /* interface instanceof code */ + + if ((super == NULL) || (super->flags & ACC_INTERFACE)) { + if (super != NULL) { + emit_test_reg_reg(cd, s1, s1); + emit_jcc(cd, CC_Z, s2); + } + + emit_mov_membase_reg(cd, s1, + OFFSET(java_objectheader, vftbl), + REG_ITMP1); + + if (super == NULL) { + codegen_add_patch_ref(cd, + PATCHER_checkcast_instanceof_interface, + iptr->sx.s23.s3.c.ref, 0); + } + + emit_movl_membase32_reg(cd, REG_ITMP1, + OFFSET(vftbl_t, interfacetablelength), + REG_ITMP3); + emit_alu_imm32_reg(cd, ALU_SUB, superindex, REG_ITMP3); + emit_test_reg_reg(cd, REG_ITMP3, REG_ITMP3); + + a = 3 + 4 /* mov_membase32_reg */ + 3 /* test */ + 4 /* setcc */; + + emit_jcc(cd, CC_LE, a); + emit_mov_membase32_reg(cd, REG_ITMP1, + OFFSET(vftbl_t, interfacetable[0]) - + superindex * sizeof(methodptr*), + REG_ITMP1); + emit_test_reg_reg(cd, REG_ITMP1, REG_ITMP1); + emit_setcc_reg(cd, CC_NE, d); + + if (!super) + emit_jmp_imm(cd, s3); + } + + /* class instanceof code */ + + if ((super == NULL) || !(super->flags & ACC_INTERFACE)) { + if (super != NULL) { + emit_test_reg_reg(cd, s1, s1); + emit_jcc(cd, CC_E, s3); + } + + emit_mov_membase_reg(cd, s1, + OFFSET(java_objectheader, vftbl), + REG_ITMP1); + + if (super == NULL) { + codegen_add_patch_ref(cd, PATCHER_instanceof_class, + iptr->sx.s23.s3.c.ref, 0); + } + + emit_mov_imm_reg(cd, (ptrint) supervftbl, REG_ITMP2); +#if defined(ENABLE_THREADS) + codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase); +#endif + emit_movl_membase_reg(cd, REG_ITMP1, + OFFSET(vftbl_t, baseval), + REG_ITMP1); + emit_movl_membase_reg(cd, REG_ITMP2, + OFFSET(vftbl_t, diffval), + REG_ITMP3); + emit_movl_membase_reg(cd, REG_ITMP2, + OFFSET(vftbl_t, baseval), + REG_ITMP2); +#if defined(ENABLE_THREADS) + codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); +#endif + emit_alu_reg_reg(cd, ALU_SUB, REG_ITMP2, REG_ITMP1); + emit_alu_reg_reg(cd, ALU_XOR, d, d); /* may be REG_ITMP2 */ + emit_alu_reg_reg(cd, ALU_CMP, REG_ITMP3, REG_ITMP1); + emit_setcc_reg(cd, CC_BE, d); + } + emit_store_dst(jd, iptr, d); + } +#endif + break; + + case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref */ + OOPS(); +#if 0 + + /* check for negative sizes and copy sizes to stack if necessary */ + + MCODECHECK((10 * 4 * iptr->s1.argcount) + 5 + 10 * 8); + + for (s1 = iptr->s1.argcount; --s1 >= 0; ) { + + /* copy SAVEDVAR sizes to stack */ + var = VAR(iptr->sx.s23.s2.args[s1]); + + /* Already Preallocated? */ + if (!(var->flags & PREALLOC)) { + s2 = emit_load(jd, iptr, var, REG_ITMP1); + M_LST(s2, REG_SP, s1 * 8); + } + } + + /* is a patcher function set? */ + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + codegen_add_patch_ref(cd, PATCHER_builtin_multianewarray, + iptr->sx.s23.s3.c.ref, 0); + } + + /* a0 = dimension count */ + + M_MOV_IMM(iptr->s1.argcount, REG_A0); + + /* a1 = classinfo */ + + M_MOV_IMM(iptr->sx.s23.s3.c.cls, REG_A1); + + /* a2 = pointer to dimensions = stack pointer */ + + M_MOV(REG_SP, REG_A2); + + M_MOV_IMM(BUILTIN_multianewarray, REG_ITMP1); + M_CALL(REG_ITMP1); + + /* check for exception before result assignment */ + + M_TEST(REG_RESULT); + M_BEQ(0); + codegen_add_fillinstacktrace_ref(cd); + + s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); + M_INTMOVE(REG_RESULT, s1); + emit_store_dst(jd, iptr, s1); +#endif + break; + + default: + *exceptionptr = new_internalerror("Unknown ICMD %d", iptr->opc); + return false; + } /* switch */ + + } /* for instruction */ + + MCODECHECK(512); /* XXX require a lower number? */ + + /* At the end of a basic block we may have to append some nops, + because the patcher stub calling code might be longer than the + actual instruction. So codepatching does not change the + following block unintentionally. */ + + if (cd->mcodeptr < cd->lastmcodeptr) { + while (cd->mcodeptr < cd->lastmcodeptr) { + M_NOP; + } + } + + } /* if (bptr -> flags >= BBREACHED) */ + } /* for basic block */ + + dseg_createlinenumbertable(cd); + + /* generate stubs */ + + emit_exception_stubs(jd); + emit_patcher_stubs(jd); +#if 0 + emit_replacement_stubs(jd); +#endif + + codegen_finish(jd); + + /* everything's ok */ + + return true; +} + + +/* createcompilerstub ********************************************************** + + Creates a stub routine which calls the compiler. + +*******************************************************************************/ + +#define COMPILERSTUB_DATASIZE (3 * SIZEOF_VOID_P) +#define COMPILERSTUB_CODESIZE (SZ_BRAS + SZ_AHI + (2 * SZ_L) + SZ_BR) + +#define COMPILERSTUB_SIZE (COMPILERSTUB_DATASIZE + COMPILERSTUB_CODESIZE) + + +u1 *createcompilerstub(methodinfo *m) +{ + u1 *s; /* memory to hold the stub */ + ptrint *d; + codeinfo *code; + codegendata *cd; + s4 dumpsize; + + s = CNEW(u1, COMPILERSTUB_SIZE); + + /* set data pointer and code pointer */ + + d = (ptrint *) s; + s = s + COMPILERSTUB_DATASIZE; + + /* mark start of dump memory area */ + + dumpsize = dump_size(); + + cd = DNEW(codegendata); + cd->mcodeptr = s; + + /* Store the codeinfo pointer in the same place as in the + methodheader for compiled methods. */ + + code = code_codeinfo_new(m); + + d[0] = (ptrint) asm_call_jit_compiler; + d[1] = (ptrint) m; + d[2] = (ptrint) code; + + /* code for the stub */ + + /* don't touch ITMP3 as it cointains the return address */ + + N_L2(REG_ITMP1, -2 * 4, REG_PV); /* methodinfo */ + /* TODO where is methodpointer loaded into itmp2? is it already inside? */ + N_L2(REG_PV, -3 * 4, REG_PV); /* compiler pointer */ + N_BR(REG_PV); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_cstub_len += COMPILERSTUB_SIZE; +#endif + + /* release dump area */ + + dump_release(dumpsize); + + return s; +} + + +/* createnativestub ************************************************************ + + Creates a stub routine which calls a native method. + +*******************************************************************************/ + +/* + arguments on stack \ +-------------------------------------------------| <- SP on nativestub entry + return address | + callee saved int regs (none) | + callee saved float regs (none) | stack frame like in cacao + local variable slots (none) | + arguments for calling methods (none) / +------------------------------------------------------------------ <- datasp + stackframe info + locaref table + integer arguments + float arguments +96 - ... on stack parameters (nmd->memuse slots) \ stack frame like in ABI +0 - 96 register save area for callee / +-------------------------------------------------------- <- SP native method + == + SP after method entry +*/ + +u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd) +{ + methodinfo *m; + codeinfo *code; + codegendata *cd; + registerdata *rd; + methoddesc *md; + s4 nativeparams; + s4 i, j; /* count variables */ + s4 t; + s4 s1, s2; + s4 disp; + + /* get required compiler data */ + + m = jd->m; + code = jd->code; + cd = jd->cd; + rd = jd->rd; + + /* initialize variables */ + + md = m->parseddesc; + nativeparams = (m->flags & ACC_STATIC) ? 2 : 1; + + /* calculate stack frame size */ +#if 0 + cd->stackframesize = + sizeof(stackframeinfo) / SIZEOF_VOID_P + + sizeof(localref_table) / SIZEOF_VOID_P + + INT_ARG_CNT + FLT_ARG_CNT + + 1 + /* functionptr, TODO: store in data segment */ + nmd->memuse; + + cd->stackframesize |= 0x1; /* keep stack 16-byte aligned */ +#endif + + cd->stackframesize = + 1 + /* r14 - return address */ + + sizeof(stackframeinfo) / SIZEOF_VOID_P + + sizeof(localref_table) / SIZEOF_VOID_P + + 1 + /* itmp3 */ + (INT_ARG_CNT + FLT_ARG_CNT) * 2 + + nmd->memuse + /* parameter passing */ + 96 / SIZEOF_VOID_P /* required by ABI */; + + + /* create method header */ + + (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ + (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* FrameSize */ + (void) dseg_add_unique_s4(cd, 0); /* IsSync */ + (void) dseg_add_unique_s4(cd, 0); /* IsLeaf */ + (void) dseg_add_unique_s4(cd, 0); /* IntSave */ + (void) dseg_add_unique_s4(cd, 0); /* FltSave */ + (void) dseg_addlinenumbertablesize(cd); + (void) dseg_add_unique_s4(cd, 0); /* ExTableSize */ + + /* generate native method profiling code */ +#if 0 + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { + /* count frequency */ + + M_MOV_IMM(code, REG_ITMP3); + M_IINC_MEMBASE(REG_ITMP3, OFFSET(codeinfo, frequency)); + } +#endif + + /* generate stub code */ + + N_AHI(REG_SP, -(cd->stackframesize * SIZEOF_VOID_P)); + + /* save return address */ + + N_ST(R14, (cd->stackframesize - 1) * SIZEOF_VOID_P, 0, REG_SP) + +#if 0 +#if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + emit_verbosecall_enter(jd); +#endif +#endif + + /* get function address (this must happen before the stackframeinfo) */ + +#if !defined(WITH_STATIC_CLASSPATH) + if (f == NULL) + codegen_add_patch_ref(cd, PATCHER_resolve_native, m, 0); +#endif + + disp = dseg_add_functionptr(cd, f); + N_L2(REG_ITMP3, disp, REG_PV); + + j = 96 + (nmd->memuse * 4); + + /* todo some arg registers are not volatile in C-abi terms */ + + /* save integer and float argument registers */ + + for (i = 0; i < md->paramcount; i++) { + if (! md->params[i].inmemory) { + s1 = md->params[i].regoff; + + if (IS_INT_LNG_TYPE(md->paramtypes[i].type)) { + if (IS_2_WORD_TYPE(t)) { + /* todo store multiple */ + N_ST(rd->argintregs[GET_HIGH_REG(s1)], j, 0, REG_SP); + N_ST(rd->argintregs[GET_LOW_REG(s1)], j + 4, 0, REG_SP); + } else { + N_ST(rd->argintregs[s1], j, 0, REG_SP); + } + } else { + if (IS_2_WORD_TYPE(t)) { + N_STD(rd->argfltregs[s1], j, 0, REG_SP); + } else { + N_STE(rd->argfltregs[s1], j, 0, REG_SP); + } + } + + j += 8; + } + } + + N_ST(REG_ITMP3, j, 0, REG_SP); + + /* create dynamic stack info */ + + N_LAE(REG_A0, (cd->stackframesize - 1) * 4, 0, REG_SP); /* datasp */ + N_LR(REG_A1, REG_PV) /* pv */ + N_LAE(REG_A2, cd->stackframesize * 4, 0, REG_SP); /* old SP */ + N_L(REG_A3, (cd->stackframesize - 1) * 4, 0, REG_SP); /* return address */ + + disp = dseg_add_functionptr(cd, codegen_start_native_call); + N_L2(REG_ITMP1, disp, REG_PV); + + M_CALL(REG_ITMP1); /* call */ + + /* restore integer and float argument registers */ + + j = 96 + (nmd->memuse * 4); + + for (i = 0; i < md->paramcount; i++) { + if (! md->params[i].inmemory) { + s1 = md->params[i].regoff; + + if (IS_INT_LNG_TYPE(md->paramtypes[i].type)) { + if (IS_2_WORD_TYPE(t)) { + /* todo load multiple ! */ + N_L(rd->argintregs[GET_HIGH_REG(s1)], j, 0, REG_SP); + N_L(rd->argintregs[GET_LOW_REG(s1)], j + 4, 0, REG_SP); + } else { + N_L(rd->argintregs[s1], j, 0, REG_SP); + } + } else { + if (IS_2_WORD_TYPE(t)) { + N_LD(rd->argfltregs[s1], j, 0, REG_SP); + } else { + N_LE(rd->argfltregs[s1], j, 0, REG_SP); + } + } + + j += 8; + } + } + + N_L(REG_ITMP3, j, 0, REG_SP); + + /* copy or spill arguments to new locations */ + + for (i = md->paramcount - 1, j = i + nativeparams; i >= 0; i--, j--) { + t = md->paramtypes[i].type; + + if (IS_INT_LNG_TYPE(t)) { + + if (!md->params[i].inmemory) { + + s1 = rd->argintregs[md->params[i].regoff]; + + if (!nmd->params[j].inmemory) { + s2 = rd->argintregs[nmd->params[j].regoff]; + if (IS_2_WORD_TYPE(t)) { + N_LR(GET_HIGH_REG(s2), GET_HIGH_REG(s1)); + N_LR(GET_LOW_REG(s2), GET_LOW_REG(s1)); + } else { + N_LR(s2, s1); + } + } else { + s2 = nmd->params[j].regoff; + if (IS_2_WORD_TYPE(t)) { + N_LM(GET_LOW_REG(s1), GET_HIGH_REG(s1), 96 + (s2 * 4), REG_SP); + } else { + N_L(s1, 96 + (s2 * 4), 0, REG_SP); + } + } + + } else { + s1 = md->params[i].regoff + cd->stackframesize + 1; /* + 1 (RA) */ + s2 = nmd->params[j].regoff; + + if (IS_2_WORD_TYPE(t)) { + N_MVC(96 + (s2 * 4), 8, REG_SP, s1, REG_SP); + } else { + N_MVC(96 + (s2 * 4), 4, REG_SP, s1, REG_SP); + } + } + + } else { + /* We only copy spilled float arguments, as the float argument */ + /* registers keep unchanged. */ + + if (md->params[i].inmemory) { + s1 = md->params[i].regoff + cd->stackframesize + 1; /* + 1 (RA) */ + s2 = nmd->params[j].regoff; + + if (IS_2_WORD_TYPE(t)) { + N_MVC(96 + (s2 * 4), 8, REG_SP, s1, REG_SP); + } else { + N_MVC(96 + (s2 * 4), 4, REG_SP, s1, REG_SP); + } + } + } + } + + /* put class into second argument register */ + + if (m->flags & ACC_STATIC) { + disp = dseg_add_address(cd, m->class); + N_L2(REG_A1, disp, REG_PV); + } + + /* put env into first argument register */ + + disp = dseg_add_address(cd, _Jv_env); + N_L2(REG_A0, disp, REG_PV); + + /* do the native function call */ + + M_CALL(REG_ITMP3); /* call */ + + /* save return value */ + + t = md->returntype.type; + + if (t != TYPE_VOID) { + if (IS_INT_LNG_TYPE(t)) { + if (IS_2_WORD_TYPE(t)) { + N_STM(REG_RESULT, REG_RESULT2, 96, REG_SP); + } else { + N_ST(REG_RESULT, 96, 0, REG_SP); + } + } else { + if (IS_2_WORD_TYPE(t)) { + N_STD(REG_FRESULT, 96, 0, REG_SP); + } else { + N_STE(REG_FRESULT, 96, 0, REG_SP); + } + } + } + +#if 0 +#if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + emit_verbosecall_exit(jd); +#endif +#endif + + /* remove native stackframe info */ + + N_LAE(REG_A0, cd->stackframesize * 4, 0, REG_SP); + disp = dseg_add_functionptr(cd, codegen_finish_native_call); + N_L2(REG_ITMP1, disp, REG_PV); + M_CALL(REG_ITMP1); + N_LR(REG_ITMP3, REG_RESULT); + + /* restore return value */ + + if (t != TYPE_VOID) { + if (IS_INT_LNG_TYPE(t)) { + if (IS_2_WORD_TYPE(t)) { + N_LM(REG_RESULT, REG_RESULT2, 96, REG_SP); + } else { + N_L(REG_RESULT, 96, 0, REG_SP); + } + } else { + if (IS_2_WORD_TYPE(t)) { + N_LD(REG_FRESULT, 96, 0, REG_SP); + } else { + N_LE(REG_FRESULT, 96, 0, REG_SP); + } + } + } + + /* remove stackframe */ + + N_AHI(REG_SP, cd->stackframesize * 4); + + /* test for exception */ + + N_LTR(REG_ITMP3, REG_ITMP3); + N_BRC(DD_NE, SZ_BRC + SZ_BC); + N_BC(DD_ANY, 0, 0, REG_SP); /* return */ + + /* handle exception */ + + N_LONG_0(); + +#if 0 + M_MOV(REG_ITMP3, REG_ITMP1_XPTR); + M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8); /* get return address from stack */ + M_ASUB_IMM(3, REG_ITMP2_XPC); /* callq */ + + M_MOV_IMM(asm_handle_nat_exception, REG_ITMP3); + M_JMP(REG_ITMP3); + + /* generate patcher stubs */ + + emit_patcher_stubs(jd); + +#endif + codegen_finish(jd); + + return code->entrypoint; + return NULL; +} + + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/s390/codegen.h b/src/vm/jit/s390/codegen.h new file mode 100644 index 000000000..a34fa8fb7 --- /dev/null +++ b/src/vm/jit/s390/codegen.h @@ -0,0 +1,695 @@ +/* src/vm/jit/x86_64/codegen.h - code generation macros for x86_64 + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Andreas Krall + Christian Thalinger + + $Id: codegen.h 7219 2007-01-16 22:18:57Z pm $ + +*/ + + +#ifndef _CODEGEN_H +#define _CODEGEN_H + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "vm/jit/jit.h" + + +/* additional functions and macros to generate code ***************************/ + +#define CALCOFFSETBYTES(var, reg, val) \ + if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \ + else if ((s4) (val) != 0) (var) += 1; \ + else if ((reg) == RBP || (reg) == RSP || (reg) == R12 || (reg) == R13) (var) += 1; + + +#define CALCIMMEDIATEBYTES(var, val) \ + if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \ + else (var) += 1; + + +/* gen_nullptr_check(objreg) */ + +#define gen_nullptr_check(objreg) \ + if (checknull) { \ + M_TEST(objreg); \ + M_BEQ(0); \ + codegen_add_nullpointerexception_ref(cd); \ + } + + +#define gen_bound_check \ + if (checkbounds) { \ + M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));\ + M_ICMP(REG_ITMP3, s2); \ + M_BAE(0); \ + codegen_add_arrayindexoutofboundsexception_ref(cd, s2); \ + } + + +/* MCODECHECK(icnt) */ + +#define MCODECHECK(icnt) \ + do { \ + if ((cd->mcodeptr + (icnt)) > cd->mcodeend) \ + codegen_increase(cd); \ + } while (0) + + +#define ALIGNCODENOP \ + if ((s4) (((ptrint) cd->mcodeptr) & 7)) { \ + M_NOP; \ + } + + +/* M_INTMOVE: + generates an integer-move from register a to b. + if a and b are the same int-register, no code will be generated. +*/ + +#define M_INTMOVE(reg,dreg) \ + do { \ + if ((reg) != (dreg)) { \ + M_MOV(reg, dreg); \ + } \ + } while (0) + + +/* M_FLTMOVE: + generates a floating-point-move from register a to b. + if a and b are the same float-register, no code will be generated +*/ + +#define M_FLTMOVE(reg,dreg) \ + do { \ + if ((reg) != (dreg)) { \ + M_FMOV(reg, dreg); \ + } \ + } while (0) + + +#define ICONST(r,c) \ + do { \ + if ((c) == 0) \ + M_CLR((d)); \ + else \ + M_IMOV_IMM((c), (d)); \ + } while (0) +/* do { \ */ +/* M_IMOV_IMM((c), (d)); \ */ +/* } while (0) */ + + +#define LCONST(r,c) \ + do { \ + if ((c) == 0) \ + M_CLR((d)); \ + else \ + M_MOV_IMM((c), (d)); \ + } while (0) + + +/* some patcher defines *******************************************************/ + +#define PATCHER_CALL_SIZE 5 /* size in bytes of a patcher call */ + +#define PATCHER_NOPS \ + do { \ + M_NOP; \ + M_NOP; \ + M_NOP; \ + M_NOP; \ + M_NOP; \ + } while (0) + + +/* macros to create code ******************************************************/ + +/* Conventions: + * N_foo: defines the instrucition foo as in `ESA/390 Principles of operations' + * SZ_foo: defines the size of the instruction N_foo + * DD_foo: defines a condition code as used by s390 GCC + * M_foo: defines the alpha like instruction used in cacao + * the instruction is defined by an equivalent N_ instruction + * CC_foo: defines a condition code as used + * the instruction is defined as an equivalent DD_ condition code + */ + +/* S390 specific code */ + +/* Instruction formats */ + +#define _CODE(t, code) \ + do { \ + *((t *) cd->mcodeptr) = (code); \ + cd->mcodeptr += sizeof(t); \ + } while (0); + +#define _CODE2(code) _CODE(u2, code) +#define _CODE4(code) _CODE(u4, code) + +#define _IFNEG(val, neg, pos) \ + do { if ((val) < 0) { neg ; } else { pos ; } } while (0) + +#define N_RR(op, r1, r2) \ + _CODE2( (op << 8) | (r1 << 4) | (r2) ) + +#define SZ_RR 2 + +#define N_RR2(op, i) \ + _CODE2( (op << 8) | (i) ) + +#define N_RX(op, r1, d2, x2, b2) \ + _CODE4( ((op) << 24) | ((r1) << 20) | ((x2) << 16) | ((b2) << 12) | ((d2) << 0) ) + +#define SZ_RX 4 + +#define N_RI(op1, op2, r1, i2) \ + _CODE4( ((op1) << 24) | ((r1) << 20) | ((op2) << 16) | ((u2) i2) ) + +#define SZ_RI 4 + +#define N_SI(op, d1, b1, i2) \ + _CODE4( ((op) << 24) | ((i2) << 16) | ((b1) << 12) | (d1) ) + +#define SZ_SI 4 + +#define N_SS(op, d1, l, b1, d2, b2) \ + _CODE4( ((op) << 24) | ((l) << 16) | ((b1) << 12) | (d1) ) \ + _CODE2( ((b2) << 12) | (d2) ) + +#define SZ_SS 6 + +#define N_SS2(op, d1, l1, b1, d2, l2, b2) \ + N_SS(op, d1, ((l1) << 4) | (l2), b1, d2, l2) + +#define N_RS(op, r1, r3, d2, b2) \ + _CODE4( ((op) << 24) | ((r1) << 20) | ((r3) << 16) | ((b2) << 12) | (d2) ) + +#define SZ_RS 4 + +#define N_RSI(op, r1, r2, i2) \ + _CODE4( ((op) << 24) | ((r1) << 20) | ((r3) << 16) | ((u2)i2) ) + +#define SZ_RSI 4 + +#define N_RRE(op, r1, r2) \ + _CODE4( ((op) << 16) | ((r1) << 4) | (r2) ) + +#define SZ_RRE 4 + +#define N_S2(d2, b2) \ + _CODE4( ((op) << 16) | ((b2) << 12) | (d2) ) + +#define SZ_S2 4 + +#define N_E(op) \ + _CODE2( (op) ) + +#define SZ_E 2 + +/* Condition codes */ + +#define DD_O 1 +#define DD_H 2 +#define DD_NLE 3 +#define DD_L 4 +#define DD_NHE 5 +#define DD_LH 6 +#define DD_NE 7 +#define DD_E 8 +#define DD_NLH 9 +#define DD_HE 10 +#define DD_NL 11 +#define DD_LE 12 +#define DD_NH 13 +#define DD_NO 14 +#define DD_ANY 15 + +/* Misc */ + +#define N_LONG_0() _CODE4(0) + +/* Chapter 7. General instructions */ + +#define N_AR(r1, r2) N_RR(0x1A, r1, r2) +#define N_A(r1, d2, x2, b2) N_RX(0x5A, r1, d2, x2, b2) +#define N_AH(r1, d2, x2, b2) N_RX(0x4A, r1, d2, x2, b2) +#define N_AHI(r1, i2) N_RI(0xA7, 0xA, r1, i2) +# define SZ_AHI SZ_RI +#define N_ALR(r1, r2) N_RR(0x1E, r1, r2) +#define N_AL(r1, d2, x2, b2) N_RX(0x5E, r1, d2, x2, b2) +#define N_NR(r1, r2) N_RR(r1, r2) +#define N_N(r1, d2, x2, b2) N_RX(0x54, r1, d2, x2, b2) +#define N_NI(d1, b1, i2) N_SI(0x94, d1, b1, i2) +#define N_NC(d1, l, b1, d2, b2) N_NC(0xD4, l, b1, d1, b2, d2) +#define N_BALR(r1, r2) N_RR(0x05, r1, r2) +#define N_BAL(r1, d2, x2, b2) N_RX(0x45, r1, d2, x2, b2) +#define N_BASR(r1, r2) N_RR(0x0D, r1, r2) +#define N_BAS(r1, d2, x2, b2) N_RX(0x4D, r1, d2, x2, b2) +#define N_BASSM(r1, r2) N_RR(0x0C, r1, r2) +#define N_BSM(r1, r2) N_RR(0x0B, r1, r2) +#define N_BCR(m1, r2) N_RR(0x07, m1, r2) +# define SZ_BCR SZ_RR +# define N_BR(r2) N_BCR(DD_ANY, r2) +# define SZ_BR SZ_BCR +#define N_BC(m1, d2, x2, b2) N_RS(0x47, m1, d2, x2, b2) +# define SZ_BC SZ_RS +#define N_BCTR(r1, r2) N_RR(0x06, r1, r2) +#define N_BCT(r1, d2, x2, b2) N_RX(0x46, r1, d2, x2, b2) +#define N_BHX(r1, r2, d2, b2) N_RS(0xB6, r1, r3, d2, b2) +#define N_BXLE(r1, r3, d2, b2) N_RS(0xB7, r1, r3, d2, b2) +#define N_BRAS(r1, i2) N_RI(0xA7, 0x5, r1, (i2) / 2) +# define SZ_BRAS SZ_RI +#define N_BRC(m1, i2) N_RI(0xA7, 0x4, m1, (i2) / 2) +# define N_J(i2) N_BRC(DD_ANY, i2) +# define SZ_BRC SZ_RI +# define SZ_J SZ_RI +#define N_BRCT(r1, i2) N_RI(0xA7, 0x6, r1, (i2) / 2) +#define N_BRXH(r1, r3, i2) N_RSI(0x84, r1, r3, (i2) / 2) +#define N_BRXLE(r1, r3, i2) N_RSI(0x85, r1, r2, (i2) / 2) +#define N_CKSM(r1, r2) N_RRE(0xB241, r1, r2) +#define N_CR(r1, r2), N_RR(0x19, r1, r2) +#define N_C(r1, d2, x2, b2) N_RX(0x59, r1, d2, x2, b2) +#define N_CFC(d2, b2) N_S2(0xB21A, d2, b2) +#define N_CS(r1, r3, d2, b2) N_RS(0xBA, r1, r3, d2, b2) +#define N_CDS(r1, r3, d2, b2) N_RS(0xBB, r1, r3, d2, b2) +#define N_CH(r1, d2, x2, b2) N_CH(0x49, r1, d2, x2, b2) +#define N_CHI(r1, i2) N_RI(0xA7, 0xE, r1, i2) +#define N_CLR(r1, r2) N_RR(0x15, r1, r2) +#define N_CL(r1, d2, x2, b2) N_RX(0x55, r1, d2, x2, b2) +#define N_CLI(d1, b1, i2) N_SI(0x95, d1, b1, i2) +#define N_CLC(d1, l, b1, d2, b2) N_SS(0xD5, d1, l, b1, d2, b2) +#define N_CLM(r1, m3, d2, b2) N_RS(0xBD, r1, m3, d2, b2) +#define N_CLCL(r1, r2) N_RR(0x0F, r1, r2) +#define N_CLCLE(r1, r3, d2, b2) N_RS(0xA9, r1, r3, d2, b2) +#define N_CLST(r1, r2) N_RRE(0xB25D, r1, r2) +#define N_CUSE(r1, r2) N_RRE(0xB257, r1, r2) +#define N_CVB(r1, d2, x2, b2) N_RX(0x4F, r1, r2, x2, b2) +#define N_CVD(r1, d2, x2, b2) N_RX(0x4E, r1, d2, x2, b2) +#define N_CUUTF(r1, r2) N_RRE(0xB2A6, r1, r2) +#define N_CUTFU(r1, r2) N_RRE(0xB2A7, r1, r2) +#define N_CPYA(r1, r2) N_RRE(0xB240, r1, r2) +#define N_DR(r1, r2) N_RR(0x1D, r1, r2) +#define N_D(r1, d2, x2, b2) N_RX(0x5D, r1, d2, x2, b2) +#define N_XR(r1, r2) N_RR(0x17, r1, r2) +#define N_X(r1, d2, x2, b2) N_RX(0x57, r1, d2, x2, b2) +#define N_XI(d1, b1, i2) N_SI(0x97, d1, b1, i2) +#define N_XC(d1, l, b1, d2, b2) N_SS(0xD7, d1, l, b1, d2, b2) +#define N_EX(r1, d2, x2, b2) N_RX(0x44, r1, d2, x2, b2) +#define N_EAR(r1, r2) N_RRE(0xB24F, r1, r2) +#define N_IC(r1, d2, x2, b2) N_RX(0x43, r1, d2, x2, b2) +#define N_ICM(r1, m3, d2, b2) N_RS(0xBF, r1, m3, d2, b2) +#define N_IPM(r1) N_RRE(0xB222, r1, 0) +#define N_LR(r1, r2) N_RR(0x18, r1, r2) +#define N_L(r1, d2, x2, b2) N_RX(0x58, r1, d2, x2, b2) +# define SZ_L SZ_RX +# define N_L2(r1, d2, b2) \ + do { N_LHI(r1, d2); N_L(r1, 0, r1, b2); } while (0) +#define N_LAM(r1, r3, d2, b2) N_RS(0x9A, r1, r3, d2, b2) +#define N_LA(r1, d2, x2, b2) N_RX(0x41, r1, d2, x2, b2) +# define N_LA2(r1, d2, b2) \ + do { N_LHI(r1, d2); N_LA(r1, 0, r1, b2); } while (0) +#define N_LAE(r1, d2, x2, b2) N_RX(0x51, r1, d2, x2, b2) +#define N_LTR(r1, r2) N_RR(0x12, r1, r2) +#define N_LCR(r1, r2) N_RR(0x13, r1, r2) +#define N_LH(r1, d2, x2, b2) N_RX(0x48, r1, d2, x2, b2) +#define N_LHI(r1, i2) N_RI(0xA7, 0x8, r1, i2) +#define N_LM(r1, r3, d2, b2) N_RS(0x98, r1, r3, d2, b2) +#define N_LNR(r1, r2) N_RR(0x11, r1, r2) +#define N_LPR(r1, r2) N_RR(0x10, r1, r2) +#define N_MC(d1, b1, i2) N_SI(0xAF, d1, b1, i2) +#define N_MVI(d1, b1, i2) N_SI(0x92, d1, b1, i2) +#define N_MVC(d1, l, b1, d2, b2) N_SS(0xD2, d1, l, b1, d2, b2) +#define N_MVCIN(d1, l, b1, d2, b2) N_SS(0xEB, d1, l, b1, d2, b2) +#define N_MVCL(r1, r2) N_RR(0x0E, r1, r2) +#define N_MVCLE(r1, r3, d2, b2) N_RS(0xAB, r1, r3, d2, b2) +#define N_MVN(d1, l, b1, d2, b2) N_SS(0xD1, d1, l, b1, d2, b2) +#define N_MVPG(r1, r2) N_RRE(0xB254, r1, r2) +#define N_MVST(r1, r2) N_RRE(0xB255, r1, r2) +#define N_MVO(d1, l1, b1, d2, l2, b2) N_SS2(0xF1, d1, l1, b1, d2, l2, b2) +#define N_MVZ(d1, l, b1, d2, b2) N_SS(0xD3, d1, l, b1, d2, b2) +#define N_MR(r1, r2) N_RR(0x1C, r1, r2) +#define N_M(r1, d2, x2, b2) N_RX(0x5C, r1, d2, x2, b2) +#define N_MH(r1, d2, x2, b2) N_RX(0x4C, r1, d2, x2, b2) +#define N_MHI(r1, i2) N_RI(0xA7, 0xC, r1, i2) +#define N_MSR(r1, r2) N_RRE(0xB252, r1, r2) +#define N_MS(r1, d2, x2, b2) N_RX(0x71, r1, d2, x2, b2) +#define N_OR(r1, r2) N_RR(0x16, r1, r2) +#define N_O(r1, d2, x2, b2) N_RX(0x56, r1, d2, x2, b2) +#define N_OI(d1, b1, i2) N_SI(0x96, d1, b1, i2) +#define N_OC(d1, l, b1, d2, b2) N_SS(0xD6, d1, l, b1, d2, b2) +#define N_PACK(d1, l1, b1, d2, l2, b2) N_SS2(0xF2, d1, l1, b1, d2, l2, b2) +#define N_PLO(r1, d2, b2, r3, d4, b4) N_SS2(0xEE, d2, r1, b2, d4, r3, b4) +#define N_SRST(r1, r2) N_RRE(0xB25E, r1, r2) +#define N_SAR(r1, r2) N_RRE(0xB24E, r1, r2) +#define N_SPM(r1) N_RR(0x04, r1, 0x00) +#define N_SLDA(r1, d2, b2) N_RS(0x8F, r1, 0x00, d2, b2) +#define N_SLDL(r1, d2, b2) N_RS(0x8D, r1, 0x00, d2, b2) +#define N_SLA(r1, d2, b2) N_RS(0x8B, r1, 0x00, d2, b2) +#define N_SLL(r1, d2, b2) N_RS(0x89, r1, 0x00, d2, b2) +#define N_SRDA(r1, d2, b2) N_RS(0x8E, r1, 0x00, d2, b2) +#define N_SRDL(r1, d2, b2) N_RS(0x8C, r1, 0x00, d2, b2) +#define N_SRA(r1, d2, b2) N_RS(0x8A, r1, 0x00, d2, b2) +#define N_SRL(r1, d2, b2) N_RS(0x88, r1, 0x00, d2, b2) +#define N_ST(r1, d2, x2, b2) N_RX(0x50, r1, d2, x2, b2) +#define N_STAM(r1, r3, d2, b2) N_RS(0x9B, r1, r3, d2, b2) +#define N_STC(r1, d2, x2, b2) N_RX(0x42, r1, d2, x2, b2) +#define N_STCM(r1, m3, d2, b2) N_RS(0xBE, r1, m3, d2, b2) +#define N_STCK(d2, b2) N_S2(0xB205, d2, b2) +#define N_STCKE(d2, b2) N_S2(0xB278, d2, b2) +#define N_STH(r1, d2, x2, b2) N_RX(0x40, r1, d2, x2, b2) +#define N_STM(r1, r3, d2, b2) N_RS(0x90, r1, r3, d2, b2) +#define N_SR(r1, r2) N_RR(0x1B, r1, r2) +#define N_S(r1, d2, x2, b2) N_RX(0x5B, r1, d2, x2, b2) +#define N_SH(r1, d2, x2, b2) N_RX(0x4B, r1, d2, x2, b2) +#define N_SLR(r1, r2) N_RR(0x1F, r1, r2) +#define N_SL(r1, d2, x2, b2) N_RX(0x5F, r1, d2, x2, b2) +#define N_SVC(i) N_RR2(0x0A, i) +#define N_TS(d2, b2) N_S2(0x93, d2, b2) +#define N_TM(d1, b1, i2) N_SI(0x91, d1, b1, i2) +#define N_TMH(r1, i2) N_RI(0xA7, 0x00, r1, i2) +#define N_TML(r1, i2) N_RI(0xA7, 0x01, r1, i2) +#define N_TR(d1, l, b1, d2, b2) N_SS(0xDC, d1, l, b1, d2, b2) +#define N_TRT(d1, l, b1, d2, b2) N_SS(0xDD, d1, l, b1, d2, b2) +#define N_TRE(r1, r2) N_RRE(0xB2A5, r1, r2) +#define N_UNPK(d1, l1, b1, d2, l2, b2) N_SS2(0xF3, d1, l1, b1, d2, l2, b2) +#define N_UPT() N_E(0x0102) + +/* Chapter 9. Floating point instructions */ + +#define N_LER(r1, r2) N_RR(0x38, r1, r2) +#define N_LDR(r1, r2) N_RR(0x28, r1, r2) +#define N_LXR(r1, r2) N_RRE(0xB365, r1, r2) +#define N_LE(r1, d2, x2, b2) N_RX(0x78, r1, d2, x2, b2) +#define N_LD(r1, d2, x2, b2) N_RX(0x68, r1, d2, x2, b2) +#define N_LZER(r1) N_RRE(0xB374, r1, 0x0) +#define N_LZDR(r1) N_RRE(0xB375, r1, 0x0) +#define N_LZXR(r1) N_RRE(0xB376, r1, 0x0) +#define N_STE(r1, d2, x2, b2) N_RX(0x70, r1, d2, x2, b2) +#define N_STD(r1, d2, x2, b2) N_RX(0x60, r1, d2, x2, b2) + +/* chapter 19. Binary floating point instructions */ + +/* Alpha like instructions */ + +#define M_CALL(r2) N_BASR(R14, r2) + +#define M_ALD(r, b, d) _IFNEG(d, N_L2(r, d, b), N_L(r, d, 0, b)) +#define M_ILD(r, b, d) _IFNEG(d, N_LA2(r, d, b), N_LA(r, d, 0, b)) +#define M_FLD(r, b, d) _IFNEG(d, assert(0), N_LE(r, d, 0, b)) +#define M_DLD(r, b, d) _IFNEG(d, assert(0), N_LD(r, d, 0, b)) +/* TODO 3 instead of 4 instrs for d < 0 ! */ +#define M_LLD(r, b, d) \ + do { M_ILD(GET_HIGH_REG(r), b, d); M_ILD(GET_LOW_REG(r), b, d + 4); } while(0) + +/* ----------------------------------------------- */ + +#define M_MOV(a,b) emit_mov_reg_reg(cd, (a), (b)) +#define M_MOV_IMM(a,b) emit_mov_imm_reg(cd, (u8) (a), (b)) + +#define M_IMOV(a,b) emit_movl_reg_reg(cd, (a), (b)) +#define M_IMOV_IMM(a,b) emit_movl_imm_reg(cd, (u4) (a), (b)) + +#define M_FMOV(a,b) emit_movq_reg_reg(cd, (a), (b)) + +#define M__ILD(a,b,disp) emit_movl_membase_reg(cd, (b), (disp), (a)) +#define M__LLD(a,b,disp) emit_mov_membase_reg(cd, (b), (disp), (a)) + +#define M_ILD32(a,b,disp) emit_movl_membase32_reg(cd, (b), (disp), (a)) +#define M_LLD32(a,b,disp) emit_mov_membase32_reg(cd, (b), (disp), (a)) + +#define M_IST(a,b,disp) emit_movl_reg_membase(cd, (a), (b), (disp)) +#define M_LST(a,b,disp) emit_mov_reg_membase(cd, (a), (b), (disp)) + +#define M_IST_IMM(a,b,disp) emit_movl_imm_membase(cd, (a), (b), (disp)) +#define M_LST_IMM32(a,b,disp) emit_mov_imm_membase(cd, (a), (b), (disp)) + +#define M_IST32(a,b,disp) emit_movl_reg_membase32(cd, (a), (b), (disp)) +#define M_LST32(a,b,disp) emit_mov_reg_membase32(cd, (a), (b), (disp)) + +#define M_IST32_IMM(a,b,disp) emit_movl_imm_membase32(cd, (a), (b), (disp)) +#define M_LST32_IMM32(a,b,disp) emit_mov_imm_membase32(cd, (a), (b), (disp)) + +#define M_IADD(a,b) emit_alul_reg_reg(cd, ALU_ADD, (a), (b)) +#define M_ISUB(a,b) emit_alul_reg_reg(cd, ALU_SUB, (a), (b)) +#define M_IMUL(a,b) emit_imull_reg_reg(cd, (a), (b)) + +#define M_IADD_IMM(a,b) emit_alul_imm_reg(cd, ALU_ADD, (a), (b)) +#define M_ISUB_IMM(a,b) emit_alul_imm_reg(cd, ALU_SUB, (a), (b)) +#define M_IMUL_IMM(a,b,c) emit_imull_imm_reg_reg(cd, (b), (a), (c)) + +#define M_LADD(a,b) emit_alu_reg_reg(cd, ALU_ADD, (a), (b)) +#define M_LSUB(a,b) emit_alu_reg_reg(cd, ALU_SUB, (a), (b)) +#define M_LMUL(a,b) emit_imul_reg_reg(cd, (a), (b)) + +#define M_LADD_IMM(a,b) emit_alu_imm_reg(cd, ALU_ADD, (a), (b)) +#define M_LSUB_IMM(a,b) emit_alu_imm_reg(cd, ALU_SUB, (a), (b)) +#define M_LMUL_IMM(a,b,c) emit_imul_imm_reg_reg(cd, (b), (a), (c)) + +#define M_IINC(a) emit_incl_reg(cd, (a)) +#define M_IDEC(a) emit_decl_reg(cd, (a)) + +#define M__ALD(a,b,disp) M_LLD(a,b,disp) +#define M_ALD32(a,b,disp) M_LLD32(a,b,disp) + +#define M_AST(a,b,c) M_LST(a,b,c) +#define M_AST_IMM32(a,b,c) M_LST_IMM32(a,b,c) + +#define M_AADD(a,b) M_LADD(a,b) +#define M_AADD_IMM(a,b) M_LADD_IMM(a,b) +#define M_ASUB_IMM(a,b) M_LSUB_IMM(a,b) + +#define M_LADD_IMM32(a,b) emit_alu_imm32_reg(cd, ALU_ADD, (a), (b)) +#define M_AADD_IMM32(a,b) M_LADD_IMM32(a,b) +#define M_LSUB_IMM32(a,b) emit_alu_imm32_reg(cd, ALU_SUB, (a), (b)) + +#define M_ILEA(a,b,c) emit_leal_membase_reg(cd, (a), (b), (c)) +#define M_LLEA(a,b,c) emit_lea_membase_reg(cd, (a), (b), (c)) +#define M_ALEA(a,b,c) M_LLEA(a,b,c) + +#define M_INEG(a) emit_negl_reg(cd, (a)) +#define M_LNEG(a) emit_neg_reg(cd, (a)) + +#define M_IAND(a,b) emit_alul_reg_reg(cd, ALU_AND, (a), (b)) +#define M_IOR(a,b) emit_alul_reg_reg(cd, ALU_OR, (a), (b)) +#define M_IXOR(a,b) emit_alul_reg_reg(cd, ALU_XOR, (a), (b)) + +#define M_IAND_IMM(a,b) emit_alul_imm_reg(cd, ALU_AND, (a), (b)) +#define M_IOR_IMM(a,b) emit_alul_imm_reg(cd, ALU_OR, (a), (b)) +#define M_IXOR_IMM(a,b) emit_alul_imm_reg(cd, ALU_XOR, (a), (b)) + +#define M_LAND(a,b) emit_alu_reg_reg(cd, ALU_AND, (a), (b)) +#define M_LOR(a,b) emit_alu_reg_reg(cd, ALU_OR, (a), (b)) +#define M_LXOR(a,b) emit_alu_reg_reg(cd, ALU_XOR, (a), (b)) + +#define M_LAND_IMM(a,b) emit_alu_imm_reg(cd, ALU_AND, (a), (b)) +#define M_LOR_IMM(a,b) emit_alu_imm_reg(cd, ALU_OR, (a), (b)) +#define M_LXOR_IMM(a,b) emit_alu_imm_reg(cd, ALU_XOR, (a), (b)) + +#define M_BSEXT(a,b) emit_movsbq_reg_reg(cd, (a), (b)) +#define M_SSEXT(a,b) emit_movswq_reg_reg(cd, (a), (b)) +#define M_ISEXT(a,b) emit_movslq_reg_reg(cd, (a), (b)) + +#define M_CZEXT(a,b) emit_movzwq_reg_reg(cd, (a), (b)) + +#define M_ISLL_IMM(a,b) emit_shiftl_imm_reg(cd, SHIFT_SHL, (a), (b)) +#define M_ISRA_IMM(a,b) emit_shiftl_imm_reg(cd, SHIFT_SAR, (a), (b)) +#define M_ISRL_IMM(a,b) emit_shiftl_imm_reg(cd, SHIFT_SHR, (a), (b)) + +#define M_LSLL_IMM(a,b) emit_shift_imm_reg(cd, SHIFT_SHL, (a), (b)) +#define M_LSRA_IMM(a,b) emit_shift_imm_reg(cd, SHIFT_SAR, (a), (b)) +#define M_LSRL_IMM(a,b) emit_shift_imm_reg(cd, SHIFT_SHR, (a), (b)) + +#define M_TEST(a) emit_test_reg_reg(cd, (a), (a)) +#define M_ITEST(a) emit_testl_reg_reg(cd, (a), (a)) + +#define M_LCMP(a,b) emit_alu_reg_reg(cd, ALU_CMP, (a), (b)) +#define M_LCMP_IMM(a,b) emit_alu_imm_reg(cd, ALU_CMP, (a), (b)) +#define M_LCMP_IMM_MEMBASE(a,b,c) emit_alu_imm_membase(cd, ALU_CMP, (a), (b), (c)) +#define M_LCMP_MEMBASE(a,b,c) emit_alu_membase_reg(cd, ALU_CMP, (a), (b), (c)) + +#define M_ICMP(a,b) emit_alul_reg_reg(cd, ALU_CMP, (a), (b)) +#define M_ICMP_IMM(a,b) emit_alul_imm_reg(cd, ALU_CMP, (a), (b)) +#define M_ICMP_IMM_MEMBASE(a,b,c) emit_alul_imm_membase(cd, ALU_CMP, (a), (b), (c)) +#define M_ICMP_MEMBASE(a,b,c) emit_alul_membase_reg(cd, ALU_CMP, (a), (b), (c)) + +#define M_BEQ(disp) emit_jcc(cd, CC_E, (disp)) +#define M_BNE(disp) emit_jcc(cd, CC_NE, (disp)) +#define M_BLT(disp) emit_jcc(cd, CC_L, (disp)) +#define M_BLE(disp) emit_jcc(cd, CC_LE, (disp)) +#define M_BGE(disp) emit_jcc(cd, CC_GE, (disp)) +#define M_BGT(disp) emit_jcc(cd, CC_G, (disp)) +#define M_BAE(disp) emit_jcc(cd, CC_AE, (disp)) +#define M_BA(disp) emit_jcc(cd, CC_A, (disp)) + +#define M_CMOVEQ(a,b) emit_cmovcc_reg_reg(cd, CC_E, (a), (b)) +#define M_CMOVNE(a,b) emit_cmovcc_reg_reg(cd, CC_NE, (a), (b)) +#define M_CMOVLT(a,b) emit_cmovcc_reg_reg(cd, CC_L, (a), (b)) +#define M_CMOVLE(a,b) emit_cmovcc_reg_reg(cd, CC_LE, (a), (b)) +#define M_CMOVGE(a,b) emit_cmovcc_reg_reg(cd, CC_GE, (a), (b)) +#define M_CMOVGT(a,b) emit_cmovcc_reg_reg(cd, CC_G, (a), (b)) + +#define M_CMOVEQ_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_E, (a), (b)) +#define M_CMOVNE_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_NE, (a), (b)) +#define M_CMOVLT_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_L, (a), (b)) +#define M_CMOVLE_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_LE, (a), (b)) +#define M_CMOVGE_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_GE, (a), (b)) +#define M_CMOVGT_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_G, (a), (b)) + +#define M_CMOVB(a,b) emit_cmovcc_reg_reg(cd, CC_B, (a), (b)) +#define M_CMOVA(a,b) emit_cmovcc_reg_reg(cd, CC_A, (a), (b)) +#define M_CMOVP(a,b) emit_cmovcc_reg_reg(cd, CC_P, (a), (b)) + +#define M_PUSH(a) emit_push_reg(cd, (a)) +#define M_PUSH_IMM(a) emit_push_imm(cd, (a)) +#define M_POP(a) emit_pop_reg(cd, (a)) + +#define M_JMP(a) emit_jmp_reg(cd, (a)) +#define M_JMP_IMM(a) emit_jmp_imm(cd, (a)) +#define M__CALL(a) emit_call_reg(cd, (a)) +#define M_CALL_IMM(a) emit_call_imm(cd, (a)) +#define M_RET emit_ret(cd) + +#define M_NOP emit_nop(cd) + +#define M_CLR(a) M_LXOR(a,a) + + +#define M__FLD(a,b,disp) emit_movss_membase_reg(cd, (b), (disp), (a)) +#define M__DLD(a,b,disp) emit_movsd_membase_reg(cd, (b), (disp), (a)) + +#define M_FLD32(a,b,disp) emit_movss_membase32_reg(cd, (b), (disp), (a)) +#define M_DLD32(a,b,disp) emit_movsd_membase32_reg(cd, (b), (disp), (a)) + +#define M_FST(a,b,disp) emit_movss_reg_membase(cd, (a), (b), (disp)) +#define M_DST(a,b,disp) emit_movsd_reg_membase(cd, (a), (b), (disp)) + +#define M_FST32(a,b,disp) emit_movss_reg_membase32(cd, (a), (b), (disp)) +#define M_DST32(a,b,disp) emit_movsd_reg_membase32(cd, (a), (b), (disp)) + +#define M_FADD(a,b) emit_addss_reg_reg(cd, (a), (b)) +#define M_DADD(a,b) emit_addsd_reg_reg(cd, (a), (b)) +#define M_FSUB(a,b) emit_subss_reg_reg(cd, (a), (b)) +#define M_DSUB(a,b) emit_subsd_reg_reg(cd, (a), (b)) +#define M_FMUL(a,b) emit_mulss_reg_reg(cd, (a), (b)) +#define M_DMUL(a,b) emit_mulsd_reg_reg(cd, (a), (b)) +#define M_FDIV(a,b) emit_divss_reg_reg(cd, (a), (b)) +#define M_DDIV(a,b) emit_divsd_reg_reg(cd, (a), (b)) + +#define M_CVTIF(a,b) emit_cvtsi2ss_reg_reg(cd, (a), (b)) +#define M_CVTID(a,b) emit_cvtsi2sd_reg_reg(cd, (a), (b)) +#define M_CVTLF(a,b) emit_cvtsi2ssq_reg_reg(cd, (a), (b)) +#define M_CVTLD(a,b) emit_cvtsi2sdq_reg_reg(cd, (a), (b)) +#define M_CVTFI(a,b) emit_cvttss2si_reg_reg(cd, (a), (b)) +#define M_CVTDI(a,b) emit_cvttsd2si_reg_reg(cd, (a), (b)) +#define M_CVTFL(a,b) emit_cvttss2siq_reg_reg(cd, (a), (b)) +#define M_CVTDL(a,b) emit_cvttsd2siq_reg_reg(cd, (a), (b)) + +#define M_CVTFD(a,b) emit_cvtss2sd_reg_reg(cd, (a), (b)) +#define M_CVTDF(a,b) emit_cvtsd2ss_reg_reg(cd, (a), (b)) + + +/* system instructions ********************************************************/ + +#define M_RDTSC emit_rdtsc(cd) + +#define M_IINC_MEMBASE(a,b) emit_incl_membase(cd, (a), (b)) + +#define M_IADD_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_ADD, (a), (b), (c)) +#define M_IADC_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_ADC, (a), (b), (c)) +#define M_ISUB_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_SUB, (a), (b), (c)) +#define M_ISBB_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_SBB, (a), (b), (c)) + +#define PROFILE_CYCLE_START +#define __PROFILE_CYCLE_START \ + do { \ + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { \ + M_PUSH(RAX); \ + M_PUSH(RDX); \ + \ + M_MOV_IMM(code, REG_ITMP3); \ + M_RDTSC; \ + M_ISUB_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); \ + M_ISBB_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); \ + \ + M_POP(RDX); \ + M_POP(RAX); \ + } \ + } while (0) + +#define PROFILE_CYCLE_STOP +#define __PROFILE_CYCLE_STOP \ + do { \ + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { \ + M_PUSH(RAX); \ + M_PUSH(RDX); \ + \ + M_MOV_IMM(code, REG_ITMP3); \ + M_RDTSC; \ + M_IADD_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); \ + M_IADC_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); \ + \ + M_POP(RDX); \ + M_POP(RAX); \ + } \ + } while (0) + + +/* function gen_resolvebranch ************************************************** + + backpatches a branch instruction + + parameters: ip ... pointer to instruction after branch (void*) + so ... offset of instruction after branch (s8) + to ... offset of branch target (s8) + +*******************************************************************************/ + +#define gen_resolvebranch(ip,so,to) \ + *((s4*) ((ip) - 4)) = (s4) ((to) - (so)); + +#endif /* _CODEGEN_H */ + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/vm/jit/s390/disass.c b/src/vm/jit/s390/disass.c new file mode 100644 index 000000000..4077fe525 --- /dev/null +++ b/src/vm/jit/s390/disass.c @@ -0,0 +1,129 @@ +/* src/vm/jit/x86_64/disass.c - wrapper functions for GNU binutils disassembler + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Andreas Krall + Reinhard Grafl + + Changes: Christian Thalinger + + $Id: disass.c 7219 2007-01-16 22:18:57Z pm $ + +*/ + + +#include "config.h" + +#include +#include + +#include "vm/types.h" + +#include "vm/global.h" +#include "vm/jit/disass.h" + + +/* global variables ***********************************************************/ + +/* name table for 16 integer registers */ + +char *regs[] = { + "r0", + "r1", + "r2", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15" +}; + + +/* disassinstr ***************************************************************** + + Outputs a disassembler listing of one machine code instruction on + `stdout'. + + code: pointer to machine code + +*******************************************************************************/ + +u1 *disassinstr(u1 *code) +{ + s4 seqlen; + s4 i; + + if (!disass_initialized) { + INIT_DISASSEMBLE_INFO(info, NULL, disass_printf); + + /* setting the struct members must be done after + INIT_DISASSEMBLE_INFO */ + + info.mach = bfd_mach_s390_31; + info.read_memory_func = &disass_buffer_read_memory; + + disass_initialized = true; + } + + printf("0x%08x: ", (s4) code); + + disass_len = 0; + + seqlen = print_insn_s390((bfd_vma) code, &info); + + for (i = 0; i < seqlen; i++, code++) { + printf("%02x ", *code); + } + + for (; i < 10; i++) { + printf(" "); + } + + printf(" %s\n", disass_buf); + + return code; +} + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/vm/jit/s390/emit.c b/src/vm/jit/s390/emit.c new file mode 100644 index 000000000..d9a3c1f3b --- /dev/null +++ b/src/vm/jit/s390/emit.c @@ -0,0 +1,2237 @@ +/* src/vm/jit/x86_64/emit.c - x86_64 code emitter functions + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + + $Id: emit.c 7219 2007-01-16 22:18:57Z pm $ + +*/ + +#include "config.h" + +#include "vm/types.h" + +#include "md-abi.h" + +#include "vm/jit/s390/codegen.h" +#include "vm/jit/s390/emit.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#endif + +#include "vm/builtin.h" +#include "vm/jit/abi-asm.h" +#include "vm/jit/asmpart.h" +#include "vm/jit/codegen-common.h" +#include "vm/jit/emit-common.h" +#include "vm/jit/jit.h" +#include "vm/jit/replace.h" + +#define __PORTED__ + +/* emit_load ******************************************************************* + + Emits a possible load of an operand. + +*******************************************************************************/ + +__PORTED__ s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg) +{ + codegendata *cd; + s4 disp; + s4 reg; + + /* get required compiler data */ + + cd = jd->cd; + + if (IS_INMEMORY(src->flags)) { + COUNT_SPILLS; + + disp = src->vv.regoff * 4; + + if (IS_FLT_DBL_TYPE(src->type)) { + if (IS_2_WORD_TYPE(src->type)) + M_DLD(tempreg, REG_SP, disp); + else + M_FLD(tempreg, REG_SP, disp); + } + else { + if (IS_2_WORD_TYPE(src->type)) + M_LLD(tempreg, REG_SP, disp); + else + M_ILD(tempreg, REG_SP, disp); + } + + reg = tempreg; + } + else + reg = src->vv.regoff; + + return reg; +} + + +/* emit_store ****************************************************************** + + This function generates the code to store the result of an + operation back into a spilled pseudo-variable. If the + pseudo-variable has not been spilled in the first place, this + function will generate nothing. + +*******************************************************************************/ + +inline void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d) +{ + codegendata *cd; + s4 disp; +#if 0 + s4 s; + u2 opcode; +#endif + + /* get required compiler data */ + + cd = jd->cd; + +#if 0 + /* do we have to generate a conditional move? */ + + if ((iptr != NULL) && (iptr->opc & ICMD_CONDITION_MASK)) { + /* the passed register d is actually the source register */ + + s = d; + + /* Only pass the opcode to codegen_reg_of_var to get the real + destination register. */ + + opcode = iptr->opc & ICMD_OPCODE_MASK; + + /* get the real destination register */ + + d = codegen_reg_of_var(rd, opcode, dst, REG_ITMP1); + + /* and emit the conditional move */ + + emit_cmovxx(cd, iptr, s, d); + } +#endif + + if (IS_INMEMORY(dst->flags)) { + COUNT_SPILLS; + + disp = dst->vv.regoff * 8; + + if (IS_FLT_DBL_TYPE(dst->type)) { + if (IS_2_WORD_TYPE(dst->type)) + M_DST(d, REG_SP, disp); + else + M_FST(d, REG_SP, disp); + } + else + M_LST(d, REG_SP, disp); + } +} + + +/* emit_copy ******************************************************************* + + Generates a register/memory to register/memory copy. + +*******************************************************************************/ + +void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst) +{ + codegendata *cd; + s4 s1, d; + + /* get required compiler data */ + + cd = jd->cd; + + if ((src->vv.regoff != dst->vv.regoff) || + ((src->flags ^ dst->flags) & INMEMORY)) { + + /* If one of the variables resides in memory, we can eliminate + the register move from/to the temporary register with the + order of getting the destination register and the load. */ + + if (IS_INMEMORY(src->flags)) { + d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP); + s1 = emit_load(jd, iptr, src, d); + } + else { + s1 = emit_load(jd, iptr, src, REG_IFTMP); + d = codegen_reg_of_var(iptr->opc, dst, s1); + } + + if (s1 != d) { + if (IS_FLT_DBL_TYPE(src->type)) + M_FMOV(s1, d); + else + M_MOV(s1, d); + } + + emit_store(jd, iptr, dst, d); + } +} + + +void emit_cmovxx(codegendata *cd, instruction *iptr, s4 s, s4 d) +{ +#if 0 + switch (iptr->flags.fields.condition) { + case ICMD_IFEQ: + M_CMOVEQ(s, d); + break; + case ICMD_IFNE: + M_CMOVNE(s, d); + break; + case ICMD_IFLT: + M_CMOVLT(s, d); + break; + case ICMD_IFGE: + M_CMOVGE(s, d); + break; + case ICMD_IFGT: + M_CMOVGT(s, d); + break; + case ICMD_IFLE: + M_CMOVLE(s, d); + break; + } +#endif +} + + +/* emit_exception_stubs ******************************************************** + + Generates the code for the exception stubs. + +*******************************************************************************/ + +void emit_exception_stubs(jitdata *jd) +{ + codegendata *cd; + registerdata *rd; + exceptionref *er; + s4 branchmpc; + s4 targetmpc; + s4 targetdisp; + + /* get required compiler data */ + + cd = jd->cd; + rd = jd->rd; + + /* generate exception stubs */ + + targetdisp = 0; + + for (er = cd->exceptionrefs; er != NULL; er = er->next) { + /* back-patch the branch to this exception code */ + + branchmpc = er->branchpos; + targetmpc = cd->mcodeptr - cd->mcodebase; + + md_codegen_patch_branch(cd, branchmpc, targetmpc); + + MCODECHECK(512); + + /* Check if the exception is an + ArrayIndexOutOfBoundsException. If so, move index register + into a4. */ + + if (er->reg != -1) + M_MOV(er->reg, rd->argintregs[4]); + + /* calcuate exception address */ + + M_MOV_IMM(0, rd->argintregs[3]); + dseg_adddata(cd); + M_AADD_IMM32(er->branchpos - 6, rd->argintregs[3]); + + /* move function to call into REG_ITMP3 */ + + M_MOV_IMM(er->function, REG_ITMP3); + + if (targetdisp == 0) { + targetdisp = cd->mcodeptr - cd->mcodebase; + + emit_lea_membase_reg(cd, RIP, -((cd->mcodeptr + 7) - cd->mcodebase), rd->argintregs[0]); + M_MOV(REG_SP, rd->argintregs[1]); + M_ALD(rd->argintregs[2], REG_SP, cd->stackframesize * 8); + + M_ASUB_IMM(2 * 8, REG_SP); + M_AST(rd->argintregs[3], REG_SP, 0 * 8); /* store XPC */ + + M_CALL(REG_ITMP3); + + M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8); + M_AADD_IMM(2 * 8, REG_SP); + + M_MOV_IMM(asm_handle_exception, REG_ITMP3); + M_JMP(REG_ITMP3); + } + else { + M_JMP_IMM((cd->mcodebase + targetdisp) - + (cd->mcodeptr + PATCHER_CALL_SIZE)); + } + } +} + + +/* emit_patcher_stubs ********************************************************** + + Generates the code for the patcher stubs. + +*******************************************************************************/ + +void emit_patcher_stubs(jitdata *jd) +{ + codegendata *cd; + patchref *pref; + u8 mcode; + u1 *savedmcodeptr; + u1 *tmpmcodeptr; + s4 targetdisp; + s4 disp; + + /* get required compiler data */ + + cd = jd->cd; + + /* generate code patching stub call code */ + + targetdisp = 0; + + for (pref = cd->patchrefs; pref != NULL; pref = pref->next) { + /* check size of code segment */ + + MCODECHECK(512); + + /* Get machine code which is patched back in later. A + `call rel32' is 5 bytes long (but read 8 bytes). */ + + savedmcodeptr = cd->mcodebase + pref->branchpos; + mcode = *((u8 *) savedmcodeptr); + + /* patch in `call rel32' to call the following code */ + + tmpmcodeptr = cd->mcodeptr; /* save current mcodeptr */ + cd->mcodeptr = savedmcodeptr; /* set mcodeptr to patch position */ + + M_CALL_IMM(tmpmcodeptr - (savedmcodeptr + PATCHER_CALL_SIZE)); + + cd->mcodeptr = tmpmcodeptr; /* restore the current mcodeptr */ + + /* move pointer to java_objectheader onto stack */ + +#if defined(ENABLE_THREADS) + /* create a virtual java_objectheader */ + + (void) dseg_add_unique_address(cd, NULL); /* flcword */ + (void) dseg_add_unique_address(cd, lock_get_initial_lock_word()); + disp = dseg_add_unique_address(cd, NULL); /* vftbl */ + + emit_lea_membase_reg(cd, RIP, -((cd->mcodeptr + 7) - cd->mcodebase) + disp, REG_ITMP3); + M_PUSH(REG_ITMP3); +#else + M_PUSH_IMM(0); +#endif + + /* move machine code bytes and classinfo pointer into registers */ + + M_MOV_IMM(mcode, REG_ITMP3); + M_PUSH(REG_ITMP3); + + M_MOV_IMM(pref->ref, REG_ITMP3); + M_PUSH(REG_ITMP3); + + M_MOV_IMM(pref->disp, REG_ITMP3); + M_PUSH(REG_ITMP3); + + M_MOV_IMM(pref->patcher, REG_ITMP3); + M_PUSH(REG_ITMP3); + + if (targetdisp == 0) { + targetdisp = cd->mcodeptr - cd->mcodebase; + + M_MOV_IMM(asm_patcher_wrapper, REG_ITMP3); + M_JMP(REG_ITMP3); + } + else { + M_JMP_IMM((cd->mcodebase + targetdisp) - + (cd->mcodeptr + PATCHER_CALL_SIZE)); + } + } +} + + +/* emit_replacement_stubs ****************************************************** + + Generates the code for the replacement stubs. + +*******************************************************************************/ + +void emit_replacement_stubs(jitdata *jd) +{ + codegendata *cd; + codeinfo *code; + rplpoint *rplp; + s4 disp; + s4 i; + + /* get required compiler data */ + + cd = jd->cd; + code = jd->code; + + rplp = code->rplpoints; + + for (i = 0; i < code->rplpointcount; ++i, ++rplp) { + /* check code segment size */ + + MCODECHECK(512); + + /* note start of stub code */ + + rplp->outcode = (u1 *) (ptrint) (cd->mcodeptr - cd->mcodebase); + + /* make machine code for patching */ + + disp = (ptrint) (rplp->outcode - rplp->pc) - 5; + + rplp->mcode = 0xe9 | ((u8) disp << 8); + + /* push address of `rplpoint` struct */ + + M_MOV_IMM(rplp, REG_ITMP3); + M_PUSH(REG_ITMP3); + + /* jump to replacement function */ + + M_MOV_IMM(asm_replacement_out, REG_ITMP3); + M_JMP(REG_ITMP3); + } +} + + +/* emit_verbosecall_enter ****************************************************** + + Generates the code for the call trace. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void emit_verbosecall_enter(jitdata *jd) +{ + methodinfo *m; + codegendata *cd; + registerdata *rd; + methoddesc *md; + s4 i, j, k; + + /* get required compiler data */ + + m = jd->m; + cd = jd->cd; + rd = jd->rd; + + md = m->parseddesc; + + /* mark trace code */ + + M_NOP; + + /* additional +1 is for 16-byte stack alignment */ + + M_LSUB_IMM((ARG_CNT + TMP_CNT + 1 + 1) * 8, REG_SP); + + /* save argument registers */ + + for (i = 0; i < INT_ARG_CNT; i++) + M_LST(rd->argintregs[i], REG_SP, (1 + i) * 8); + + for (i = 0; i < FLT_ARG_CNT; i++) + M_DST(rd->argfltregs[i], REG_SP, (1 + INT_ARG_CNT + i) * 8); + + /* save temporary registers for leaf methods */ + + if (jd->isleafmethod) { + for (i = 0; i < INT_TMP_CNT; i++) + M_LST(rd->tmpintregs[i], REG_SP, (1 + ARG_CNT + i) * 8); + + for (i = 0; i < FLT_TMP_CNT; i++) + M_DST(rd->tmpfltregs[i], REG_SP, (1 + ARG_CNT + INT_TMP_CNT + i) * 8); + } + + /* show integer hex code for float arguments */ + + for (i = 0, j = 0; i < md->paramcount && i < INT_ARG_CNT; i++) { + /* If the paramtype is a float, we have to right shift all + following integer registers. */ + + if (IS_FLT_DBL_TYPE(md->paramtypes[i].type)) { + for (k = INT_ARG_CNT - 2; k >= i; k--) + M_MOV(rd->argintregs[k], rd->argintregs[k + 1]); + + emit_movd_freg_reg(cd, rd->argfltregs[j], rd->argintregs[i]); + j++; + } + } + + M_MOV_IMM(m, REG_ITMP2); + M_AST(REG_ITMP2, REG_SP, 0 * 8); + M_MOV_IMM(builtin_trace_args, REG_ITMP1); + M_CALL(REG_ITMP1); + + /* restore argument registers */ + + for (i = 0; i < INT_ARG_CNT; i++) + M_LLD(rd->argintregs[i], REG_SP, (1 + i) * 8); + + for (i = 0; i < FLT_ARG_CNT; i++) + M_DLD(rd->argfltregs[i], REG_SP, (1 + INT_ARG_CNT + i) * 8); + + /* restore temporary registers for leaf methods */ + + if (jd->isleafmethod) { + for (i = 0; i < INT_TMP_CNT; i++) + M_LLD(rd->tmpintregs[i], REG_SP, (1 + ARG_CNT + i) * 8); + + for (i = 0; i < FLT_TMP_CNT; i++) + M_DLD(rd->tmpfltregs[i], REG_SP, (1 + ARG_CNT + INT_TMP_CNT + i) * 8); + } + + M_LADD_IMM((ARG_CNT + TMP_CNT + 1 + 1) * 8, REG_SP); + + /* mark trace code */ + + M_NOP; +} +#endif /* !defined(NDEBUG) */ + + +/* emit_verbosecall_exit ******************************************************* + + Generates the code for the call trace. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void emit_verbosecall_exit(jitdata *jd) +{ + methodinfo *m; + codegendata *cd; + registerdata *rd; + + /* get required compiler data */ + + m = jd->m; + cd = jd->cd; + rd = jd->rd; + + /* mark trace code */ + + M_NOP; + + M_ASUB_IMM(2 * 8, REG_SP); + + M_LST(REG_RESULT, REG_SP, 0 * 8); + M_DST(REG_FRESULT, REG_SP, 1 * 8); + + M_MOV_IMM(m, rd->argintregs[0]); + M_MOV(REG_RESULT, rd->argintregs[1]); + M_FLTMOVE(REG_FRESULT, rd->argfltregs[0]); + M_FLTMOVE(REG_FRESULT, rd->argfltregs[1]); + + M_MOV_IMM(builtin_displaymethodstop, REG_ITMP1); + M_CALL(REG_ITMP1); + + M_LLD(REG_RESULT, REG_SP, 0 * 8); + M_DLD(REG_FRESULT, REG_SP, 1 * 8); + + M_AADD_IMM(2 * 8, REG_SP); + + /* mark trace code */ + + M_NOP; +} +#endif /* !defined(NDEBUG) */ + + +/* code generation functions **************************************************/ + +static void emit_membase(codegendata *cd, s4 basereg, s4 disp, s4 dreg) +{ + if ((basereg == REG_SP) || (basereg == R12)) { + if (disp == 0) { + emit_address_byte(0, dreg, REG_SP); + emit_address_byte(0, REG_SP, REG_SP); + + } else if (IS_IMM8(disp)) { + emit_address_byte(1, dreg, REG_SP); + emit_address_byte(0, REG_SP, REG_SP); + emit_imm8(disp); + + } else { + emit_address_byte(2, dreg, REG_SP); + emit_address_byte(0, REG_SP, REG_SP); + emit_imm32(disp); + } + + } else if ((disp) == 0 && (basereg) != RBP && (basereg) != R13) { + emit_address_byte(0,(dreg),(basereg)); + + } else if ((basereg) == RIP) { + emit_address_byte(0, dreg, RBP); + emit_imm32(disp); + + } else { + if (IS_IMM8(disp)) { + emit_address_byte(1, dreg, basereg); + emit_imm8(disp); + + } else { + emit_address_byte(2, dreg, basereg); + emit_imm32(disp); + } + } +} + + +static void emit_membase32(codegendata *cd, s4 basereg, s4 disp, s4 dreg) +{ + if ((basereg == REG_SP) || (basereg == R12)) { + emit_address_byte(2, dreg, REG_SP); + emit_address_byte(0, REG_SP, REG_SP); + emit_imm32(disp); + } + else { + emit_address_byte(2, dreg, basereg); + emit_imm32(disp); + } +} + + +static void emit_memindex(codegendata *cd, s4 reg, s4 disp, s4 basereg, s4 indexreg, s4 scale) +{ + if (basereg == -1) { + emit_address_byte(0, reg, 4); + emit_address_byte(scale, indexreg, 5); + emit_imm32(disp); + } + else if ((disp == 0) && (basereg != RBP) && (basereg != R13)) { + emit_address_byte(0, reg, 4); + emit_address_byte(scale, indexreg, basereg); + } + else if (IS_IMM8(disp)) { + emit_address_byte(1, reg, 4); + emit_address_byte(scale, indexreg, basereg); + emit_imm8(disp); + } + else { + emit_address_byte(2, reg, 4); + emit_address_byte(scale, indexreg, basereg); + emit_imm32(disp); + } +} + + +void emit_ishift(jitdata *jd, s4 shift_op, instruction *iptr) +{ + s4 s1, s2, d, d_old; + varinfo *v_s1,*v_s2,*v_dst; + codegendata *cd; + + /* get required compiler data */ + + cd = jd->cd; + + v_s1 = VAROP(iptr->s1); + v_s2 = VAROP(iptr->sx.s23.s2); + v_dst = VAROP(iptr->dst); + + s1 = v_s1->vv.regoff; + s2 = v_s2->vv.regoff; + d = v_dst->vv.regoff; + + M_INTMOVE(RCX, REG_ITMP1); /* save RCX */ + + if (IS_INMEMORY(v_dst->flags)) { + if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { + if (s1 == d) { + M_ILD(RCX, REG_SP, s2 * 8); + emit_shiftl_membase(cd, shift_op, REG_SP, d * 8); + + } else { + M_ILD(RCX, REG_SP, s2 * 8); + M_ILD(REG_ITMP2, REG_SP, s1 * 8); + emit_shiftl_reg(cd, shift_op, REG_ITMP2); + M_IST(REG_ITMP2, REG_SP, d * 8); + } + + } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) { + /* s1 may be equal to RCX */ + if (s1 == RCX) { + if (s2 == d) { + M_ILD(REG_ITMP1, REG_SP, s2 * 8); + M_IST(s1, REG_SP, d * 8); + M_INTMOVE(REG_ITMP1, RCX); + + } else { + M_IST(s1, REG_SP, d * 8); + M_ILD(RCX, REG_SP, s2 * 8); + } + + } else { + M_ILD(RCX, REG_SP, s2 * 8); + M_IST(s1, REG_SP, d * 8); + } + + emit_shiftl_membase(cd, shift_op, REG_SP, d * 8); + + } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { + if (s1 == d) { + M_INTMOVE(s2, RCX); + emit_shiftl_membase(cd, shift_op, REG_SP, d * 8); + + } else { + M_INTMOVE(s2, RCX); + M_ILD(REG_ITMP2, REG_SP, s1 * 8); + emit_shiftl_reg(cd, shift_op, REG_ITMP2); + M_IST(REG_ITMP2, REG_SP, d * 8); + } + + } else { + /* s1 may be equal to RCX */ + M_IST(s1, REG_SP, d * 8); + M_INTMOVE(s2, RCX); + emit_shiftl_membase(cd, shift_op, REG_SP, d * 8); + } + + M_INTMOVE(REG_ITMP1, RCX); /* restore RCX */ + + } else { + d_old = d; + if (d == RCX) { + d = REG_ITMP3; + } + + if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { + M_ILD(RCX, REG_SP, s2 * 8); + M_ILD(d, REG_SP, s1 * 8); + emit_shiftl_reg(cd, shift_op, d); + + } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) { + /* s1 may be equal to RCX */ + M_INTMOVE(s1, d); + M_ILD(RCX, REG_SP, s2 * 8); + emit_shiftl_reg(cd, shift_op, d); + + } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { + M_INTMOVE(s2, RCX); + M_ILD(d, REG_SP, s1 * 8); + emit_shiftl_reg(cd, shift_op, d); + + } else { + /* s1 may be equal to RCX */ + if (s1 == RCX) { + if (s2 == d) { + /* d cannot be used to backup s1 since this would + overwrite s2. */ + M_INTMOVE(s1, REG_ITMP3); + M_INTMOVE(s2, RCX); + M_INTMOVE(REG_ITMP3, d); + + } else { + M_INTMOVE(s1, d); + M_INTMOVE(s2, RCX); + } + + } else { + /* d may be equal to s2 */ + M_INTMOVE(s2, RCX); + M_INTMOVE(s1, d); + } + emit_shiftl_reg(cd, shift_op, d); + } + + if (d_old == RCX) + M_INTMOVE(REG_ITMP3, RCX); + else + M_INTMOVE(REG_ITMP1, RCX); /* restore RCX */ + } +} + + +void emit_lshift(jitdata *jd, s4 shift_op, instruction *iptr) +{ + s4 s1, s2, d, d_old; + varinfo *v_s1,*v_s2,*v_dst; + codegendata *cd; + + /* get required compiler data */ + + cd = jd->cd; + + v_s1 = VAROP(iptr->s1); + v_s2 = VAROP(iptr->sx.s23.s2); + v_dst = VAROP(iptr->dst); + + s1 = v_s1->vv.regoff; + s2 = v_s2->vv.regoff; + d = v_dst->vv.regoff; + + M_INTMOVE(RCX, REG_ITMP1); /* save RCX */ + + if (IS_INMEMORY(v_dst->flags)) { + if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { + if (s1 == d) { + M_ILD(RCX, REG_SP, s2 * 8); + emit_shift_membase(cd, shift_op, REG_SP, d * 8); + + } else { + M_ILD(RCX, REG_SP, s2 * 8); + M_LLD(REG_ITMP2, REG_SP, s1 * 8); + emit_shift_reg(cd, shift_op, REG_ITMP2); + M_LST(REG_ITMP2, REG_SP, d * 8); + } + + } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) { + /* s1 may be equal to RCX */ + if (s1 == RCX) { + if (s2 == d) { + M_ILD(REG_ITMP1, REG_SP, s2 * 8); + M_LST(s1, REG_SP, d * 8); + M_INTMOVE(REG_ITMP1, RCX); + + } else { + M_LST(s1, REG_SP, d * 8); + M_ILD(RCX, REG_SP, s2 * 8); + } + + } else { + M_ILD(RCX, REG_SP, s2 * 8); + M_LST(s1, REG_SP, d * 8); + } + + emit_shift_membase(cd, shift_op, REG_SP, d * 8); + + } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { + if (s1 == d) { + M_INTMOVE(s2, RCX); + emit_shift_membase(cd, shift_op, REG_SP, d * 8); + + } else { + M_INTMOVE(s2, RCX); + M_LLD(REG_ITMP2, REG_SP, s1 * 8); + emit_shift_reg(cd, shift_op, REG_ITMP2); + M_LST(REG_ITMP2, REG_SP, d * 8); + } + + } else { + /* s1 may be equal to RCX */ + M_LST(s1, REG_SP, d * 8); + M_INTMOVE(s2, RCX); + emit_shift_membase(cd, shift_op, REG_SP, d * 8); + } + + M_INTMOVE(REG_ITMP1, RCX); /* restore RCX */ + + } else { + d_old = d; + if (d == RCX) { + d = REG_ITMP3; + } + + if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { + M_ILD(RCX, REG_SP, s2 * 8); + M_LLD(d, REG_SP, s1 * 8); + emit_shift_reg(cd, shift_op, d); + + } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) { + /* s1 may be equal to RCX */ + M_INTMOVE(s1, d); + M_ILD(RCX, REG_SP, s2 * 8); + emit_shift_reg(cd, shift_op, d); + + } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { + M_INTMOVE(s2, RCX); + M_LLD(d, REG_SP, s1 * 8); + emit_shift_reg(cd, shift_op, d); + + } else { + /* s1 may be equal to RCX */ + if (s1 == RCX) { + if (s2 == d) { + /* d cannot be used to backup s1 since this would + overwrite s2. */ + M_INTMOVE(s1, REG_ITMP3); + M_INTMOVE(s2, RCX); + M_INTMOVE(REG_ITMP3, d); + + } else { + M_INTMOVE(s1, d); + M_INTMOVE(s2, RCX); + } + + } else { + /* d may be equal to s2 */ + M_INTMOVE(s2, RCX); + M_INTMOVE(s1, d); + } + emit_shift_reg(cd, shift_op, d); + } + + if (d_old == RCX) + M_INTMOVE(REG_ITMP3, RCX); + else + M_INTMOVE(REG_ITMP1, RCX); /* restore RCX */ + } +} + + +/* low-level code emitter functions *******************************************/ + +void emit_mov_reg_reg(codegendata *cd, s8 reg, s8 dreg) +{ + emit_rex(1,(reg),0,(dreg)); + *(cd->mcodeptr++) = 0x89; + emit_reg((reg),(dreg)); +} + + +void emit_mov_imm_reg(codegendata *cd, s8 imm, s8 reg) +{ + emit_rex(1,0,0,(reg)); + *(cd->mcodeptr++) = 0xb8 + ((reg) & 0x07); + emit_imm64((imm)); +} + + +void emit_movl_reg_reg(codegendata *cd, s8 reg, s8 dreg) +{ + emit_rex(0,(reg),0,(dreg)); + *(cd->mcodeptr++) = 0x89; + emit_reg((reg),(dreg)); +} + + +void emit_movl_imm_reg(codegendata *cd, s8 imm, s8 reg) { + emit_rex(0,0,0,(reg)); + *(cd->mcodeptr++) = 0xb8 + ((reg) & 0x07); + emit_imm32((imm)); +} + + +void emit_mov_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) { + emit_rex(1,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x8b; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +/* + * this one is for INVOKEVIRTUAL/INVOKEINTERFACE to have a + * constant membase immediate length of 32bit + */ +void emit_mov_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) { + emit_rex(1,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x8b; + emit_membase32(cd, (basereg),(disp),(reg)); +} + + +void emit_movl_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) +{ + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x8b; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +/* ATTENTION: Always emit a REX byte, because the instruction size can + be smaller when all register indexes are smaller than 7. */ +void emit_movl_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) +{ + emit_byte_rex((reg),0,(basereg)); + *(cd->mcodeptr++) = 0x8b; + emit_membase32(cd, (basereg),(disp),(reg)); +} + + +void emit_mov_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) { + emit_rex(1,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x89; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +void emit_mov_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp) { + emit_rex(1,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x89; + emit_membase32(cd, (basereg),(disp),(reg)); +} + + +void emit_movl_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) { + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x89; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +/* Always emit a REX byte, because the instruction size can be smaller when */ +/* all register indexes are smaller than 7. */ +void emit_movl_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp) { + emit_byte_rex((reg),0,(basereg)); + *(cd->mcodeptr++) = 0x89; + emit_membase32(cd, (basereg),(disp),(reg)); +} + + +void emit_mov_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) { + emit_rex(1,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x8b; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movl_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) { + emit_rex(0,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x8b; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_mov_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) { + emit_rex(1,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x89; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movl_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) { + emit_rex(0,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x89; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movw_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) { + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x89; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movb_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) { + emit_byte_rex((reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x88; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_mov_imm_membase(codegendata *cd, s8 imm, s8 basereg, s8 disp) { + emit_rex(1,0,0,(basereg)); + *(cd->mcodeptr++) = 0xc7; + emit_membase(cd, (basereg),(disp),0); + emit_imm32((imm)); +} + + +void emit_mov_imm_membase32(codegendata *cd, s8 imm, s8 basereg, s8 disp) { + emit_rex(1,0,0,(basereg)); + *(cd->mcodeptr++) = 0xc7; + emit_membase32(cd, (basereg),(disp),0); + emit_imm32((imm)); +} + + +void emit_movl_imm_membase(codegendata *cd, s8 imm, s8 basereg, s8 disp) { + emit_rex(0,0,0,(basereg)); + *(cd->mcodeptr++) = 0xc7; + emit_membase(cd, (basereg),(disp),0); + emit_imm32((imm)); +} + + +/* Always emit a REX byte, because the instruction size can be smaller when */ +/* all register indexes are smaller than 7. */ +void emit_movl_imm_membase32(codegendata *cd, s8 imm, s8 basereg, s8 disp) { + emit_byte_rex(0,0,(basereg)); + *(cd->mcodeptr++) = 0xc7; + emit_membase32(cd, (basereg),(disp),0); + emit_imm32((imm)); +} + + +void emit_movsbq_reg_reg(codegendata *cd, s8 reg, s8 dreg) +{ + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xbe; + /* XXX: why do reg and dreg have to be exchanged */ + emit_reg((dreg),(reg)); +} + + +void emit_movswq_reg_reg(codegendata *cd, s8 reg, s8 dreg) +{ + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xbf; + /* XXX: why do reg and dreg have to be exchanged */ + emit_reg((dreg),(reg)); +} + + +void emit_movslq_reg_reg(codegendata *cd, s8 reg, s8 dreg) +{ + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x63; + /* XXX: why do reg and dreg have to be exchanged */ + emit_reg((dreg),(reg)); +} + + +void emit_movzwq_reg_reg(codegendata *cd, s8 reg, s8 dreg) +{ + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xb7; + /* XXX: why do reg and dreg have to be exchanged */ + emit_reg((dreg),(reg)); +} + + +void emit_movswq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) { + emit_rex(1,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xbf; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movsbq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) { + emit_rex(1,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xbe; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movzwq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) { + emit_rex(1,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xb7; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_mov_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale) +{ + emit_rex(1,0,(indexreg),(basereg)); + *(cd->mcodeptr++) = 0xc7; + emit_memindex(cd, 0,(disp),(basereg),(indexreg),(scale)); + emit_imm32((imm)); +} + + +void emit_movl_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale) +{ + emit_rex(0,0,(indexreg),(basereg)); + *(cd->mcodeptr++) = 0xc7; + emit_memindex(cd, 0,(disp),(basereg),(indexreg),(scale)); + emit_imm32((imm)); +} + + +void emit_movw_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale) +{ + *(cd->mcodeptr++) = 0x66; + emit_rex(0,0,(indexreg),(basereg)); + *(cd->mcodeptr++) = 0xc7; + emit_memindex(cd, 0,(disp),(basereg),(indexreg),(scale)); + emit_imm16((imm)); +} + + +void emit_movb_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale) +{ + emit_rex(0,0,(indexreg),(basereg)); + *(cd->mcodeptr++) = 0xc6; + emit_memindex(cd, 0,(disp),(basereg),(indexreg),(scale)); + emit_imm8((imm)); +} + + +/* + * alu operations + */ +void emit_alu_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg) +{ + emit_rex(1,(reg),0,(dreg)); + *(cd->mcodeptr++) = (((opc)) << 3) + 1; + emit_reg((reg),(dreg)); +} + + +void emit_alul_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg) +{ + emit_rex(0,(reg),0,(dreg)); + *(cd->mcodeptr++) = (((opc)) << 3) + 1; + emit_reg((reg),(dreg)); +} + + +void emit_alu_reg_membase(codegendata *cd, s8 opc, s8 reg, s8 basereg, s8 disp) +{ + emit_rex(1,(reg),0,(basereg)); + *(cd->mcodeptr++) = (((opc)) << 3) + 1; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +void emit_alul_reg_membase(codegendata *cd, s8 opc, s8 reg, s8 basereg, s8 disp) +{ + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = (((opc)) << 3) + 1; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +void emit_alu_membase_reg(codegendata *cd, s8 opc, s8 basereg, s8 disp, s8 reg) +{ + emit_rex(1,(reg),0,(basereg)); + *(cd->mcodeptr++) = (((opc)) << 3) + 3; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +void emit_alul_membase_reg(codegendata *cd, s8 opc, s8 basereg, s8 disp, s8 reg) +{ + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = (((opc)) << 3) + 3; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +void emit_alu_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) { + if (IS_IMM8(imm)) { + emit_rex(1,0,0,(dreg)); + *(cd->mcodeptr++) = 0x83; + emit_reg((opc),(dreg)); + emit_imm8((imm)); + } else { + emit_rex(1,0,0,(dreg)); + *(cd->mcodeptr++) = 0x81; + emit_reg((opc),(dreg)); + emit_imm32((imm)); + } +} + + +void emit_alu_imm32_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) { + emit_rex(1,0,0,(dreg)); + *(cd->mcodeptr++) = 0x81; + emit_reg((opc),(dreg)); + emit_imm32((imm)); +} + + +void emit_alul_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) { + if (IS_IMM8(imm)) { + emit_rex(0,0,0,(dreg)); + *(cd->mcodeptr++) = 0x83; + emit_reg((opc),(dreg)); + emit_imm8((imm)); + } else { + emit_rex(0,0,0,(dreg)); + *(cd->mcodeptr++) = 0x81; + emit_reg((opc),(dreg)); + emit_imm32((imm)); + } +} + + +void emit_alu_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) { + if (IS_IMM8(imm)) { + emit_rex(1,(basereg),0,0); + *(cd->mcodeptr++) = 0x83; + emit_membase(cd, (basereg),(disp),(opc)); + emit_imm8((imm)); + } else { + emit_rex(1,(basereg),0,0); + *(cd->mcodeptr++) = 0x81; + emit_membase(cd, (basereg),(disp),(opc)); + emit_imm32((imm)); + } +} + + +void emit_alul_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) { + if (IS_IMM8(imm)) { + emit_rex(0,(basereg),0,0); + *(cd->mcodeptr++) = 0x83; + emit_membase(cd, (basereg),(disp),(opc)); + emit_imm8((imm)); + } else { + emit_rex(0,(basereg),0,0); + *(cd->mcodeptr++) = 0x81; + emit_membase(cd, (basereg),(disp),(opc)); + emit_imm32((imm)); + } +} + + +void emit_test_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + emit_rex(1,(reg),0,(dreg)); + *(cd->mcodeptr++) = 0x85; + emit_reg((reg),(dreg)); +} + + +void emit_testl_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + emit_rex(0,(reg),0,(dreg)); + *(cd->mcodeptr++) = 0x85; + emit_reg((reg),(dreg)); +} + + +void emit_test_imm_reg(codegendata *cd, s8 imm, s8 reg) { + *(cd->mcodeptr++) = 0xf7; + emit_reg(0,(reg)); + emit_imm32((imm)); +} + + +void emit_testw_imm_reg(codegendata *cd, s8 imm, s8 reg) { + *(cd->mcodeptr++) = 0x66; + *(cd->mcodeptr++) = 0xf7; + emit_reg(0,(reg)); + emit_imm16((imm)); +} + + +void emit_testb_imm_reg(codegendata *cd, s8 imm, s8 reg) { + *(cd->mcodeptr++) = 0xf6; + emit_reg(0,(reg)); + emit_imm8((imm)); +} + + +void emit_lea_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) { + emit_rex(1,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x8d; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +void emit_leal_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) { + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x8d; + emit_membase(cd, (basereg),(disp),(reg)); +} + + + +void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp) +{ + emit_rex(0,0,0,(basereg)); + *(cd->mcodeptr++) = 0xff; + emit_membase(cd, (basereg),(disp),0); +} + + + +void emit_cltd(codegendata *cd) { + *(cd->mcodeptr++) = 0x99; +} + + +void emit_cqto(codegendata *cd) { + emit_rex(1,0,0,0); + *(cd->mcodeptr++) = 0x99; +} + + + +void emit_imul_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xaf; + emit_reg((dreg),(reg)); +} + + +void emit_imull_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xaf; + emit_reg((dreg),(reg)); +} + + +void emit_imul_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + emit_rex(1,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xaf; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +void emit_imull_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xaf; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +void emit_imul_imm_reg(codegendata *cd, s8 imm, s8 dreg) { + if (IS_IMM8((imm))) { + emit_rex(1,0,0,(dreg)); + *(cd->mcodeptr++) = 0x6b; + emit_reg(0,(dreg)); + emit_imm8((imm)); + } else { + emit_rex(1,0,0,(dreg)); + *(cd->mcodeptr++) = 0x69; + emit_reg(0,(dreg)); + emit_imm32((imm)); + } +} + + +void emit_imul_imm_reg_reg(codegendata *cd, s8 imm, s8 reg, s8 dreg) { + if (IS_IMM8((imm))) { + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x6b; + emit_reg((dreg),(reg)); + emit_imm8((imm)); + } else { + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x69; + emit_reg((dreg),(reg)); + emit_imm32((imm)); + } +} + + +void emit_imull_imm_reg_reg(codegendata *cd, s8 imm, s8 reg, s8 dreg) { + if (IS_IMM8((imm))) { + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x6b; + emit_reg((dreg),(reg)); + emit_imm8((imm)); + } else { + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x69; + emit_reg((dreg),(reg)); + emit_imm32((imm)); + } +} + + +void emit_imul_imm_membase_reg(codegendata *cd, s8 imm, s8 basereg, s8 disp, s8 dreg) { + if (IS_IMM8((imm))) { + emit_rex(1,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x6b; + emit_membase(cd, (basereg),(disp),(dreg)); + emit_imm8((imm)); + } else { + emit_rex(1,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x69; + emit_membase(cd, (basereg),(disp),(dreg)); + emit_imm32((imm)); + } +} + + +void emit_imull_imm_membase_reg(codegendata *cd, s8 imm, s8 basereg, s8 disp, s8 dreg) { + if (IS_IMM8((imm))) { + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x6b; + emit_membase(cd, (basereg),(disp),(dreg)); + emit_imm8((imm)); + } else { + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x69; + emit_membase(cd, (basereg),(disp),(dreg)); + emit_imm32((imm)); + } +} + + +void emit_idiv_reg(codegendata *cd, s8 reg) { + emit_rex(1,0,0,(reg)); + *(cd->mcodeptr++) = 0xf7; + emit_reg(7,(reg)); +} + + +void emit_idivl_reg(codegendata *cd, s8 reg) { + emit_rex(0,0,0,(reg)); + *(cd->mcodeptr++) = 0xf7; + emit_reg(7,(reg)); +} + + + +void emit_ret(codegendata *cd) { + *(cd->mcodeptr++) = 0xc3; +} + + + +/* + * shift ops + */ +void emit_shift_reg(codegendata *cd, s8 opc, s8 reg) { + emit_rex(1,0,0,(reg)); + *(cd->mcodeptr++) = 0xd3; + emit_reg((opc),(reg)); +} + + +void emit_shiftl_reg(codegendata *cd, s8 opc, s8 reg) { + emit_rex(0,0,0,(reg)); + *(cd->mcodeptr++) = 0xd3; + emit_reg((opc),(reg)); +} + + +void emit_shift_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp) { + emit_rex(1,0,0,(basereg)); + *(cd->mcodeptr++) = 0xd3; + emit_membase(cd, (basereg),(disp),(opc)); +} + + +void emit_shiftl_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp) { + emit_rex(0,0,0,(basereg)); + *(cd->mcodeptr++) = 0xd3; + emit_membase(cd, (basereg),(disp),(opc)); +} + + +void emit_shift_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) { + if ((imm) == 1) { + emit_rex(1,0,0,(dreg)); + *(cd->mcodeptr++) = 0xd1; + emit_reg((opc),(dreg)); + } else { + emit_rex(1,0,0,(dreg)); + *(cd->mcodeptr++) = 0xc1; + emit_reg((opc),(dreg)); + emit_imm8((imm)); + } +} + + +void emit_shiftl_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) { + if ((imm) == 1) { + emit_rex(0,0,0,(dreg)); + *(cd->mcodeptr++) = 0xd1; + emit_reg((opc),(dreg)); + } else { + emit_rex(0,0,0,(dreg)); + *(cd->mcodeptr++) = 0xc1; + emit_reg((opc),(dreg)); + emit_imm8((imm)); + } +} + + +void emit_shift_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) { + if ((imm) == 1) { + emit_rex(1,0,0,(basereg)); + *(cd->mcodeptr++) = 0xd1; + emit_membase(cd, (basereg),(disp),(opc)); + } else { + emit_rex(1,0,0,(basereg)); + *(cd->mcodeptr++) = 0xc1; + emit_membase(cd, (basereg),(disp),(opc)); + emit_imm8((imm)); + } +} + + +void emit_shiftl_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) { + if ((imm) == 1) { + emit_rex(0,0,0,(basereg)); + *(cd->mcodeptr++) = 0xd1; + emit_membase(cd, (basereg),(disp),(opc)); + } else { + emit_rex(0,0,0,(basereg)); + *(cd->mcodeptr++) = 0xc1; + emit_membase(cd, (basereg),(disp),(opc)); + emit_imm8((imm)); + } +} + + + +/* + * jump operations + */ +void emit_jmp_imm(codegendata *cd, s8 imm) { + *(cd->mcodeptr++) = 0xe9; + emit_imm32((imm)); +} + + +void emit_jmp_reg(codegendata *cd, s8 reg) { + emit_rex(0,0,0,(reg)); + *(cd->mcodeptr++) = 0xff; + emit_reg(4,(reg)); +} + + +void emit_jcc(codegendata *cd, s8 opc, s8 imm) { + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = (0x80 + (opc)); + emit_imm32((imm)); +} + + + +/* + * conditional set and move operations + */ + +/* we need the rex byte to get all low bytes */ +void emit_setcc_reg(codegendata *cd, s8 opc, s8 reg) { + *(cd->mcodeptr++) = (0x40 | (((reg) >> 3) & 0x01)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = (0x90 + (opc)); + emit_reg(0,(reg)); +} + + +/* we need the rex byte to get all low bytes */ +void emit_setcc_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp) { + *(cd->mcodeptr++) = (0x40 | (((basereg) >> 3) & 0x01)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = (0x90 + (opc)); + emit_membase(cd, (basereg),(disp),0); +} + + +void emit_cmovcc_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg) +{ + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = (0x40 + (opc)); + emit_reg((dreg),(reg)); +} + + +void emit_cmovccl_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg) +{ + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = (0x40 + (opc)); + emit_reg((dreg),(reg)); +} + + + +void emit_neg_reg(codegendata *cd, s8 reg) +{ + emit_rex(1,0,0,(reg)); + *(cd->mcodeptr++) = 0xf7; + emit_reg(3,(reg)); +} + + +void emit_negl_reg(codegendata *cd, s8 reg) +{ + emit_rex(0,0,0,(reg)); + *(cd->mcodeptr++) = 0xf7; + emit_reg(3,(reg)); +} + + +void emit_push_reg(codegendata *cd, s8 reg) { + emit_rex(0,0,0,(reg)); + *(cd->mcodeptr++) = 0x50 + (0x07 & (reg)); +} + + +void emit_push_imm(codegendata *cd, s8 imm) { + *(cd->mcodeptr++) = 0x68; + emit_imm32((imm)); +} + + +void emit_pop_reg(codegendata *cd, s8 reg) { + emit_rex(0,0,0,(reg)); + *(cd->mcodeptr++) = 0x58 + (0x07 & (reg)); +} + + +void emit_xchg_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + emit_rex(1,(reg),0,(dreg)); + *(cd->mcodeptr++) = 0x87; + emit_reg((reg),(dreg)); +} + + +void emit_nop(codegendata *cd) { + *(cd->mcodeptr++) = 0x90; +} + + + +/* + * call instructions + */ +void emit_call_reg(codegendata *cd, s8 reg) { + emit_rex(1,0,0,(reg)); + *(cd->mcodeptr++) = 0xff; + emit_reg(2,(reg)); +} + + +void emit_call_imm(codegendata *cd, s8 imm) { + *(cd->mcodeptr++) = 0xe8; + emit_imm32((imm)); +} + + +void emit_call_mem(codegendata *cd, ptrint mem) +{ + *(cd->mcodeptr++) = 0xff; + emit_mem(2,(mem)); +} + + + +/* + * floating point instructions (SSE2) + */ +void emit_addsd_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x58; + emit_reg((dreg),(reg)); +} + + +void emit_addss_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x58; + emit_reg((dreg),(reg)); +} + + +void emit_cvtsi2ssq_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x2a; + emit_reg((dreg),(reg)); +} + + +void emit_cvtsi2ss_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x2a; + emit_reg((dreg),(reg)); +} + + +void emit_cvtsi2sdq_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x2a; + emit_reg((dreg),(reg)); +} + + +void emit_cvtsi2sd_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x2a; + emit_reg((dreg),(reg)); +} + + +void emit_cvtss2sd_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x5a; + emit_reg((dreg),(reg)); +} + + +void emit_cvtsd2ss_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x5a; + emit_reg((dreg),(reg)); +} + + +void emit_cvttss2siq_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x2c; + emit_reg((dreg),(reg)); +} + + +void emit_cvttss2si_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x2c; + emit_reg((dreg),(reg)); +} + + +void emit_cvttsd2siq_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x2c; + emit_reg((dreg),(reg)); +} + + +void emit_cvttsd2si_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x2c; + emit_reg((dreg),(reg)); +} + + +void emit_divss_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x5e; + emit_reg((dreg),(reg)); +} + + +void emit_divsd_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x5e; + emit_reg((dreg),(reg)); +} + + +void emit_movd_reg_freg(codegendata *cd, s8 reg, s8 freg) { + *(cd->mcodeptr++) = 0x66; + emit_rex(1,(freg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x6e; + emit_reg((freg),(reg)); +} + + +void emit_movd_freg_reg(codegendata *cd, s8 freg, s8 reg) { + *(cd->mcodeptr++) = 0x66; + emit_rex(1,(freg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x7e; + emit_reg((freg),(reg)); +} + + +void emit_movd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) { + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x7e; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +void emit_movd_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) { + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x7e; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + *(cd->mcodeptr++) = 0x66; + emit_rex(1,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x6e; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +void emit_movdl_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x6e; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +void emit_movd_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg) { + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(dreg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x6e; + emit_memindex(cd, (dreg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movq_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x7e; + emit_reg((dreg),(reg)); +} + + +void emit_movq_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) { + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xd6; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +void emit_movq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x7e; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +void emit_movss_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(reg),0,(dreg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x10; + emit_reg((reg),(dreg)); +} + + +void emit_movsd_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(reg),0,(dreg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x10; + emit_reg((reg),(dreg)); +} + + +void emit_movss_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x11; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +/* Always emit a REX byte, because the instruction size can be smaller when */ +/* all register indexes are smaller than 7. */ +void emit_movss_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp) { + *(cd->mcodeptr++) = 0xf3; + emit_byte_rex((reg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x11; + emit_membase32(cd, (basereg),(disp),(reg)); +} + + +void emit_movsd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x11; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +/* Always emit a REX byte, because the instruction size can be smaller when */ +/* all register indexes are smaller than 7. */ +void emit_movsd_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp) { + *(cd->mcodeptr++) = 0xf2; + emit_byte_rex((reg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x11; + emit_membase32(cd, (basereg),(disp),(reg)); +} + + +void emit_movss_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x10; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +/* Always emit a REX byte, because the instruction size can be smaller when */ +/* all register indexes are smaller than 7. */ +void emit_movss_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_byte_rex((dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x10; + emit_membase32(cd, (basereg),(disp),(dreg)); +} + + +void emit_movlps_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) +{ + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x12; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +void emit_movlps_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) +{ + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x13; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +void emit_movsd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x10; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +/* Always emit a REX byte, because the instruction size can be smaller when */ +/* all register indexes are smaller than 7. */ +void emit_movsd_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_byte_rex((dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x10; + emit_membase32(cd, (basereg),(disp),(dreg)); +} + + +void emit_movlpd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) +{ + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x12; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +void emit_movlpd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) +{ + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(reg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x13; + emit_membase(cd, (basereg),(disp),(reg)); +} + + +void emit_movss_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x11; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movsd_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x11; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movss_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x10; + emit_memindex(cd, (dreg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_movsd_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(dreg),(indexreg),(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x10; + emit_memindex(cd, (dreg),(disp),(basereg),(indexreg),(scale)); +} + + +void emit_mulss_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x59; + emit_reg((dreg),(reg)); +} + + +void emit_mulsd_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x59; + emit_reg((dreg),(reg)); +} + + +void emit_subss_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf3; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x5c; + emit_reg((dreg),(reg)); +} + + +void emit_subsd_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0xf2; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x5c; + emit_reg((dreg),(reg)); +} + + +void emit_ucomiss_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x2e; + emit_reg((dreg),(reg)); +} + + +void emit_ucomisd_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x2e; + emit_reg((dreg),(reg)); +} + + +void emit_xorps_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x57; + emit_reg((dreg),(reg)); +} + + +void emit_xorps_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x57; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +void emit_xorpd_reg_reg(codegendata *cd, s8 reg, s8 dreg) { + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x57; + emit_reg((dreg),(reg)); +} + + +void emit_xorpd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) { + *(cd->mcodeptr++) = 0x66; + emit_rex(0,(dreg),0,(basereg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x57; + emit_membase(cd, (basereg),(disp),(dreg)); +} + + +/* system instructions ********************************************************/ + +void emit_rdtsc(codegendata *cd) +{ + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x31; +} + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/vm/jit/s390/emit.h b/src/vm/jit/s390/emit.h new file mode 100644 index 000000000..fd72bc624 --- /dev/null +++ b/src/vm/jit/s390/emit.h @@ -0,0 +1,374 @@ +/* src/vm/jit/x86_64/md-emit.h - machine dependent emit function prototypes + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + + Changes: + + $Id: emit.h 7219 2007-01-16 22:18:57Z pm $ + +*/ + + +#ifndef _MD_EMIT_H +#define _MD_EMIT_H + +#include "vm/types.h" + + +/* macros to create code ******************************************************/ + +/* immediate data union */ + +typedef union { + s4 i; + s8 l; + float f; + double d; + void *a; + u1 b[8]; +} imm_buf; + + +/* opcodes for alu instructions */ + +#define ALU_ADD 0 +#define ALU_OR 1 +#define ALU_ADC 2 +#define ALU_SBB 3 +#define ALU_AND 4 +#define ALU_SUB 5 +#define ALU_XOR 6 +#define ALU_CMP 7 + + +#define SHIFT_ROL 0 +#define SHIFT_ROR 1 +#define SHIFT_RCL 2 +#define SHIFT_RCR 3 +#define SHIFT_SHL 4 +#define SHIFT_SHR 5 +#define SHIFT_SAR 7 + +#if 0 +#define CC_O 0 +#define CC_NO 1 +#define CC_B 2 +#define CC_C 2 +#define CC_NAE 2 +#define CC_AE 3 +#define CC_NB 3 +#define CC_NC 3 +#define CC_E 4 +#define CC_Z 4 +#define CC_NE 5 +#define CC_NZ 5 +#define CC_BE 6 +#define CC_NA 6 +#define CC_A 7 +#define CC_NBE 7 +#define CC_S 8 +#define CC_LZ 8 +#define CC_NS 9 +#define CC_GEZ 9 +#define CC_P 0x0a +#define CC_PE 0x0a +#define CC_NP 0x0b +#define CC_PO 0x0b +#define CC_L 0x0c +#define CC_NGE 0x0c +#define CC_GE 0x0d +#define CC_NL 0x0d +#define CC_LE 0x0e +#define CC_NG 0x0e +#define CC_G 0x0f +#define CC_NLE 0x0f +#endif + + +/* modrm and stuff */ + +#define emit_address_byte(mod,reg,rm) \ + do { \ + *(cd->mcodeptr++) = ((((mod) & 0x03) << 6) | (((reg) & 0x07) << 3) | ((rm) & 0x07)); \ + } while (0); + + +#define emit_rex(size,reg,index,rm) \ + do { \ + if (((size) == 1) || ((reg) > 7) || ((index) > 7) || ((rm) > 7)) \ + *(cd->mcodeptr++) = (0x40 | (((size) & 0x01) << 3) | ((((reg) >> 3) & 0x01) << 2) | ((((index) >> 3) & 0x01) << 1) | (((rm) >> 3) & 0x01)); \ + } while (0) + + +#define emit_byte_rex(reg,index,rm) \ + do { \ + *(cd->mcodeptr++) = (0x40 | ((((reg) >> 3) & 0x01) << 2) | ((((index) >> 3) & 0x01) << 1) | (((rm) >> 3) & 0x01)); \ + } while (0) + + +#define emit_mem(r,disp) \ + do { \ + emit_address_byte(0,(r),5); \ + emit_imm32((disp)); \ + } while (0) + + +#define emit_imm8(imm) \ + do { \ + *(cd->mcodeptr++) = (u1) ((imm) & 0xff); \ + } while (0) + + +#define emit_imm16(imm) \ + do { \ + imm_buf imb; \ + imb.i = (s4) (imm); \ + *(cd->mcodeptr++) = imb.b[0]; \ + *(cd->mcodeptr++) = imb.b[1]; \ + } while (0) + + +#define emit_imm32(imm) \ + do { \ + imm_buf imb; \ + imb.i = (s4) (imm); \ + *(cd->mcodeptr++) = imb.b[0]; \ + *(cd->mcodeptr++) = imb.b[1]; \ + *(cd->mcodeptr++) = imb.b[2]; \ + *(cd->mcodeptr++) = imb.b[3]; \ + } while (0) + + +#define emit_imm64(imm) \ + do { \ + imm_buf imb; \ + imb.l = (s8) (imm); \ + *(cd->mcodeptr++) = imb.b[0]; \ + *(cd->mcodeptr++) = imb.b[1]; \ + *(cd->mcodeptr++) = imb.b[2]; \ + *(cd->mcodeptr++) = imb.b[3]; \ + *(cd->mcodeptr++) = imb.b[4]; \ + *(cd->mcodeptr++) = imb.b[5]; \ + *(cd->mcodeptr++) = imb.b[6]; \ + *(cd->mcodeptr++) = imb.b[7]; \ + } while (0) + + +/* convenience macros *********************************************************/ + +#define emit_reg(reg,rm) emit_address_byte(3,(reg),(rm)) + + +/* function prototypes ********************************************************/ + +void emit_cmovxx(codegendata *cd, instruction *iptr, s4 s, s4 d); + + +/* code generation prototypes */ + +void emit_ishift(jitdata *jd, s4 shift_op, instruction *iptr); +void emit_lshift(jitdata *jd, s4 shift_op, instruction *iptr); + + +/* integer instructions */ + +void emit_mov_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_mov_imm_reg(codegendata *cd, s8 imm, s8 reg); +void emit_movl_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_movl_imm_reg(codegendata *cd, s8 imm, s8 reg); +void emit_mov_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg); +void emit_mov_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg); +void emit_movl_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg); +void emit_movl_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg); +void emit_mov_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_mov_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_movl_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_movl_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_mov_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg); +void emit_movl_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg); +void emit_mov_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale); +void emit_movl_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale); +void emit_movw_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale); +void emit_movb_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale); +void emit_mov_imm_membase(codegendata *cd, s8 imm, s8 basereg, s8 disp); +void emit_mov_imm_membase32(codegendata *cd, s8 imm, s8 basereg, s8 disp); +void emit_movl_imm_membase(codegendata *cd, s8 imm, s8 basereg, s8 disp); +void emit_movl_imm_membase32(codegendata *cd, s8 imm, s8 basereg, s8 disp); +void emit_movsbq_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_movsbq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movswq_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_movswq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movslq_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_movslq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movzwq_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_movzwq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movswq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg); +void emit_movsbq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg); +void emit_movzwq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg); +void emit_mov_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale); +void emit_movl_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale); +void emit_movw_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale); +void emit_movb_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale); +void emit_alu_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg); +void emit_alul_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg); +void emit_alu_reg_membase(codegendata *cd, s8 opc, s8 reg, s8 basereg, s8 disp); +void emit_alul_reg_membase(codegendata *cd, s8 opc, s8 reg, s8 basereg, s8 disp); +void emit_alu_membase_reg(codegendata *cd, s8 opc, s8 basereg, s8 disp, s8 reg); +void emit_alul_membase_reg(codegendata *cd, s8 opc, s8 basereg, s8 disp, s8 reg); +void emit_alu_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg); +void emit_alu_imm32_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg); +void emit_alul_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg); +void emit_alu_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp); +void emit_alul_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp); +void emit_test_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_testl_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_test_imm_reg(codegendata *cd, s8 imm, s8 reg); +void emit_testw_imm_reg(codegendata *cd, s8 imm, s8 reg); +void emit_testb_imm_reg(codegendata *cd, s8 imm, s8 reg); +void emit_lea_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg); +void emit_leal_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg); + +void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp); + +void emit_cltd(codegendata *cd); +void emit_cqto(codegendata *cd); +void emit_imul_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_imull_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_imul_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_imull_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_imul_imm_reg(codegendata *cd, s8 imm, s8 dreg); +void emit_imul_imm_reg_reg(codegendata *cd, s8 imm,s8 reg, s8 dreg); +void emit_imull_imm_reg_reg(codegendata *cd, s8 imm, s8 reg, s8 dreg); +void emit_imul_imm_membase_reg(codegendata *cd, s8 imm, s8 basereg, s8 disp, s8 dreg); +void emit_imull_imm_membase_reg(codegendata *cd, s8 imm, s8 basereg, s8 disp, s8 dreg); +void emit_idiv_reg(codegendata *cd, s8 reg); +void emit_idivl_reg(codegendata *cd, s8 reg); +void emit_ret(codegendata *cd); +void emit_shift_reg(codegendata *cd, s8 opc, s8 reg); +void emit_shiftl_reg(codegendata *cd, s8 opc, s8 reg); +void emit_shift_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp); +void emit_shiftl_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp); +void emit_shift_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg); +void emit_shiftl_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg); +void emit_shift_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp); +void emit_shiftl_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp); +void emit_jmp_imm(codegendata *cd, s8 imm); +void emit_jmp_reg(codegendata *cd, s8 reg); +void emit_jcc(codegendata *cd, s8 opc, s8 imm); +void emit_setcc_reg(codegendata *cd, s8 opc, s8 reg); +void emit_setcc_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp); +void emit_cmovcc_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg); +void emit_cmovccl_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg); +void emit_neg_reg(codegendata *cd, s8 reg); +void emit_negl_reg(codegendata *cd, s8 reg); +void emit_neg_membase(codegendata *cd, s8 basereg, s8 disp); +void emit_negl_membase(codegendata *cd, s8 basereg, s8 disp); +void emit_push_reg(codegendata *cd, s8 reg); +void emit_push_imm(codegendata *cd, s8 imm); +void emit_pop_reg(codegendata *cd, s8 reg); +void emit_xchg_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_nop(codegendata *cd); +void emit_call_reg(codegendata *cd, s8 reg); +void emit_call_imm(codegendata *cd, s8 imm); +void emit_call_mem(codegendata *cd, ptrint mem); + + +/* floating point instructions (SSE2) */ + +void emit_addsd_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_addss_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_cvtsi2ssq_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_cvtsi2ss_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_cvtsi2sdq_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_cvtsi2sd_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_cvtss2sd_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_cvtsd2ss_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_cvttss2siq_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_cvttss2si_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_cvttsd2siq_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_cvttsd2si_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_divss_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_divsd_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_movd_reg_freg(codegendata *cd, s8 reg, s8 freg); +void emit_movd_freg_reg(codegendata *cd, s8 freg, s8 reg); +void emit_movd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_movd_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale); +void emit_movd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movdl_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movd_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg); +void emit_movq_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_movq_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_movq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movss_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_movsd_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_movss_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_movss_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_movsd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_movsd_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_movss_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movss_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movlps_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movlps_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_movsd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movsd_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movlpd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_movlpd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp); +void emit_movss_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale); +void emit_movsd_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale); +void emit_movss_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg); +void emit_movsd_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg); +void emit_mulss_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_mulsd_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_subss_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_subsd_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_ucomiss_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_ucomisd_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_xorps_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_xorps_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); +void emit_xorpd_reg_reg(codegendata *cd, s8 reg, s8 dreg); +void emit_xorpd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); + + +/* system instructions ********************************************************/ + +void emit_rdtsc(codegendata *cd); + +#endif /* _MD_EMIT_H */ + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/vm/jit/s390/machine-instr.h b/src/vm/jit/s390/machine-instr.h new file mode 100644 index 000000000..a9164c780 --- /dev/null +++ b/src/vm/jit/s390/machine-instr.h @@ -0,0 +1,42 @@ +#ifndef _MACHINE_INSTR_H +#define _MACHINE_INSTR_H + +static inline void +__attribute__ ((unused)) +atomic_add (volatile int *mem, int val) +{ +#if 0 + __asm__ __volatile__ ("lock; addl %1,%0" + : "=m" (*mem) + : "ir" (val), "m" (*mem)); +#endif +} + +static inline long +__attribute__ ((unused)) +compare_and_swap (volatile long *p, long oldval, long newval) +{ +#if 0 + long ret; + + __asm__ __volatile__ ("lock; cmpxchgq %2, %1" + : "=a" (ret), "=m" (*p) + : "r" (newval), "m" (*p), "0" (oldval)); + return ret; +#endif +} + +#if 0 +#define STORE_ORDER_BARRIER() __asm__ __volatile__ ("" : : : "memory"); +#define MEMORY_BARRIER_BEFORE_ATOMIC() __asm__ __volatile__ ("" : : : "memory"); +#define MEMORY_BARRIER_AFTER_ATOMIC() __asm__ __volatile__ ("" : : : "memory"); +#define MEMORY_BARRIER() __asm__ __volatile__ ( \ + "mfence" : : : "memory" ) +#endif + +#define STORE_ORDER_BARRIER() +#define MEMORY_BARRIER_BEFORE_ATOMIC() +#define MEMORY_BARRIER_AFTER_ATOMIC() +#define MEMORY_BARRIER() + +#endif diff --git a/src/vm/jit/s390/md-abi.c b/src/vm/jit/s390/md-abi.c new file mode 100644 index 000000000..b2702665a --- /dev/null +++ b/src/vm/jit/s390/md-abi.c @@ -0,0 +1,219 @@ +/* src/vm/jit/x86_64/md-abi.c - functions for x86_64 Linux ABI + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + + Changes: + + $Id: md-abi.c 7219 2007-01-16 22:18:57Z pm $ + +*/ + + +#include "config.h" +#include "vm/types.h" + +#include "vm/jit/s390/md-abi.h" + +#include "vm/descriptor.h" +#include "vm/global.h" + + +/* register descripton array **************************************************/ + +s4 nregdescint[] = { +#if 0 + REG_RET, REG_ARG, REG_ARG, REG_TMP, REG_RES, REG_SAV, REG_ARG, REG_ARG, + REG_ARG, REG_ARG, REG_RES, REG_RES, REG_SAV, REG_SAV, REG_SAV, REG_SAV, +#endif + REG_TMP, REG_TMP, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_SAV, + REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_RES, REG_TMP, REG_RES, + REG_END +}; + + +s4 nregdescfloat[] = { +#if 0 + REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, + REG_RES, REG_RES, REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, +#endif + REG_ARG, REG_TMP, REG_ARG, REG_TMP, REG_SAV, REG_TMP, REG_SAV, REG_TMP, + REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, + REG_END +}; + + +/* md_param_alloc ************************************************************** + + XXX + +*******************************************************************************/ + +void md_param_alloc(methoddesc *md) +{ + paramdesc *pd; + s4 i; + s4 iarg; + s4 farg; + s4 stacksize; + + /* set default values */ + + iarg = 0; + farg = 0; + stacksize = 0; + + /* get params field of methoddesc */ + + pd = md->params; + + for (i = 0; i < md->paramcount; i++, pd++) { + switch (md->paramtypes[i].type) { + case TYPE_INT: + case TYPE_ADR: + case TYPE_LNG: + if (iarg < INT_ARG_CNT) { + pd->inmemory = false; + pd->regoff = iarg; + } + else { + pd->inmemory = true; + pd->regoff = stacksize; + } + if (iarg < INT_ARG_CNT) + iarg++; + else + stacksize++; + break; + + case TYPE_FLT: + case TYPE_DBL: + if (farg < FLT_ARG_CNT) { + pd->inmemory = false; + pd->regoff = farg; + } + else { + pd->inmemory = true; + pd->regoff = stacksize; + } + if (farg < FLT_ARG_CNT) + farg++; + else + stacksize++; + break; + } + } + + /* Since XMM0 (==A0) is used for passing return values, this + argument register usage has to be regarded, too. */ + + if (IS_FLT_DBL_TYPE(md->returntype.type)) + if (farg < 1) + farg = 1; + + /* fill register and stack usage */ + + md->argintreguse = iarg; + md->argfltreguse = farg; + md->memuse = stacksize; +} + + +/* md_return_alloc ************************************************************* + + Precolor the Java Stackelement containing the Return Value. Only + for float/ double types straight forward possible, since INT_LNG + types use "reserved" registers Float/Double values use a00 as + return register. + + --- in + jd: jitdata of the current method + stackslot: Java Stackslot to contain the Return Value + + --- out + if precoloring was possible: + VAR(stackslot->varnum)->flags = PREALLOC + ->vv.regoff = [REG_RESULT|REG_FRESULT] + rd->arg[flt|int]reguse set to a value according the register usage + + NOTE: Do not pass a LOCALVAR in stackslot->varnum. + +*******************************************************************************/ + +void md_return_alloc(jitdata *jd, stackptr stackslot) +{ + methodinfo *m; + registerdata *rd; + methoddesc *md; + + /* get required compiler data */ + + m = jd->m; + rd = jd->rd; + + md = m->parseddesc; + + /* precoloring only straightforward possible with flt/dbl types + For Address/Integer/Long REG_RESULT == rax == REG_ITMP1 and so + could be destroyed if the return value Stack Slot "lives too + long" */ + + if (IS_FLT_DBL_TYPE(md->returntype.type)) { + /* In Leafmethods Local Vars holding parameters are precolored + to their argument register -> so leafmethods with + paramcount > 0 could already use a00! */ + + if (!jd->isleafmethod || (md->paramcount == 0)) { + /* Only precolor the stackslot, if it is not a SAVEDVAR + <-> has not to survive method invokations */ + + if (!(stackslot->flags & SAVEDVAR)) { + + VAR(stackslot->varnum)->flags = PREALLOC; + + /* float/double */ + if (rd->argfltreguse < 1) + rd->argfltreguse = 1; + + VAR(stackslot->varnum)->vv.regoff = REG_FRESULT; + } + } + } +} + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/vm/jit/s390/md-abi.h b/src/vm/jit/s390/md-abi.h new file mode 100644 index 000000000..466cb68ce --- /dev/null +++ b/src/vm/jit/s390/md-abi.h @@ -0,0 +1,200 @@ +/* src/vm/jit/x86_64/md-abi.h - defines for x86_64 Linux ABI + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + + Changes: + + $Id: md-abi.h 7219 2007-01-16 22:18:57Z pm $ + +*/ + + +#ifndef _MD_ABI_H +#define _MD_ABI_H + +/* keep old code happy */ + +#define RIP -1 +#define RAX 0 +#define RCX 1 +#define RDX 2 +#define RBX 3 +#define RSP 4 +#define RBP 5 +#define RSI 6 +#define RDI 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + + +#define XMM0 0 +#define XMM1 1 +#define XMM2 2 +#define XMM3 3 +#define XMM4 4 +#define XMM5 5 +#define XMM6 6 +#define XMM7 7 +#define XMM8 8 +#define XMM9 9 +#define XMM10 10 +#define XMM11 11 +#define XMM12 12 +#define XMM13 13 +#define XMM14 14 +#define XMM15 15 + + +#define REG_IFTMP 10 /* temporary integer and floating point register */ + + +/* define registers ***********************************************************/ + +#define R0 0 +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define F0 0 +#define F1 1 +#define F2 2 +#define F3 3 +#define F4 4 +#define F5 5 +#define F6 6 +#define F7 7 +#define F8 8 +#define F9 9 +#define F10 10 +#define F11 11 +#define F12 12 +#define F13 13 +#define F14 14 +#define F15 15 + +/* preallocated registers *****************************************************/ + +/* integer registers */ + +#define REG_RESULT R2 /* to deliver method results */ +#define REG_RESULT2 R3 + +#define REG_ITMP1 R0 /* temporary register */ +#define REG_ITMP2 R1 /* temporary register and method pointer */ +#define REG_ITMP3 R14 /* temporary register */ + +#define REG_ITMP12_PACKED PACK_REGS(REG_ITMP2, REG_ITMP1) +#define REG_ITMP23_PACKED PACK_REGS(REG_ITMP3, REG_ITMP2) +#define REG_RESULT_PACKED PACK_REGS(REG_RESULT2, REG_RESULT) + +#define REG_METHODPTR REG_ITMP2/* pointer to the place from where the */ + /* procedure vector has been fetched */ + +#define REG_NULL -1 /* used for reg_of_var where d is not needed */ + +#define REG_ITMP1_XPTR REG_ITMP1/* exception pointer = temporary register 1 */ +#define REG_ITMP2_XPC REG_ITMP2/* exception pc = temporary register 2 */ + +#define REG_SP R15 /* stack pointer */ + +#define REG_PV R13 + +#define REG_A0 R2 /* define some argument registers */ +#define REG_A1 R3 +#define REG_A2 R4 +#define REG_A3 R5 +#define REG_A4 R6 + +/* floating point registers */ + +#define REG_FRESULT F0 /* to deliver floating point method results */ + +#define REG_FTMP1 F1 /* temporary floating point register */ +#define REG_FTMP2 F3 /* temporary floating point register */ +#define REG_FTMP3 F5 /* temporary floating point register */ + +#define __REG_IFTMP 10 /* temporary integer and floating point register */ + + +#define INT_REG_CNT 16 /* number of integer registers */ +#define INT_SAV_CNT 6 /* number of integer callee saved registers */ +#define INT_ARG_CNT 5 /* number of integer argument registers */ +#define INT_TMP_CNT 3 /* number of integer temporary registers */ +#define INT_RES_CNT 2 /* number of integer reserved registers */ + +#define FLT_REG_CNT 16 /* number of float registers */ +#define FLT_SAV_CNT 2 /* number of float callee saved registers */ +#define FLT_ARG_CNT 2 /* number of float argument registers */ +#define FLT_TMP_CNT 12 /* number of float temporary registers */ +#define FLT_RES_CNT 0 /* number of float reserved registers */ + +#define TRACE_ARGS_NUM 6 + + + + + + + + + + + + +#endif /* _MD_ABI_H */ + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/vm/jit/s390/md-asm.h b/src/vm/jit/s390/md-asm.h new file mode 100644 index 000000000..0d673a2a2 --- /dev/null +++ b/src/vm/jit/s390/md-asm.h @@ -0,0 +1,196 @@ +/* src/vm/jit/x86_64/md-asm.h - assembler defines for x86_64 Linux ABI + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + + Changes: + + $Id: md-asm.h 7219 2007-01-16 22:18:57Z pm $ + +*/ + + +#ifndef _MD_ASM_H +#define _MD_ASM_H + +/* register defines ***********************************************************/ + +#if 0 + +#define v0 %rax +#define v0l %eax +#define itmp1 v0 + +#define a3 %rcx +#define a2 %rdx + +#define t0 %rbx +#define t0l %ebx + +#define sp %rsp +#define s0 %rbp + +#define a1 %rsi +#define a0 %rdi +#define a0l %edi + +#define a4 %r8 +#define a5 %r9 + +#define itmp2 %r10 +#define itmp3 %r14 + +#define s1 %r12 +#define s2 %r13 +#define s3 %r14 +#define s4 %r15 + + +#define bp s0 + +#define itmp1l %eax +#define itmp2l %r10d +#define itmp3l %r11d + +#define xptr itmp1 +#define xpc itmp2 +#define mptr itmp2 + + +#define fa0 %xmm0 +#define fa1 %xmm1 +#define fa2 %xmm2 +#define fa3 %xmm3 +#define fa4 %xmm4 +#define fa5 %xmm5 +#define fa6 %xmm6 +#define fa7 %xmm7 + +#define ftmp1 %xmm8 +#define ftmp2 %xmm9 +#define ftmp3 %xmm10 + +#define ft0 %xmm11 +#define ft1 %xmm12 +#define ft2 %xmm13 +#define ft3 %xmm14 +#define ft4 %xmm15 + +#endif + +#define a0 %r2 +#define a1 %r3 +#define a2 %r4 +#define a3 %r5 +#define a4 %r6 + +#define sp %r15 +#define itmp1 %r0 +#define itmp2 %r1 +#define itmp3 %r14 +#define v0 %r2 +#define pv %r13 + +#define mptr itmp2 + +#define s0 %r7 +#define s1 %r8 +#define s2 %r9 +#define s3 %r10 +#define s4 %r11 +#define s5 %r12 + +#define fa0 %f0 +#define fa1 %f2 + +/* save and restore macros ****************************************************/ + +#define SAVE_ARGUMENT_REGISTERS(off) \ + mov a0,(0+(off))*8(sp) ; \ + mov a1,(1+(off))*8(sp) ; \ + mov a2,(2+(off))*8(sp) ; \ + mov a3,(3+(off))*8(sp) ; \ + mov a4,(4+(off))*8(sp) ; \ + mov a5,(5+(off))*8(sp) ; \ + \ + movq fa0,(6+(off))*8(sp) ; \ + movq fa1,(7+(off))*8(sp) ; \ + movq fa2,(8+(off))*8(sp) ; \ + movq fa3,(9+(off))*8(sp) ; \ + movq fa4,(10+(off))*8(sp) ; \ + movq fa5,(11+(off))*8(sp) ; \ + movq fa6,(12+(off))*8(sp) ; \ + movq fa7,(13+(off))*8(sp) ; + + +#define RESTORE_ARGUMENT_REGISTERS(off) \ + mov (0+(off))*8(sp),a0 ; \ + mov (1+(off))*8(sp),a1 ; \ + mov (2+(off))*8(sp),a2 ; \ + mov (3+(off))*8(sp),a3 ; \ + mov (4+(off))*8(sp),a4 ; \ + mov (5+(off))*8(sp),a5 ; \ + \ + movq (6+(off))*8(sp),fa0 ; \ + movq (7+(off))*8(sp),fa1 ; \ + movq (8+(off))*8(sp),fa2 ; \ + movq (9+(off))*8(sp),fa3 ; \ + movq (10+(off))*8(sp),fa4 ; \ + movq (11+(off))*8(sp),fa5 ; \ + movq (12+(off))*8(sp),fa6 ; \ + movq (13+(off))*8(sp),fa7 ; + + +#define SAVE_TEMPORARY_REGISTERS(off) \ + mov t0,(0+(off))*8(sp) ; \ + movq ft0,(1+(off))*8(sp) ; \ + movq ft1,(2+(off))*8(sp) ; \ + movq ft2,(3+(off))*8(sp) ; \ + movq ft3,(4+(off))*8(sp) ; + + +#define RESTORE_TEMPORARY_REGISTERS(off) \ + mov (0+(off))*8(sp),t0 ; \ + movq (1+(off))*8(sp),ft0 ; \ + movq (2+(off))*8(sp),ft1 ; \ + movq (3+(off))*8(sp),ft2 ; \ + movq (4+(off))*8(sp),ft3 ; + +#endif /* _MD_ASM_H */ + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/vm/jit/s390/md.c b/src/vm/jit/s390/md.c new file mode 100644 index 000000000..949b13391 --- /dev/null +++ b/src/vm/jit/s390/md.c @@ -0,0 +1,434 @@ +/* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + + Changes: Edwin Steiner + + $Id: md.c 7219 2007-01-16 22:18:57Z pm $ + +*/ + +#define REG_RSP 0 +#define REG_RIP 0 +#define REG_RAX 0 +#define REG_R10 0 +#define REG_ITMP2 0 +#define REG_RIP 0 +#define REG_RSP 0 +#define REG_RIP 0 +#define REG_RAX 0 +#define REG_R10 0 +#define REG_ITMP2 0 +#define REG_RIP 0 +#define REG_METHODPTR 0 + + +#define _GNU_SOURCE + +#include "config.h" + +#include +#include +#include + +#include "vm/jit/s390/md-abi.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/threads.h" +#endif + +#include "vm/exceptions.h" +#include "vm/signallocal.h" +#include "vm/jit/asmpart.h" +#include "vm/jit/stacktrace.h" + +#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) +#include "vm/options.h" /* XXX debug */ +#include "vm/jit/disass.h" /* XXX debug */ +#endif + + +/* md_init ********************************************************************* + + Do some machine dependent initialization. + +*******************************************************************************/ + +void md_init(void) +{ + /* nothing to do */ +} + + +/* md_signal_handler_sigsegv *************************************************** + + NullPointerException signal handler for hardware null pointer + check. + +*******************************************************************************/ + +void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p) +{ + ucontext_t *_uc; + mcontext_t *_mc; + u1 *sp; + u1 *ra; + u1 *xpc; + + _uc = (ucontext_t *) _p; + _mc = &_uc->uc_mcontext; + + /* ATTENTION: Don't use CACAO's internal REG_* defines as they are + different to the ones in . */ + + sp = (u1 *) _mc->gregs[REG_RSP]; + xpc = (u1 *) _mc->gregs[REG_RIP]; + ra = xpc; /* return address is equal to xpc */ + +#if 0 + /* check for StackOverflowException */ + + threads_check_stackoverflow(sp); +#endif + + _mc->gregs[REG_RAX] = + (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc); + + _mc->gregs[REG_R10] = (ptrint) xpc; /* REG_ITMP2_XPC */ + _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception; +} + + +/* md_signal_handler_sigfpe **************************************************** + + ArithmeticException signal handler for hardware divide by zero + check. + +*******************************************************************************/ + +void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p) +{ + ucontext_t *_uc; + mcontext_t *_mc; + u1 *sp; + u1 *ra; + u1 *xpc; + + _uc = (ucontext_t *) _p; + _mc = &_uc->uc_mcontext; + + /* ATTENTION: Don't use CACAO's internal REG_* defines as they are + different to the ones in . */ + + sp = (u1 *) _mc->gregs[REG_RSP]; + xpc = (u1 *) _mc->gregs[REG_RIP]; + ra = xpc; /* return address is equal to xpc */ + + _mc->gregs[REG_RAX] = + (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc); + + _mc->gregs[REG_R10] = (ptrint) xpc; /* REG_ITMP2_XPC */ + _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception; +} + + +/* md_signal_handler_sigusr2 *************************************************** + + Signal handler for profiling sampling. + +*******************************************************************************/ + +#if defined(ENABLE_THREADS) +void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p) +{ + threadobject *t; + ucontext_t *_uc; + mcontext_t *_mc; + u1 *pc; + + t = THREADOBJECT; + + _uc = (ucontext_t *) _p; + _mc = &_uc->uc_mcontext; + + /* ATTENTION: Don't use CACAO's internal REG_* defines as they are + different to the ones in . */ + + pc = (u1 *) _mc->gregs[REG_RIP]; + + t->pc = pc; +} +#endif + + +#if defined(ENABLE_THREADS) +void thread_restartcriticalsection(ucontext_t *_uc) +{ + mcontext_t *_mc; + void *pc; + + _mc = &_uc->uc_mcontext; + + pc = critical_find_restart_point((void *) _mc->gregs[REG_RIP]); + + if (pc != NULL) + _mc->gregs[REG_RIP] = (ptrint) pc; +} +#endif + + +/* md_codegen_patch_branch ***************************************************** + + Back-patches a branch instruction. + +*******************************************************************************/ + +void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc) +{ + s4 *mcodeptr; + s4 disp; /* branch displacement */ + + /* calculate the patch position */ + + mcodeptr = (s4 *) (cd->mcodebase + branchmpc); + + /* Calculate the branch displacement. */ + + disp = targetmpc - branchmpc; + + /* I don't think we have to check for branch-displacement + overflow. +/-2GB should be enough. */ + + /* patch the branch instruction before the mcodeptr */ + + mcodeptr[-1] = disp; +} + + +/* md_stacktrace_get_returnaddress ********************************************* + + Returns the return address of the current stackframe, specified by + the passed stack pointer and the stack frame size. + +*******************************************************************************/ + +u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize) +{ + u1 *ra; + + /* on x86_64 the return address is above the current stack frame */ + + ra = *((u1 **) (sp + framesize)); + + return ra; +} + + +/* md_get_method_patch_address ************************************************* + + Gets the patch address of the currently compiled method. The offset + is extracted from the load instruction(s) before the jump and added + to the right base address (PV or REG_METHODPTR). + + INVOKESTATIC/SPECIAL: + + 4d 8b 15 e2 fe ff ff mov -286(%rip),%r10 + 49 ff d2 rex64Z callq *%r10 + + INVOKEVIRTUAL: + + 4c 8b 17 mov (%rdi),%r10 + 49 8b 82 00 00 00 00 mov 0x0(%r10),%rax + 48 ff d3 rex64 callq *%rax + + INVOKEINTERFACE: + + 4c 8b 17 mov (%rdi),%r10 + 4d 8b 92 00 00 00 00 mov 0x0(%r10),%r10 + 49 8b 82 00 00 00 00 mov 0x0(%r10),%rax + 48 ff d3 rex64 callq *%r11 + +*******************************************************************************/ + +u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) +{ + u1 mcode; + s4 offset; + u1 *pa; /* patch address */ + + /* go back to the actual call instruction (3-bytes) */ + + ra = ra - 3; + + /* get the last byte of the call */ + + mcode = ra[2]; + + /* check for the different calls */ + + if (mcode == 0xd2) { + /* INVOKESTATIC/SPECIAL */ + + /* Get the offset from the instruction (the offset address is + 4-bytes before the call instruction). */ + + offset = *((s4 *) (ra - 4)); + + /* add the offset to the return address (IP-relative addressing) */ + + pa = ra + offset; + } + else if (mcode == 0xd3) { + /* INVOKEVIRTUAL/INTERFACE */ + + /* Get the offset from the instruction (the offset address is + 4-bytes before the call instruction). */ + + offset = *((s4 *) (ra - 4)); + + /* add the offset to the method pointer */ + + pa = mptr + offset; + } + else { + /* catch any problems */ + + assert(0); + } + + return pa; +} + + +/* md_codegen_get_pv_from_pc *************************************************** + + On this architecture just a wrapper function to + codegen_get_pv_from_pc. + +*******************************************************************************/ + +u1 *md_codegen_get_pv_from_pc(u1 *ra) +{ + u1 *pv; + + /* Get the start address of the function which contains this + address from the method table. */ + + pv = codegen_get_pv_from_pc(ra); + + return pv; +} + + +/* md_cacheflush *************************************************************** + + Calls the system's function to flush the instruction and data + cache. + +*******************************************************************************/ + +void md_cacheflush(u1 *addr, s4 nbytes) +{ + /* do nothing */ +} + + +/* md_icacheflush ************************************************************** + + Calls the system's function to flush the instruction cache. + +*******************************************************************************/ + +void md_icacheflush(u1 *addr, s4 nbytes) +{ + /* do nothing */ +} + + +/* md_dcacheflush ************************************************************** + + Calls the system's function to flush the data cache. + +*******************************************************************************/ + +void md_dcacheflush(u1 *addr, s4 nbytes) +{ + /* do nothing */ +} + + +/* md_patch_replacement_point ************************************************** + + Patch the given replacement point. + +*******************************************************************************/ + +void md_patch_replacement_point(rplpoint *rp) +{ + u8 mcode; + + /* XXX this is probably unsafe! */ + + /* save the current machine code */ + mcode = *(u8*)rp->pc; + + /* write spinning instruction */ + *(u2*)(rp->pc) = 0xebfe; + + /* write 5th byte */ + rp->pc[4] = (rp->mcode >> 32); + + /* write first word */ + *(u4*)(rp->pc) = (u4) rp->mcode; + + /* store saved mcode */ + rp->mcode = mcode; + +#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) + { + u1* u1ptr = rp->pc; + DISASSINSTR(u1ptr); + fflush(stdout); + } +#endif + + /* XXX if required asm_cacheflush(rp->pc,8); */ +} + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/s390/patcher.c b/src/vm/jit/s390/patcher.c new file mode 100644 index 000000000..c28528f59 --- /dev/null +++ b/src/vm/jit/s390/patcher.c @@ -0,0 +1,922 @@ +/* src/vm/jit/x86_64/patcher.c - x86_64 code patching functions + + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Authors: Christian Thalinger + + Changes: + + $Id: patcher.c 7219 2007-01-16 22:18:57Z pm $ + +*/ + + +#include "config.h" +#include "vm/types.h" + +#include "vm/jit/s390/codegen.h" + +#include "mm/memory.h" +#include "native/native.h" +#include "vm/builtin.h" +#include "vm/class.h" +#include "vm/exceptions.h" +#include "vm/field.h" +#include "vm/initialize.h" +#include "vm/options.h" +#include "vm/references.h" +#include "vm/resolve.h" +#include "vm/jit/patcher.h" + + +/* patcher_wrapper ************************************************************* + + Wrapper for all patchers. It also creates the stackframe info + structure. + + If the return value of the patcher function is false, it gets the + exception object, clears the exception pointer and returns the + exception. + +*******************************************************************************/ + +java_objectheader *patcher_wrapper(u1 *sp, u1 *pv, u1 *ra) +{ + stackframeinfo sfi; + u1 *xpc; + java_objectheader *o; + functionptr f; + bool result; + java_objectheader *e; + + /* define the patcher function */ + + bool (*patcher_function)(u1 *); + + /* get stuff from the stack */ + + xpc = (u1 *) *((ptrint *) (sp + 5 * 8)); + o = (java_objectheader *) *((ptrint *) (sp + 4 * 8)); + f = (functionptr) *((ptrint *) (sp + 0 * 8)); + + /* calculate and set the new return address */ + + xpc = xpc - PATCHER_CALL_SIZE; + + *((ptrint *) (sp + 5 * 8)) = (ptrint) xpc; + + /* cast the passed function to a patcher function */ + + patcher_function = (bool (*)(u1 *)) (ptrint) f; + + /* enter a monitor on the patching position */ + + PATCHER_MONITORENTER; + + /* create the stackframeinfo */ + + /* RA is passed as NULL, but the XPC is correct and can be used in + stacktrace_create_extern_stackframeinfo for + md_codegen_get_pv_from_pc. */ + + stacktrace_create_extern_stackframeinfo(&sfi, pv, sp + 6 * 8, xpc, xpc); + + /* call the proper patcher function */ + + result = (patcher_function)(sp); + + /* remove the stackframeinfo */ + + stacktrace_remove_stackframeinfo(&sfi); + + /* check for return value and exit accordingly */ + + if (result == false) { + e = exceptions_get_and_clear_exception(); + + PATCHER_MONITOREXIT; + + return e; + } + + PATCHER_MARK_PATCHED_MONITOREXIT; + + return NULL; +} + + +/* patcher_get_putstatic ******************************************************* + + Machine code: + + + 4d 8b 15 86 fe ff ff mov -378(%rip),%r10 + 49 8b 32 mov (%r10),%rsi + +*******************************************************************************/ + +bool patcher_get_putstatic(u1 *sp) +{ + u1 *ra; + u8 mcode; + unresolved_field *uf; + s4 disp; + fieldinfo *fi; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + uf = (unresolved_field *) *((ptrint *) (sp + 2 * 8)); + disp = *((s4 *) (sp + 1 * 8)); + + /* get the fieldinfo */ + + if (!(fi = resolve_field_eager(uf))) + return false; + + /* check if the field's class is initialized */ + + if (!(fi->class->state & CLASS_INITIALIZED)) + if (!initialize_class(fi->class)) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch the field value's address */ + + *((ptrint *) (ra + 7 + disp)) = (ptrint) &(fi->value); + + return true; +} + + +/* patcher_get_putfield ******************************************************** + + Machine code: + + + 45 8b 8f 00 00 00 00 mov 0x0(%r15),%r9d + +*******************************************************************************/ + +bool patcher_get_putfield(u1 *sp) +{ + u1 *ra; + u8 mcode; + unresolved_field *uf; + fieldinfo *fi; + u1 byte; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + uf = (unresolved_field *) *((ptrint *) (sp + 2 * 8)); + + /* get the fieldinfo */ + + if (!(fi = resolve_field_eager(uf))) + return false; + + /* patch back original code (instruction code is smaller than 8 bytes) */ + + *((u4 *) (ra + 0)) = (u4) mcode; + *((u1 *) (ra + 4)) = (u1) (mcode >> 32); + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch the field's offset: we check for the field type, because the */ + /* instructions have different lengths */ + + if (IS_INT_LNG_TYPE(fi->type)) { + /* check for special case: %rsp or %r12 as base register */ + + byte = *(ra + 3); + + if (byte == 0x24) + *((u4 *) (ra + 4)) = (u4) (fi->offset); + else + *((u4 *) (ra + 3)) = (u4) (fi->offset); + } + else { + /* check for special case: %rsp or %r12 as base register */ + + byte = *(ra + 5); + + if (byte == 0x24) + *((u4 *) (ra + 6)) = (u4) (fi->offset); + else + *((u4 *) (ra + 5)) = (u4) (fi->offset); + } + + return true; +} + + +/* patcher_putfieldconst ******************************************************* + + Machine code: + + + 41 c7 85 00 00 00 00 7b 00 00 00 movl $0x7b,0x0(%r13) + +*******************************************************************************/ + +bool patcher_putfieldconst(u1 *sp) +{ + u1 *ra; + u8 mcode; + unresolved_field *uf; + fieldinfo *fi; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + uf = (unresolved_field *) *((ptrint *) (sp + 2 * 8)); + + /* get the fieldinfo */ + + if (!(fi = resolve_field_eager(uf))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch the field's offset */ + + if (IS_2_WORD_TYPE(fi->type) || IS_ADR_TYPE(fi->type)) { + /* handle special case when the base register is %r12 */ + + if (*(ra + 2) == 0x84) { + *((u4 *) (ra + 4)) = (u4) (fi->offset); + *((u4 *) (ra + 12 + 4)) = (u4) (fi->offset + 4); + } + else { + *((u4 *) (ra + 3)) = (u4) (fi->offset); + *((u4 *) (ra + 11 + 3)) = (u4) (fi->offset + 4); + } + } + else { + /* handle special case when the base register is %r12 */ + + if (*(ra + 2) == 0x84) + *((u4 *) (ra + 4)) = (u4) (fi->offset); + else + *((u4 *) (ra + 3)) = (u4) (fi->offset); + } + + return true; +} + + +/* patcher_aconst ************************************************************** + + Machine code: + + + 48 bf a0 f0 92 00 00 00 00 00 mov $0x92f0a0,%rdi + +*******************************************************************************/ + +bool patcher_aconst(u1 *sp) +{ + u1 *ra; + u8 mcode; + constant_classref *cr; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 8)); + + /* get the classinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch the classinfo pointer */ + + *((ptrint *) (ra + 2)) = (ptrint) c; + + return true; +} + + +/* patcher_builtin_multianewarray ********************************************** + + Machine code: + + + 48 bf 02 00 00 00 00 00 00 00 mov $0x2,%rdi + 48 be 30 40 b2 00 00 00 00 00 mov $0xb24030,%rsi + 48 89 e2 mov %rsp,%rdx + 48 b8 7c 96 4b 00 00 00 00 00 mov $0x4b967c,%rax + 48 ff d0 callq *%rax + +*******************************************************************************/ + +bool patcher_builtin_multianewarray(u1 *sp) +{ + u1 *ra; + u8 mcode; + constant_classref *cr; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 8)); + + /* get the classinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch the classinfo pointer */ + + *((ptrint *) (ra + 10 + 2)) = (ptrint) c; + + return true; +} + + +/* patcher_builtin_arraycheckcast ********************************************** + + Machine code: + + + 48 be b8 3f b2 00 00 00 00 00 mov $0xb23fb8,%rsi + 48 b8 00 00 00 00 00 00 00 00 mov $0x0,%rax + 48 ff d0 callq *%rax + +*******************************************************************************/ + +bool patcher_builtin_arraycheckcast(u1 *sp) +{ + u1 *ra; + u8 mcode; + constant_classref *cr; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 8)); + + /* get the classinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch the classinfo pointer */ + + *((ptrint *) (ra + 2)) = (ptrint) c; + + return true; +} + + +/* patcher_invokestatic_special ************************************************ + + Machine code: + + + 49 ba 00 00 00 00 00 00 00 00 mov $0x0,%r10 + 49 ff d2 callq *%r10 + +*******************************************************************************/ + +bool patcher_invokestatic_special(u1 *sp) +{ + u1 *ra; + u8 mcode; + unresolved_method *um; + s4 disp; + methodinfo *m; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + um = (unresolved_method *) *((ptrint *) (sp + 2 * 8)); + disp = *((s4 *) (sp + 1 * 8)); + + /* get the fieldinfo */ + + if (!(m = resolve_method_eager(um))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch stubroutine */ + +/* *((ptrint *) (ra + 2)) = (ptrint) m->stubroutine; */ + *((ptrint *) (ra + 7 + disp)) = (ptrint) m->stubroutine; + + return true; +} + + +/* patcher_invokevirtual ******************************************************* + + Machine code: + + + 4c 8b 17 mov (%rdi),%r10 + 49 8b 82 00 00 00 00 mov 0x0(%r10),%rax + 48 ff d0 callq *%rax + +*******************************************************************************/ + +bool patcher_invokevirtual(u1 *sp) +{ + u1 *ra; + u8 mcode; + unresolved_method *um; + methodinfo *m; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + um = (unresolved_method *) *((ptrint *) (sp + 2 * 8)); + + /* get the fieldinfo */ + + if (!(m = resolve_method_eager(um))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch vftbl index */ + + *((s4 *) (ra + 3 + 3)) = (s4) (OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * m->vftblindex); + + return true; +} + + +/* patcher_invokeinterface ***************************************************** + + Machine code: + + + 4c 8b 17 mov (%rdi),%r10 + 4d 8b 92 00 00 00 00 mov 0x0(%r10),%r10 + 49 8b 82 00 00 00 00 mov 0x0(%r10),%rax + 48 ff d0 callq *%rax + +*******************************************************************************/ + +bool patcher_invokeinterface(u1 *sp) +{ + u1 *ra; + u8 mcode; + unresolved_method *um; + methodinfo *m; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + um = (unresolved_method *) *((ptrint *) (sp + 2 * 8)); + + /* get the fieldinfo */ + + if (!(m = resolve_method_eager(um))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch interfacetable index */ + + *((s4 *) (ra + 3 + 3)) = (s4) (OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr) * m->class->index); + + /* patch method offset */ + + *((s4 *) (ra + 3 + 7 + 3)) = + (s4) (sizeof(methodptr) * (m - m->class->methods)); + + return true; +} + + +/* patcher_checkcast_instanceof_flags ****************************************** + + Machine code: + + + 41 ba 00 00 00 00 mov $0x0,%r10d + 41 81 e2 00 02 00 00 and $0x200,%r10d + 0f 84 35 00 00 00 je 0x00002aaaaab01479 + +*******************************************************************************/ + +bool patcher_checkcast_instanceof_flags(u1 *sp) +{ + u1 *ra; + u8 mcode; + constant_classref *cr; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 8)); + + /* get the fieldinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch class flags */ + + *((s4 *) (ra + 2)) = (s4) c->flags; + + return true; +} + + +/* patcher_checkcast_instanceof_interface ************************************** + + Machine code: + + + 45 8b 9a 1c 00 00 00 mov 0x1c(%r10),%r11d + 49 81 eb 00 00 00 00 sub $0x0,%r11 + 4d 85 db test %r11,%r11 + 0f 8e 94 04 00 00 jle 0x00002aaaaab018f8 + 4d 8b 9a 00 00 00 00 mov 0x0(%r10),%r11 + +*******************************************************************************/ + +bool patcher_checkcast_instanceof_interface(u1 *sp) +{ + u1 *ra; + u8 mcode; + constant_classref *cr; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 8)); + + /* get the fieldinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch super class index */ + + *((s4 *) (ra + 7 + 3)) = (s4) c->index; + + *((s4 *) (ra + 7 + 7 + 3 + 6 + 3)) = + (s4) (OFFSET(vftbl_t, interfacetable[0]) - + c->index * sizeof(methodptr*)); + + return true; +} + + +/* patcher_checkcast_class ***************************************************** + + Machine code: + + + 49 bb 00 00 00 00 00 00 00 00 mov $0x0,%r11 + 45 8b 92 20 00 00 00 mov 0x20(%r10),%r10d + 45 8b 9b 20 00 00 00 mov 0x20(%r11),%r11d + 4d 29 da sub %r11,%r10 + 49 bb 00 00 00 00 00 00 00 00 mov $0x0,%r11 + +*******************************************************************************/ + +bool patcher_checkcast_class(u1 *sp) +{ + u1 *ra; + u8 mcode; + constant_classref *cr; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 8)); + + /* get the fieldinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch super class' vftbl */ + + *((ptrint *) (ra + 2)) = (ptrint) c->vftbl; + *((ptrint *) (ra + 10 + 7 + 7 + 3 + 2)) = (ptrint) c->vftbl; + + return true; +} + + +/* patcher_instanceof_class **************************************************** + + Machine code: + + + 49 ba 00 00 00 00 00 00 00 00 mov $0x0,%r10 + +*******************************************************************************/ + +bool patcher_instanceof_class(u1 *sp) +{ + u1 *ra; + u8 mcode; + constant_classref *cr; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 8)); + + /* get the fieldinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch super class' vftbl */ + + *((ptrint *) (ra + 2)) = (ptrint) c->vftbl; + + return true; +} + + +/* patcher_clinit ************************************************************** + + May be used for GET/PUTSTATIC and in native stub. + + Machine code: + + + 4d 8b 15 92 ff ff ff mov -110(%rip),%r10 + 49 89 1a mov %rbx,(%r10) + +*******************************************************************************/ + +bool patcher_clinit(u1 *sp) +{ + u1 *ra; + u8 mcode; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + c = (classinfo *) *((ptrint *) (sp + 2 * 8)); + + /* check if the class is initialized */ + + if (!(c->state & CLASS_INITIALIZED)) + if (!initialize_class(c)) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + return true; +} + + +/* patcher_athrow_areturn ****************************************************** + + Machine code: + + + +*******************************************************************************/ + +#ifdef ENABLE_VERIFIER +bool patcher_athrow_areturn(u1 *sp) +{ + u1 *ra; + u8 mcode; + unresolved_class *uc; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + uc = (unresolved_class *) *((ptrint *) (sp + 2 * 8)); + + /* resolve the class */ + + if (!resolve_class(uc, resolveEager, false, &c)) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + return true; +} +#endif /* ENABLE_VERIFIER */ + + +/* patcher_resolve_native ****************************************************** + + Machine code: + + + 48 b8 00 00 00 00 00 00 00 00 mov $0x0,%rax + 48 ff d0 callq *%rax + +*******************************************************************************/ + +#if !defined(WITH_STATIC_CLASSPATH) +bool patcher_resolve_native(u1 *sp) +{ + u1 *ra; + u8 mcode; + methodinfo *m; + functionptr f; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 8)); + mcode = *((u8 *) (sp + 3 * 8)); + m = (methodinfo *) *((ptrint *) (sp + 2 * 8)); + + /* resolve native function */ + + if (!(f = native_resolve_function(m))) + return false; + + /* patch back original code */ + + *((u8 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop's */ + + if (opt_shownops) + ra = ra + 5; + + /* patch native function pointer */ + + *((ptrint *) (ra + 2)) = (ptrint) f; + + return true; +} +#endif /* !defined(WITH_STATIC_CLASSPATH) */ + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */