issue #169 MIR update

arrays
Dibyendu Majumdar 4 years ago
parent 6f7313594c
commit 71e5bd8d8c

@ -0,0 +1,15 @@
# Run this on LLVM 10 source dir
mkdir build
cd build
cmake3 -DCMAKE_INSTALL_PREFIX=$HOME/Software/llvm10 \
-DLLVM_TARGETS_TO_BUILD="X86" \
-DLLVM_BUILD_TOOLS=OFF \
-DLLVM_INCLUDE_TOOLS=OFF \
-DLLVM_BUILD_EXAMPLES=OFF \
-DLLVM_INCLUDE_EXAMPLES=OFF \
-DLLVM_BUILD_TESTS=OFF \
-DLLVM_INCLUDE_TESTS=OFF \
..
cmake3 --build . --config Release --target install

@ -31,6 +31,8 @@
#include "aarch64/caarch64.h"
#elif defined(__PPC64__)
#include "ppc64/cppc64.h"
#elif defined(__s390x__)
#include "s390x/cs390x.h"
#else
#error "undefined or unsupported generation target for C"
#endif
@ -317,6 +319,8 @@ static mir_size_t raw_type_size (c2m_ctx_t c2m_ctx, struct type *type) {
#include "aarch64/caarch64-code.c"
#elif defined(__PPC64__)
#include "ppc64/cppc64-code.c"
#elif defined(__s390x__)
#include "s390x/cs390x-code.c"
#else
#error "undefined or unsupported generation target for C"
#endif
@ -10237,7 +10241,8 @@ static void gen_memcpy (MIR_context_t ctx, MIR_disp_t disp, MIR_reg_t base, op_t
MIR_op_t treg_op, args[6];
MIR_module_t module;
if (val.mir_op.u.mem.index == 0 && val.mir_op.u.mem.disp == disp && val.mir_op.u.mem.base == base)
if (val.mir_op.mode == MIR_OP_MEM && val.mir_op.u.mem.index == 0 && val.mir_op.u.mem.disp == disp
&& val.mir_op.u.mem.base == base)
return;
if (memcpy_item == NULL) {
ret_type = get_int_mir_type (sizeof (mir_size_t));
@ -11435,6 +11440,7 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
signed_p ? MIR_new_int_op (ctx, e->u.i_val) : MIR_new_uint_op (ctx, e->u.u_val));
emit3 (ctx, short_p ? MIR_UBGTS : MIR_UBGT, MIR_new_label_op (ctx, label), index.mir_op,
MIR_new_uint_op (ctx, range));
if (short_p) emit2 (ctx, MIR_UEXT32, index.mir_op, index.mir_op);
VARR_TRUNC (case_t, switch_cases, 0);
for (c = DLIST_HEAD (case_t, switch_attr->case_labels);
c != NULL && c->case_node->code != N_DEFAULT; c = DLIST_NEXT (case_t, c))
@ -12185,6 +12191,8 @@ static void init_include_dirs (MIR_context_t ctx) {
#else
VARR_PUSH (char_ptr_t, system_headers, "/usr/include/powerpc64-linux-gnu");
#endif
#elif defined(__linux__) && defined(__s390x__)
VARR_PUSH (char_ptr_t, system_headers, "/usr/include/s390x-linux-gnu");
#endif
#if defined(__APPLE__) || defined(__unix__)
VARR_PUSH (char_ptr_t, system_headers, "/usr/include");

@ -0,0 +1,23 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#include "../mirc.h"
#include "mirc-s390x-linux.h"
static const char *standard_includes[] = {mirc, s390x_mirc};
static const char *standard_include_dirs[] = {"include/mirc/", "include/mirc/s390x/"};
#define MAX_ALIGNMENT 16
#define ADJUST_VAR_ALIGNMENT(c2m_ctx, align, type) \
s390x_adjust_var_alignment (c2m_ctx, align, type)
static int s390x_adjust_var_alignment (c2m_ctx_t c2m_ctx, int align, struct type *type) {
return align;
}
static int invalid_alignment (mir_llong align) {
return align != 0 && align != 1 && align != 2 && align != 4 && align != 8 && align != 16;
}

@ -0,0 +1,50 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#include <stdint.h>
#define MIR_CHAR_BIT 8
typedef int8_t mir_schar;
typedef int16_t mir_short;
typedef int32_t mir_int;
typedef int64_t mir_long;
typedef int64_t mir_llong;
#define MIR_SCHAR_MIN INT8_MIN
#define MIR_SCHAR_MAX INT8_MAX
#define MIR_SHORT_MIN INT16_MIN
#define MIR_SHORT_MAX INT16_MAX
#define MIR_INT_MIN INT32_MIN
#define MIR_INT_MAX INT32_MAX
#define MIR_LONG_MIN INT64_MIN
#define MIR_LONG_MAX INT64_MAX
#define MIR_LLONG_MIN INT64_MIN
#define MIR_LLONG_MAX INT64_MAX
typedef uint8_t mir_uchar;
typedef uint16_t mir_ushort;
typedef uint32_t mir_uint;
typedef uint64_t mir_ulong;
typedef uint64_t mir_ullong;
#define MIR_UCHAR_MAX UINT8_MAX
#define MIR_USHORT_MAX UINT16_MAX
#define MIR_UINT_MAX UINT32_MAX
#define MIR_ULONG_MAX UINT64_MAX
#define MIR_ULLONG_MAX UINT64_MAX
typedef mir_schar mir_char;
#define MIR_CHAR_MIN MIR_SCHAR_MIN
#define MIR_CHAR_MAX MIR_SCHAR_MAX
typedef float mir_float;
typedef double mir_double;
typedef long double mir_ldouble;
typedef uint8_t mir_bool;
typedef int64_t mir_ptrdiff_t;
typedef uint64_t mir_size_t;
#define MIR_SIZE_MAX UINT64_MAX

@ -0,0 +1,102 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
static char s390x_mirc[]
= "#define __zarch__ 1\n"
"#define _LP64 1\n"
"#define __LP64__ 1\n"
"#define __s390__ 1\n"
"#define __s390x__ 1\n"
"#define __ELF__ 1\n"
"\n"
#if __SIZEOF_LONG_DOUBLE__ == 16
"#define __LONG_DOUBLE_128__ 1\n" // ???
"#define __SIZEOF_LONG_DOUBLE__ 16\n"
#else
"#define __SIZEOF_LONG_DOUBLE__ 8\n"
#endif
"#define __SIZEOF_FLOAT__ 4\n"
"#define __SIZEOF_INT__ 4\n"
"#define __SIZEOF_LONG_DOUBLE__ 16\n"
"#define __SIZEOF_LONG_LONG__ 8\n"
"#define __SIZEOF_LONG__ 8\n"
"#define __SIZEOF_POINTER__ 8\n"
"#define __SIZEOF_PTRDIFF_T__ 8\n"
"#define __SIZEOF_SHORT__ 2\n"
"#define __SIZEOF_SIZE_T__ 8\n"
"\n"
"#define __ORDER_LITTLE_ENDIAN__ 1234\n"
"#define __ORDER_BIG_ENDIAN__ 4321\n"
"#define _BIG_ENDIAN 1\n"
"#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__\n"
"\n"
"/* Some GCC predefined macros: */\n"
"#define __SIZE_TYPE__ unsigned long\n"
"#define __PTRDIFF_TYPE__ long\n"
"#define __INTMAX_TYPE__ long\n"
"#define __UINTMAX_TYPE__ unsigned long\n"
"#define __INT8_TYPE__ signed char\n"
"#define __INT16_TYPE__ short\n"
"#define __INT32_TYPE__ int\n"
"#define __INT64_TYPE__ long\n"
"#define __UINT8_TYPE__ unsigned char\n"
"#define __UINT16_TYPE__ unsigned short\n"
"#define __UINT32_TYPE__ unsigned int\n"
"#define __UINT64_TYPE__ unsigned long\n"
"#define __INTPTR_TYPE__ long\n"
"#define __UINTPTR_TYPE__ unsigned long\n"
"\n"
"#define __CHAR_BIT__ 8\n"
"#define __INT8_MAX__ 127\n"
"#define __INT16_MAX__ 32767\n"
"#define __INT32_MAX__ 2147483647\n"
"#define __INT64_MAX__ 9223372036854775807l\n"
"#define __UINT8_MAX__ (__INT8_MAX__ * 2u + 1u)\n"
"#define __UINT16_MAX__ (__INT16_MAX__ * 2u + 1u)\n"
"#define __UINT32_MAX__ (__INT32_MAX__ * 2u + 1u)\n"
"#define __UINT64_MAX__ (__INT64_MAX__ * 2u + 1u)\n"
"#define __SCHAR_MAX__ __INT8_MAX__\n"
"#define __SHRT_MAX__ __INT16_MAX__\n"
"#define __INT_MAX__ __INT32_MAX__\n"
"#define __LONG_MAX__ __INT64_MAX__\n"
"#define __LONG_LONG_MAX__ __INT64_MAX__\n"
"#define __SIZE_MAX__ __UINT64_MAX__\n"
"#define __PTRDIFF_MAX__ __INT64_MAX__\n"
"#define __INTMAX_MAX__ __INT64_MAX__\n"
"#define __UINTMAX_MAX__ __UINT64_MAX__\n"
"#define __INTPTR_MAX__ __INT64_MAX__\n"
"#define __UINTPTR_MAX__ __UINT64_MAX__\n"
"\n"
"#define __FLT_MIN_EXP__ (-125)\n"
"#define __FLT_MAX_EXP__ 128\n"
"#define __FLT_DIG__ 6\n"
"#define __FLT_DECIMAL_DIG__ 9\n"
"#define __FLT_MANT_DIG__ 24\n"
"#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F\n"
"#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F\n"
"#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F\n"
"\n"
"#define __DBL_MIN_EXP__ (-1021)\n"
"#define __DBL_MAX_EXP__ 1024\n"
"#define __DBL_DIG__ 15\n"
"#define __DBL_DECIMAL_DIG__ 17\n"
"#define __DBL_MANT_DIG__ 53\n"
"#define __DBL_MAX__ ((double) 1.79769313486231570814527423731704357e+308L)\n"
"#define __DBL_MIN__ ((double) 2.22507385850720138309023271733240406e-308L)\n"
"#define __DBL_EPSILON__ ((double) 2.22044604925031308084726333618164062e-16L)\n"
"\n"
"typedef unsigned short char16_t;\n"
"typedef unsigned int char32_t;\n"
"\n"
#if defined(__linux__)
"#define __gnu_linux__ 1\n"
"#define __linux 1\n"
"#define __linux__ 1\n"
"#define linux 1\n"
"#define unix 1\n"
"#define __unix 1\n"
"#define __unix__ 1\n"
#endif
"\n"
"void *alloca (unsigned long);\n";

@ -33,6 +33,8 @@ static int target_locs_num (MIR_reg_t loc, MIR_type_t type) {
return loc > MAX_HARD_REG && type == MIR_T_LD ? 2 : 1;
}
static inline MIR_reg_t target_nth_loc (MIR_reg_t loc, MIR_type_t type, int n) { return loc + n; }
/* Hard regs not used in machinized code, preferably call used ones. */
const MIR_reg_t TEMP_INT_HARD_REG1 = R9_HARD_REG, TEMP_INT_HARD_REG2 = R10_HARD_REG;
const MIR_reg_t TEMP_FLOAT_HARD_REG1 = V16_HARD_REG, TEMP_FLOAT_HARD_REG2 = V17_HARD_REG;

@ -35,6 +35,8 @@ static int target_locs_num (MIR_reg_t loc, MIR_type_t type) {
return /*loc > MAX_HARD_REG && */ type == MIR_T_LD ? 2 : 1;
}
static inline MIR_reg_t target_nth_loc (MIR_reg_t loc, MIR_type_t type, int n) { return loc + n; }
/* Hard regs not used in machinized code, preferably call used ones. */
const MIR_reg_t TEMP_INT_HARD_REG1 = R11_HARD_REG, TEMP_INT_HARD_REG2 = R12_HARD_REG;
const MIR_reg_t TEMP_FLOAT_HARD_REG1 = F11_HARD_REG, TEMP_FLOAT_HARD_REG2 = F12_HARD_REG;
@ -53,13 +55,14 @@ static inline int target_hard_reg_type_ok_p (MIR_reg_t hard_reg, MIR_type_t type
static inline int target_fixed_hard_reg_p (MIR_reg_t hard_reg) {
assert (hard_reg <= MAX_HARD_REG);
return (hard_reg == FP_HARD_REG || hard_reg == SP_HARD_REG || hard_reg == LR_HARD_REG
/* don't bother to allocate R0 as it has special meaning for base reg and of addi: */
|| hard_reg == R0_HARD_REG || hard_reg == R2_HARD_REG || hard_reg == R13_HARD_REG
|| hard_reg == TEMP_INT_HARD_REG1 || hard_reg == TEMP_INT_HARD_REG2
|| hard_reg == TEMP_FLOAT_HARD_REG1 || hard_reg == TEMP_FLOAT_HARD_REG2
|| hard_reg == TEMP_DOUBLE_HARD_REG1 || hard_reg == TEMP_DOUBLE_HARD_REG2
|| hard_reg == TEMP_LDOUBLE_HARD_REG1 || hard_reg == TEMP_LDOUBLE_HARD_REG2);
return (hard_reg == FP_HARD_REG || hard_reg == SP_HARD_REG
|| hard_reg == LR_HARD_REG
/* don't bother to allocate R0 as it has special meaning for base reg and of addi: */
|| hard_reg == R0_HARD_REG || hard_reg == R2_HARD_REG || hard_reg == R13_HARD_REG
|| hard_reg == TEMP_INT_HARD_REG1 || hard_reg == TEMP_INT_HARD_REG2
|| hard_reg == TEMP_FLOAT_HARD_REG1 || hard_reg == TEMP_FLOAT_HARD_REG2
|| hard_reg == TEMP_DOUBLE_HARD_REG1 || hard_reg == TEMP_DOUBLE_HARD_REG2
|| hard_reg == TEMP_LDOUBLE_HARD_REG1 || hard_reg == TEMP_LDOUBLE_HARD_REG2);
}
static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg) {
@ -75,7 +78,7 @@ static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg) {
| Floating point register save area optional optional
| General register save area optional optional
| VRSAVE save word (32-bits) 0 NA
| Alignment padding (4 or 12 bytes)
| Alignment padding (4 or 12 bytes)
| Vector register save area (quadword aligned) we don't have it
| Local variable space optional optional
| Parameter save area (for callees) (SP + 48) (SP + 32) optional
@ -216,33 +219,35 @@ static void machinize_call (MIR_context_t ctx, MIR_insn_t call_insn) {
ext_insn = MIR_new_insn (ctx, ext_code, temp_op, arg_op);
call_insn->ops[i] = arg_op = temp_op;
}
mem_type = type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD ? type : MIR_T_I64; // ???
mem_type = type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD ? type : MIR_T_I64; // ???
if ((type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) && n_fregs < 13) {
/* put arguments to argument hard regs */
if (ext_insn != NULL) gen_add_insn_before (ctx, call_insn, ext_insn);
arg_reg_op = _MIR_new_hard_reg_op (ctx, F1_HARD_REG + n_fregs);
gen_mov (ctx, call_insn, type == MIR_T_F ? MIR_FMOV : type == MIR_T_D ? MIR_DMOV : MIR_LDMOV, // ???
arg_reg_op, arg_op);
gen_mov (ctx, call_insn,
type == MIR_T_F ? MIR_FMOV : type == MIR_T_D ? MIR_DMOV : MIR_LDMOV, // ???
arg_reg_op, arg_op);
call_insn->ops[i] = arg_reg_op;
if (vararg_p) { // ??? dead insns
if (vararg_p) { // ??? dead insns
if (n_iregs >= 8 || type == MIR_T_LD && n_iregs == 7) { /* store in memory too */
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, mem_size + PPC64_STACK_HEADER_SIZE,
SP_HARD_REG, MIR_NON_HARD_REG, 1);
gen_assert (n_fregs < 12);
gen_mov (ctx, call_insn, type == MIR_T_LD ? MIR_LDMOV : MIR_DMOV, mem_op, arg_reg_op);
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, mem_size + PPC64_STACK_HEADER_SIZE,
SP_HARD_REG, MIR_NON_HARD_REG, 1);
gen_assert (n_fregs < 12);
gen_mov (ctx, call_insn, type == MIR_T_LD ? MIR_LDMOV : MIR_DMOV, mem_op, arg_reg_op);
}
if (n_iregs < 8) { /* load into gp reg too */
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, -16, SP_HARD_REG, MIR_NON_HARD_REG, 1);
gen_mov (ctx, call_insn, type == MIR_T_LD ? MIR_LDMOV : MIR_DMOV, mem_op, arg_reg_op);
mem_type = mem_type == MIR_T_F ? MIR_T_I32 : MIR_T_I64; // ???
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, -16, SP_HARD_REG, MIR_NON_HARD_REG, 1);
arg_reg_op = _MIR_new_hard_reg_op (ctx, R3_HARD_REG + n_iregs);
gen_mov (ctx, call_insn, MIR_MOV, arg_reg_op, mem_op);
call_insn->ops[i] = arg_reg_op; /* keep it alive */
if (type == MIR_T_LD && n_iregs + 1 < 8) {
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, -8, SP_HARD_REG, MIR_NON_HARD_REG, 1);
gen_mov (ctx, call_insn, MIR_MOV, _MIR_new_hard_reg_op (ctx, R3_HARD_REG + n_iregs + 1), mem_op);
}
if (n_iregs < 8) { /* load into gp reg too */
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, -16, SP_HARD_REG, MIR_NON_HARD_REG, 1);
gen_mov (ctx, call_insn, type == MIR_T_LD ? MIR_LDMOV : MIR_DMOV, mem_op, arg_reg_op);
mem_type = mem_type == MIR_T_F ? MIR_T_I32 : MIR_T_I64; // ???
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, -16, SP_HARD_REG, MIR_NON_HARD_REG, 1);
arg_reg_op = _MIR_new_hard_reg_op (ctx, R3_HARD_REG + n_iregs);
gen_mov (ctx, call_insn, MIR_MOV, arg_reg_op, mem_op);
call_insn->ops[i] = arg_reg_op; /* keep it alive */
if (type == MIR_T_LD && n_iregs + 1 < 8) {
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, -8, SP_HARD_REG, MIR_NON_HARD_REG, 1);
gen_mov (ctx, call_insn, MIR_MOV, _MIR_new_hard_reg_op (ctx, R3_HARD_REG + n_iregs + 1),
mem_op);
}
}
}
n_fregs += type == MIR_T_LD ? 2 : 1;
@ -255,9 +260,9 @@ static void machinize_call (MIR_context_t ctx, MIR_insn_t call_insn) {
if (ext_insn != NULL) gen_add_insn_before (ctx, call_insn, ext_insn);
new_insn_code
= (type == MIR_T_F ? MIR_FMOV
: type == MIR_T_D ? MIR_DMOV : type == MIR_T_LD ? MIR_LDMOV : MIR_MOV);
: type == MIR_T_D ? MIR_DMOV : type == MIR_T_LD ? MIR_LDMOV : MIR_MOV);
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, mem_size + PPC64_STACK_HEADER_SIZE,
SP_HARD_REG, MIR_NON_HARD_REG, 1);
SP_HARD_REG, MIR_NON_HARD_REG, 1);
gen_mov (ctx, call_insn, new_insn_code, mem_op, arg_op);
call_insn->ops[i] = mem_op;
}
@ -269,14 +274,14 @@ static void machinize_call (MIR_context_t ctx, MIR_insn_t call_insn) {
#else
if (mem_size < 64) mem_size = 64; /* minimal param save area */
#endif
if (param_save_area_size < mem_size)
param_save_area_size = mem_size;
if (param_save_area_size < mem_size) param_save_area_size = mem_size;
n_iregs = n_fregs = 0;
for (size_t i = 0; i < proto->nres; i++) {
ret_reg_op = call_insn->ops[i + 2];
gen_assert (ret_reg_op.mode == MIR_OP_REG || ret_reg_op.mode == MIR_OP_HARD_REG);
type = proto->res_types[i];
if (((type == MIR_T_F || type == MIR_T_D) && n_fregs < 4) || (type == MIR_T_LD && n_fregs < 3)) {
if (((type == MIR_T_F || type == MIR_T_D) && n_fregs < 4)
|| (type == MIR_T_LD && n_fregs < 3)) {
new_insn_code = type == MIR_T_F ? MIR_FMOV : type == MIR_T_D ? MIR_DMOV : MIR_LDMOV;
ret_reg = F1_HARD_REG + n_fregs++;
} else if (n_iregs < 8) {
@ -284,10 +289,9 @@ static void machinize_call (MIR_context_t ctx, MIR_insn_t call_insn) {
ret_reg = R3_HARD_REG + n_iregs++;
} else {
(*MIR_get_error_func (ctx)) (MIR_ret_error,
"ppc64 can not handle this combination of return values");
"ppc64 can not handle this combination of return values");
}
new_insn = MIR_new_insn (ctx, new_insn_code, ret_reg_op,
_MIR_new_hard_reg_op (ctx, ret_reg));
new_insn = MIR_new_insn (ctx, new_insn_code, ret_reg_op, _MIR_new_hard_reg_op (ctx, ret_reg));
MIR_insert_insn_after (ctx, curr_func_item, call_insn, new_insn);
call_insn->ops[i + 2] = new_insn->ops[1];
if ((ext_code = get_ext_code (type)) != MIR_INVALID_INSN) {
@ -503,7 +507,7 @@ static MIR_disp_t target_get_stack_slot_offset (MIR_context_t ctx, MIR_type_t ty
MIR_reg_t slot) {
/* slot is 0, 1, ... */
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
return ((MIR_disp_t) slot * 8 + PPC64_STACK_HEADER_SIZE + param_save_area_size);
}
@ -514,7 +518,7 @@ static void set_prev_sp_op (MIR_context_t ctx, MIR_insn_t anchor, MIR_op_t *prev
stack_arg_func_p = TRUE;
*prev_sp_op = _MIR_new_hard_reg_op (ctx, R11_HARD_REG);
gen_mov (ctx, anchor, MIR_MOV, *prev_sp_op,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 0, SP_HARD_REG, MIR_NON_HARD_REG, 1));
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 0, SP_HARD_REG, MIR_NON_HARD_REG, 1));
}
}
@ -542,27 +546,29 @@ static void target_machinize (MIR_context_t ctx) {
arg_var_op = MIR_new_reg_op (ctx, i + 1);
if ((type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) && fp_arg_num < 13) {
if (type == MIR_T_LD && fp_arg_num == 12) { /* dmov f14,disp(r1) -> lfd f14,disp(r1): */
set_prev_sp_op (ctx, anchor, &prev_sp_op);
arg_reg_op = _MIR_new_hard_reg_op (ctx, F14_HARD_REG);
gen_mov (ctx, anchor, MIR_DMOV, arg_reg_op,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_D, disp + 8, R11_HARD_REG, MIR_NON_HARD_REG, 1));
set_prev_sp_op (ctx, anchor, &prev_sp_op);
arg_reg_op = _MIR_new_hard_reg_op (ctx, F14_HARD_REG);
gen_mov (ctx, anchor, MIR_DMOV, arg_reg_op,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_D, disp + 8, R11_HARD_REG, MIR_NON_HARD_REG,
1));
}
arg_reg_op = _MIR_new_hard_reg_op (ctx, F1_HARD_REG + fp_arg_num);
gen_mov (ctx, anchor, type == MIR_T_F ? MIR_FMOV : type == MIR_T_D ? MIR_DMOV : MIR_LDMOV,
arg_var_op, arg_reg_op); /* (f|d|ld|)mov arg, arg_hard_reg */
arg_var_op, arg_reg_op); /* (f|d|ld|)mov arg, arg_hard_reg */
fp_arg_num += type == MIR_T_LD ? 2 : 1;
} else if (type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) { /* (f|d|ld|)mov arg, arg_memory */
} else if (type == MIR_T_F || type == MIR_T_D
|| type == MIR_T_LD) { /* (f|d|ld|)mov arg, arg_memory */
set_prev_sp_op (ctx, anchor, &prev_sp_op);
gen_mov (ctx, anchor, type == MIR_T_F ? MIR_FMOV : type == MIR_T_D ? MIR_DMOV : MIR_LDMOV,
arg_var_op,
_MIR_new_hard_reg_mem_op (ctx, type, disp, R11_HARD_REG, MIR_NON_HARD_REG, 1));
arg_var_op,
_MIR_new_hard_reg_mem_op (ctx, type, disp, R11_HARD_REG, MIR_NON_HARD_REG, 1));
} else if (int_arg_num < 8) { /* mov arg, arg_hard_reg */
arg_reg_op = _MIR_new_hard_reg_op (ctx, R3_HARD_REG + int_arg_num);
gen_mov (ctx, anchor, MIR_MOV, arg_var_op, arg_reg_op);
} else { /* mov arg, arg_memory */
set_prev_sp_op (ctx, anchor, &prev_sp_op);
gen_mov (ctx, anchor, MIR_MOV, arg_var_op,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, disp, R11_HARD_REG, MIR_NON_HARD_REG, 1));
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, disp, R11_HARD_REG, MIR_NON_HARD_REG, 1));
}
disp += type == MIR_T_LD ? 16 : 8;
int_arg_num += type == MIR_T_LD ? 2 : 1;
@ -646,7 +652,8 @@ static void target_machinize (MIR_context_t ctx) {
va_reg = va_op.u.reg;
/* Insns can be non-simplified as soon as they match a machine insn. */
/* treg = mem64[r1]; treg = treg + var_args_start; mem64[va_reg] = treg */
gen_mov (ctx, insn, MIR_MOV, treg_op, _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 0, R1_HARD_REG, MIR_NON_HARD_REG, 1));
gen_mov (ctx, insn, MIR_MOV, treg_op,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 0, R1_HARD_REG, MIR_NON_HARD_REG, 1));
gen_mov (ctx, insn, MIR_MOV, treg_op2, MIR_new_int_op (ctx, var_args_start));
/* don't use immediate in ADD as treg_op can become r0: */
new_insn = MIR_new_insn (ctx, MIR_ADD, treg_op, treg_op, treg_op2);
@ -672,7 +679,7 @@ static void target_machinize (MIR_context_t ctx) {
assert (insn->ops[i].mode == MIR_OP_REG);
res_type = func->res_types[i];
if (((res_type == MIR_T_F || res_type == MIR_T_D) && n_fregs < 4)
|| (res_type == MIR_T_LD && n_fregs < 3)) {
|| (res_type == MIR_T_LD && n_fregs < 3)) {
new_insn_code
= res_type == MIR_T_F ? MIR_FMOV : res_type == MIR_T_D ? MIR_DMOV : MIR_LDMOV;
ret_reg = F1_HARD_REG + n_fregs++;
@ -716,8 +723,7 @@ static void target_make_prolog_epilog (MIR_context_t ctx, bitmap_t used_hard_reg
func = curr_func_item->u.func;
anchor = DLIST_HEAD (MIR_insn_t, func->insns);
if (func->vararg_p) {
for (i = 0; i < 8; i++)
isave (ctx, anchor, PPC64_STACK_HEADER_SIZE + i * 8, i + R3_HARD_REG);
for (i = 0; i < 8; i++) isave (ctx, anchor, PPC64_STACK_HEADER_SIZE + i * 8, i + R3_HARD_REG);
}
for (i = saved_iregs_num = saved_fregs_num = 0; i <= MAX_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
@ -741,26 +747,27 @@ static void target_make_prolog_epilog (MIR_context_t ctx, bitmap_t used_hard_reg
if (frame_size % 16 != 0) frame_size = (frame_size + 15) / 16 * 16;
gen_mov (ctx, anchor, MIR_MOV, r0_reg_op, lr_reg_op); /* r0 = lr */
gen_mov (ctx, anchor, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 16,
R1_HARD_REG, MIR_NON_HARD_REG, 1), r0_reg_op); /* mem[r1] = r0 */
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 16, R1_HARD_REG, MIR_NON_HARD_REG, 1),
r0_reg_op); /* mem[r1] = r0 */
gen_mov (ctx, anchor, MIR_MOV, r0_reg_op, sp_reg_op);
new_insn = MIR_new_insn (ctx, MIR_ADD, sp_reg_op, sp_reg_op, MIR_new_int_op (ctx, -frame_size));
gen_add_insn_before (ctx, anchor, new_insn); /* r1 -= frame_size */
gen_mov (ctx, anchor, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 0, R1_HARD_REG, MIR_NON_HARD_REG, 1),
r0_reg_op); /* mem[r1] = r0 */
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 0, R1_HARD_REG, MIR_NON_HARD_REG, 1),
r0_reg_op); /* mem[r1] = r0 */
gen_mov (ctx, anchor, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, PPC64_TOC_OFFSET, R1_HARD_REG, MIR_NON_HARD_REG, 1),
_MIR_new_hard_reg_op (ctx, R2_HARD_REG)); /* mem[r1+toc_off] = r2 */
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, PPC64_TOC_OFFSET, R1_HARD_REG,
MIR_NON_HARD_REG, 1),
_MIR_new_hard_reg_op (ctx, R2_HARD_REG)); /* mem[r1+toc_off] = r2 */
for (n = i = 0; i <= MAX_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
if (i < F0_HARD_REG)
isave (ctx, anchor, start_save_regs_offset + (n++) * 8, i);
isave (ctx, anchor, start_save_regs_offset + (n++) * 8, i);
else
fsave (ctx, anchor, start_save_regs_offset + (n++) * 8, i);
fsave (ctx, anchor, start_save_regs_offset + (n++) * 8, i);
}
isave (ctx, anchor, start_save_regs_offset + n * 8, R31_HARD_REG); /* save R31 */
gen_mov (ctx, anchor, MIR_MOV, fp_reg_op, sp_reg_op); /* r31 = r1 */
gen_mov (ctx, anchor, MIR_MOV, fp_reg_op, sp_reg_op); /* r31 = r1 */
/* Epilogue: */
anchor = DLIST_TAIL (MIR_insn_t, func->insns);
assert (anchor->code == MIR_RET);
@ -770,22 +777,23 @@ static void target_make_prolog_epilog (MIR_context_t ctx, bitmap_t used_hard_reg
if (i < F0_HARD_REG) {
gen_mov (ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, i),
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, start_save_regs_offset + (n++) * 8,
FP_HARD_REG, MIR_NON_HARD_REG, 1));
FP_HARD_REG, MIR_NON_HARD_REG, 1));
} else {
gen_mov (ctx, anchor, MIR_DMOV, _MIR_new_hard_reg_op (ctx, i),
_MIR_new_hard_reg_mem_op (ctx, MIR_T_D, start_save_regs_offset + (n++) * 8,
FP_HARD_REG, MIR_NON_HARD_REG, 1));
FP_HARD_REG, MIR_NON_HARD_REG, 1));
}
}
/* Restore sp, fp, lr */
new_insn = MIR_new_insn (ctx, MIR_ADD, sp_reg_op, fp_reg_op, MIR_new_int_op (ctx, frame_size));
gen_add_insn_before (ctx, anchor, new_insn); /* sp = fp + frame_size */
gen_mov (ctx, anchor, MIR_MOV, fp_reg_op,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, start_save_regs_offset + n * 8,
FP_HARD_REG, MIR_NON_HARD_REG, 1)); /* restore fp */
gen_mov (ctx, anchor, MIR_MOV, r0_reg_op,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 16, R1_HARD_REG, MIR_NON_HARD_REG, 1)); /* r0 = 16(sp) */
gen_mov (ctx, anchor, MIR_MOV, lr_reg_op, r0_reg_op); /* lr = r0 */
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, start_save_regs_offset + n * 8, FP_HARD_REG,
MIR_NON_HARD_REG, 1)); /* restore fp */
gen_mov (ctx, anchor, MIR_MOV, r0_reg_op,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 16, R1_HARD_REG, MIR_NON_HARD_REG,
1)); /* r0 = 16(sp) */
gen_mov (ctx, anchor, MIR_MOV, lr_reg_op, r0_reg_op); /* lr = r0 */
}
struct pattern {
@ -896,7 +904,7 @@ struct pattern {
BO<number> - field [6..10] for bcond
BI<number> - field [11..15] for bcond
LK<number> - field [31..31]
at - address disp PPC64_TOC_OFFSET
T - switch table displacement
*/
@ -905,8 +913,8 @@ struct pattern {
static const struct pattern patterns[] = {
{MIR_MOV, "r r", "o31 O444 ra0 rs1 rb1"}, /* or ra,rs,rs */
{MIR_MOV, "r h64", "o31 O339 rt0 sr8"}, /* mflr rt */
{MIR_MOV, "h64 r", "o31 O467 rs1 sr8"}, /* mtlr rs */
{MIR_MOV, "r h64", "o31 O339 rt0 sr8"}, /* mflr rt */
{MIR_MOV, "h64 r", "o31 O467 rs1 sr8"}, /* mtlr rs */
// ??? loads/stores with update
{MIR_MOV, "r Mds", "o58 rt0 Mds"}, /* ld rt,ds-mem */
@ -964,10 +972,14 @@ static const struct pattern patterns[] = {
{MIR_DMOV, "Md r", "o31 O727 rt1 M"}, /* stfdx rt, index-mem */
{MIR_LDMOV, "r r", "o63 O72 rt0 rb1;o63 O72 nt0 nb1"}, /* fmr rt,rb; fmr rt+1,rb+1 */
{MIR_LDMOV, "r mld", "o50 rt0 m; o50 nt0 mn"}, /* lfd rt,disp-mem; lfd rt+1,disp+8-mem */
{MIR_LDMOV, "mld r", "o54 rt1 m; o54 nt1 mn"}, /* stfd rt,disp-mem; stfdx rt+1,disp+8-mem */
{MIR_LDMOV, "r mld0", "o31 O444 ha10 hs0 hb0; o50 rt0 ha10; o50 nt0 ha10 i8"}, /* mr r10,r0; lfd rt,(r10); lfd rt+1,8(r10) */
{MIR_LDMOV, "mld0 r", "o31 O444 ha10 hs0 hb0; o54 rt1 ha10; o54 nt1 ha10 i8"}, /* mr r10,r0; stfd rt,(r10); stfdx rt+1,8(r10) */
{MIR_LDMOV, "r mld", "o50 rt0 m; o50 nt0 mn"}, /* lfd rt,disp-mem; lfd rt+1,disp+8-mem */
{MIR_LDMOV, "mld r", "o54 rt1 m; o54 nt1 mn"}, /* stfd rt,disp-mem; stfdx rt+1,disp+8-mem */
{MIR_LDMOV, "r mld0",
"o31 O444 ha10 hs0 hb0; o50 rt0 ha10; o50 nt0 ha10 i8"}, /* mr r10,r0; lfd rt,(r10); lfd
rt+1,8(r10) */
{MIR_LDMOV, "mld0 r",
"o31 O444 ha10 hs0 hb0; o54 rt1 ha10; o54 nt1 ha10 i8"}, /* mr r10,r0; stfd rt,(r10); stfdx
rt+1,8(r10) */
{MIR_EXT8, "r r", "o31 O954 ra0 rs1"}, /* extsb ra,rs */
{MIR_EXT16, "r r", "o31 O922 ra0 rs1"}, /* extsh ra,rs */
@ -1148,58 +1160,63 @@ static const struct pattern patterns[] = {
#define BRC(o, i) "o16 BO" #o " BI" #i " l"
#define BRCL(o, i) "o16 BO" #o " BI" #i " l8; o18 L"
#define BRLOG(CODE, CMP, BI, COND, NEG_COND) \
{CODE, "l r", CMP (i0) "; " BRC (COND, BI)}, /* cmp 7,ra1,0;bcond 7,l; */ \
{CODE, "L r", CMP (i0) "; " BRCL (NEG_COND, BI)},/* cmp 7,ra1,0;bneg_cond 7,o8;b L;l8:*/
#define BRLOG(CODE, CMP, BI, COND, NEG_COND) \
{CODE, "l r", CMP (i0) "; " BRC (COND, BI)}, /* cmp 7,ra1,0;bcond 7,l; */ \
{CODE, "L r", CMP (i0) "; " BRCL (NEG_COND, BI)}, /* cmp 7,ra1,0;bneg_cond 7,o8;b L;l8:*/
BRLOG (MIR_BT, CMPDI, 30, 4, 12) BRLOG (MIR_BTS, CMPWI, 30, 4, 12)
BRLOG (MIR_BF, CMPDI, 30, 12, 4) BRLOG (MIR_BFS, CMPWI, 30, 12, 4)
BRLOG (MIR_BF, CMPDI, 30, 12, 4) BRLOG (MIR_BFS, CMPWI, 30, 12, 4)
#define BRCMP(CODE, CMP, CMPI, BI, COND, NEG_COND) \
{CODE, "l r r", CMP "; " BRC (COND, BI)}, /* cmp 7,ra1,rb2;bcond 7,l; */ \
{CODE, "l r i", CMPI "; " BRC (COND, BI)},/* cmpi 7,ra1,i;bcond 7,l;:*/ \
{CODE, "L r r", CMP "; " BRCL (NEG_COND, BI)},/* cmp 7,ra1,rb2;bneg_cond 7,o8;b L;l8:*/ \
{CODE, "L r i", CMPI "; " BRCL (NEG_COND, BI)},/* cmp 7,ra1,i;bneg_cond 7,o8;b L;l8:*/
#define BRCMP(CODE, CMP, CMPI, BI, COND, NEG_COND) \
{CODE, "l r r", CMP "; " BRC (COND, BI)}, /* cmp 7,ra1,rb2;bcond 7,l; */ \
{CODE, "l r i", CMPI "; " BRC (COND, BI)}, /* cmpi 7,ra1,i;bcond 7,l;:*/ \
{CODE, "L r r", CMP "; " BRCL (NEG_COND, BI)}, /* cmp 7,ra1,rb2;bneg_cond 7,o8;b L;l8:*/ \
{CODE, "L r i", CMPI "; " BRCL (NEG_COND, BI)}, /* cmp 7,ra1,i;bneg_cond 7,o8;b L;l8:*/
#define BRFCMP(CODE, BI, COND, NEG_COND) \
{CODE, "l r r", FCMPU "; " BRC (COND, BI)}, /* cmp 7,ra1,rb2;bcond 7,l; */ \
{CODE, "L r r", FCMPU "; " BRCL (NEG_COND, BI)},/* cmp 7,ra1,rb2;bneg_cond 7,o8;b L;l8:*/
#define BRFCMP(CODE, BI, COND, NEG_COND) \
{CODE, "l r r", FCMPU "; " BRC (COND, BI)}, /* cmp 7,ra1,rb2;bcond 7,l; */ \
{CODE, "L r r", FCMPU "; " BRCL (NEG_COND, BI)}, /* cmp 7,ra1,rb2;bneg_cond 7,o8;b L;l8:*/
// all ld insn are changed to builtins and bt/bts
BRCMP (MIR_BEQ, CMPD, CMPDI (i), 30, 12, 4) BRCMP (MIR_BEQS, CMPW, CMPWI (i), 30, 12, 4)
BRFCMP (MIR_FBEQ, 30, 12, 4) BRFCMP (MIR_DBEQ, 30, 12, 4)
BRCMP (MIR_BNE, CMPD, CMPDI (i), 30, 4, 12) BRCMP (MIR_BNES, CMPW, CMPWI (i), 30, 4, 12)
BRFCMP (MIR_FBNE, 30, 4, 12) BRFCMP (MIR_DBNE, 30, 4, 12)
#define BRUCMP(CODE, CMP, CMPI, BI, COND, NEG_COND) \
{CODE, "l r r", CMP "; " BRC (COND, BI)}, /* cmp 7,ra1,rb2;bcond 7,l; */ \
{CODE, "l r u", CMPI "; " BRC (COND, BI)},/* cmpi 7,ra1,u;bcond 7,l;:*/ \
{CODE, "L r r", CMP "; " BRCL (NEG_COND, BI)},/* cmp 7,ra1,rb2;bneg_cond 7,o8;b L;l8:*/ \
{CODE, "L r u", CMPI "; " BRCL (NEG_COND, BI)},/* cmp 7,ra1,u;bneg_cond 7,o8;b L;l8:*/
BRCMP (MIR_BLT, CMPD, CMPDI (i), 28, 12, 4) BRCMP (MIR_BLTS, CMPW, CMPWI (i), 28, 12, 4)
BRFCMP (MIR_FBLT, 28, 12, 4) BRFCMP (MIR_DBLT, 28, 12, 4)
BRUCMP (MIR_UBLT, CMPLD, CMPLDI, 28, 12, 4) BRUCMP (MIR_UBLTS, CMPLW, CMPLWI, 28, 12, 4)
BRCMP (MIR_BGE, CMPD, CMPDI (i), 28, 4, 12) BRCMP (MIR_BGES, CMPW, CMPWI (i), 28, 4, 12)
BRFCMP (MIR_FBGE, 28, 4, 12) BRFCMP (MIR_DBGE, 28, 4, 12)
BRUCMP (MIR_UBGE, CMPLD, CMPLDI, 28, 4, 12) BRUCMP (MIR_UBGES, CMPLW, CMPLWI, 28, 4, 12)
BRCMP (MIR_BGT, CMPD, CMPDI (i), 29, 12, 4) BRCMP (MIR_BGTS, CMPW, CMPWI (i), 29, 12, 4)
BRFCMP (MIR_FBGT, 29, 12, 4) BRFCMP (MIR_DBGT, 29, 12, 4)
BRUCMP (MIR_UBGT, CMPLD, CMPLDI, 29, 12, 4) BRUCMP (MIR_UBGTS, CMPLW, CMPLWI, 29, 12, 4)
BRCMP (MIR_BLE, CMPD, CMPDI (i), 29, 4, 12) BRCMP (MIR_BLES, CMPW, CMPWI (i), 29, 4, 12)
BRFCMP (MIR_FBLE, 29, 4, 12) BRFCMP (MIR_DBLE, 29, 4, 12)
BRUCMP (MIR_UBLE, CMPLD, CMPLDI, 29, 4, 12) BRUCMP (MIR_UBLES, CMPLW, CMPLWI, 29, 4, 12)
BRFCMP (MIR_FBEQ, 30, 12, 4) BRFCMP (MIR_DBEQ, 30, 12, 4)
BRCMP (MIR_BNE, CMPD, CMPDI (i), 30, 4, 12) BRCMP (MIR_BNES, CMPW, CMPWI (i), 30, 4, 12)
BRFCMP (MIR_FBNE, 30, 4, 12) BRFCMP (MIR_DBNE, 30, 4, 12)
#define BRUCMP(CODE, CMP, CMPI, BI, COND, NEG_COND) \
{CODE, "l r r", CMP "; " BRC (COND, BI)}, /* cmp 7,ra1,rb2;bcond 7,l; */ \
{CODE, "l r u", CMPI "; " BRC (COND, BI)}, /* cmpi 7,ra1,u;bcond 7,l;:*/ \
{CODE, "L r r", CMP "; " BRCL (NEG_COND, BI)}, /* cmp 7,ra1,rb2;bneg_cond 7,o8;b L;l8:*/ \
{CODE, "L r u", CMPI "; " BRCL (NEG_COND, BI)}, /* cmp 7,ra1,u;bneg_cond 7,o8;b L;l8:*/
BRCMP (MIR_BLT, CMPD, CMPDI (i), 28, 12, 4) BRCMP (MIR_BLTS, CMPW, CMPWI (i), 28, 12, 4)
BRFCMP (MIR_FBLT, 28, 12, 4) BRFCMP (MIR_DBLT, 28, 12, 4)
BRUCMP (MIR_UBLT, CMPLD, CMPLDI, 28, 12, 4) BRUCMP (MIR_UBLTS, CMPLW, CMPLWI, 28, 12,
4)
BRCMP (MIR_BGE, CMPD, CMPDI (i), 28, 4, 12)
BRCMP (MIR_BGES, CMPW, CMPWI (i), 28, 4, 12) BRFCMP (MIR_FBGE, 28, 4, 12)
BRFCMP (MIR_DBGE, 28, 4, 12) BRUCMP (MIR_UBGE, CMPLD, CMPLDI, 28, 4, 12)
BRUCMP (MIR_UBGES, CMPLW, CMPLWI, 28, 4, 12)
BRCMP (MIR_BGT, CMPD, CMPDI (i), 29, 12, 4)
BRCMP (MIR_BGTS, CMPW, CMPWI (i), 29, 12, 4) BRFCMP (MIR_FBGT, 29, 12, 4)
BRFCMP (MIR_DBGT, 29, 12, 4) BRUCMP (MIR_UBGT, CMPLD, CMPLDI, 29, 12, 4)
BRUCMP (MIR_UBGTS, CMPLW, CMPLWI, 29, 12, 4)
BRCMP (MIR_BLE, CMPD, CMPDI (i), 29, 4, 12)
BRCMP (MIR_BLES, CMPW, CMPWI (i), 29, 4, 12)
BRFCMP (MIR_FBLE, 29, 4, 12) BRFCMP (MIR_DBLE, 29, 4, 12)
BRUCMP (MIR_UBLE, CMPLD, CMPLDI, 29, 4, 12)
BRUCMP (MIR_UBLES, CMPLW, CMPLWI, 29, 4, 12)
#define NEG "o31 O104 rt0 ra1"
#define FNEG "o63 O40 rt0 rb1"
{MIR_NEG, "r r", NEG}, /* neg Rt,Ra */
{MIR_NEGS, "r r", NEG}, /* neg Rt,Ra */
{MIR_FNEG, "r r", FNEG}, /* fneg rt,rb */
{MIR_DNEG, "r r", FNEG}, /* fneg rt,rb */
{MIR_NEG, "r r", NEG}, /* neg Rt,Ra */
{MIR_NEGS, "r r", NEG}, /* neg Rt,Ra */
{MIR_FNEG, "r r", FNEG}, /* fneg rt,rb */
{MIR_DNEG, "r r", FNEG}, /* fneg rt,rb */
// ldneg is a builtin
#define SHR(s) "o31 O" #s " ra0 rs1 rb2"
@ -1255,18 +1272,23 @@ static const struct pattern patterns[] = {
{MIR_F2I, "r r", "o63 O815 ht32 rb1; o54 hs32 mt; o58 rt0 mt"},
/* fctidz f0,rb; stfd f0,-16(r1);ld rt,-16(r1): */
{MIR_D2I, "r r", "o63 O815 ht32 rb1; o54 hs32 mt; o58 rt0 mt"},
{MIR_F2D, "r r", "o63 O72 rt0 rb1"}, /* fmr rt,rb */
{MIR_F2D, "r r", "o63 O72 rt0 rb1"}, /* fmr rt,rb */
{MIR_D2F, "r r", "o63 O12 rt0 rb1"}, /* frsp rt,rb */
// i2ld, ui2ld, ld2i, f2ld, d2ld, ld2f, ld2d are builtins
// i2ld, ui2ld, ld2i, f2ld, d2ld, ld2f, ld2d are builtins
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
{MIR_CALL, "X h12 $", "o31 O467 rs1 sr9; o19 O528 BO20 BI0 LK1"}, /* mtctr r12; bcctrl */
{MIR_CALL, "X r $", "o31 O444 ha12 rs1 rb1; o31 O467 rs1 sr9; o19 O528 BO20 BI0 LK1"}, /* mr r12,r; mtctr r; bcctrl */
{MIR_CALL, "X h12 $", "o31 O467 rs1 sr9; o19 O528 BO20 BI0 LK1"}, /* mtctr r12; bcctrl */
{MIR_CALL, "X r $",
"o31 O444 ha12 rs1 rb1; o31 O467 rs1 sr9; o19 O528 BO20 BI0 LK1"}, /* mr r12,r; mtctr r; bcctrl
*/
#else
/* mr r2,r0; ld r0,0(r2); ld r2,8(r2); mtctr r0; bcctrl */
{MIR_CALL, "X h0 $", "o31 O444 ha2 hs0 hb0; o58 ht0 ha2; o58 ht2 ha2 i8; o31 O467 hs0 sr9; o19 O528 BO20 BI0 LK1; o31 O444 ha0 hs0 hb0"},
{MIR_CALL, "X h0 $",
"o31 O444 ha2 hs0 hb0; o58 ht0 ha2; o58 ht2 ha2 i8; o31 O467 hs0 sr9; o19 O528 BO20 BI0 LK1; "
"o31 O444 ha0 hs0 hb0"},
/* ld r0,0(r); ld r2,8(r); mtctr r0; bcctrl */
{MIR_CALL, "X r $", "o58 ht0 ra1; o58 ht2 ra1 i8; o31 O467 hs0 sr9; o19 O528 BO20 BI0 LK1; o31 O444 ha0 hs0 hb0"},
{MIR_CALL, "X r $",
"o58 ht0 ra1; o58 ht2 ra1 i8; o31 O467 hs0 sr9; o19 O528 BO20 BI0 LK1; o31 O444 ha0 hs0 hb0"},
#endif
{MIR_RET, "$", "o19 O16 BO20 BI0"}, /* bclr */
@ -1274,13 +1296,15 @@ static const struct pattern patterns[] = {
#if 0
/* ld r10,16(r1); subf r1,rt,r1; ldx r0,(r1,rt); std r10,16(r1); std r0,0(r1);
std r2,PPC64_TOC_OFFSET(r1); add rt,r1,PPC64_STACK_HEADER_SIZE+PARAM_AREA_SIZE: */
#define ALLOCA_END "o58 ht10 ha1 i16; o31 O40 ht1 ra0 hb1; o31 O21 ht0 ha1 rb0; " \
"o62 hs10 ha1 i16; o62 hs0 ha1;o62 hs2 ha1 at; o14 rt0 ha1 ih"
#define ALLOCA_END \
"o58 ht10 ha1 i16; o31 O40 ht1 ra0 hb1; o31 O21 ht0 ha1 rb0; " \
"o62 hs10 ha1 i16; o62 hs0 ha1;o62 hs2 ha1 at; o14 rt0 ha1 ih"
#else
/* subf r1,rt,r1; ldx r0,(r1,rt); std r0,0(r1);
add rt,r1,PPC64_STACK_HEADER_SIZE+PARAM_AREA_SIZE: */
#define ALLOCA_END "o31 O40 ht1 ra0 hb1; o31 O21 ht0 ha1 rb0; " \
"o62 hs0 ha1; o14 rt0 ha1 ih"
/* subf r1,rt,r1; ldx r0,(r1,rt); std r0,0(r1);
add rt,r1,PPC64_STACK_HEADER_SIZE+PARAM_AREA_SIZE: */
#define ALLOCA_END \
"o31 O40 ht1 ra0 hb1; o31 O21 ht0 ha1 rb0; " \
"o62 hs0 ha1; o14 rt0 ha1 ih"
#endif
/* addi rt,ra,15;rldicr rt,rt,0,59; ... : */
{MIR_ALLOCA, "r r", "o14 rt0 ra1 i15; o30 ra0 rs0 Sh0 Me59; " ALLOCA_END},
@ -1311,7 +1335,8 @@ static void target_get_early_clobbered_hard_regs (MIR_insn_t insn, MIR_reg_t *hr
*hr1 = *hr2 = MIR_NON_HARD_REG;
if (code == MIR_MOD || code == MIR_MODS || code == MIR_UMOD || code == MIR_UMODS) {
*hr1 = R10_HARD_REG;
} else if (code == MIR_I2F || code == MIR_I2D || code == MIR_UI2F || code == MIR_UI2D || code == MIR_F2I || code == MIR_D2I) {
} else if (code == MIR_I2F || code == MIR_I2D || code == MIR_UI2F || code == MIR_UI2D
|| code == MIR_F2I || code == MIR_D2I) {
*hr1 = F0_HARD_REG;
} else if (code == MIR_LDMOV) { /* if mem base reg is R0 */
*hr1 = R10_HARD_REG;
@ -1379,8 +1404,8 @@ static int negative32_p (uint64_t u, uint64_t *n) {
return u == 0;
}
static int pattern_match_p (MIR_context_t ctx, const struct pattern *pat,
MIR_insn_t insn, int use_short_label_p) {
static int pattern_match_p (MIR_context_t ctx, const struct pattern *pat, MIR_insn_t insn,
int use_short_label_p) {
int nop, n;
size_t nops = MIR_insn_nops (ctx, insn);
const char *p;
@ -1401,7 +1426,9 @@ static int pattern_match_p (MIR_context_t ctx, const struct pattern *pat,
if (op.mode != MIR_OP_HARD_REG || op.u.hard_reg == LR_HARD_REG) return FALSE;
break;
case 'R':
if (op.mode != MIR_OP_HARD_REG || op.u.hard_reg == R0_HARD_REG || op.u.hard_reg == LR_HARD_REG) return FALSE;
if (op.mode != MIR_OP_HARD_REG || op.u.hard_reg == R0_HARD_REG
|| op.u.hard_reg == LR_HARD_REG)
return FALSE;
break;
case 'h':
if (op.mode != MIR_OP_HARD_REG) return FALSE;
@ -1419,7 +1446,8 @@ static int pattern_match_p (MIR_context_t ctx, const struct pattern *pat,
case 'm':
case 'M': {
MIR_type_t type, type2, type3 = MIR_T_BOUND;
int ds_p = FALSE, l_p = FALSE, br0_p = FALSE, u_p = TRUE, s_p = TRUE, index_p = start_ch == 'M';
int ds_p = FALSE, l_p = FALSE, br0_p = FALSE, u_p = TRUE, s_p = TRUE,
index_p = start_ch == 'M';
if (op.mode != MIR_OP_HARD_REG_MEM) return FALSE;
ch = *++p;
@ -1448,13 +1476,13 @@ static int pattern_match_p (MIR_context_t ctx, const struct pattern *pat,
break;
case 'l':
ch = *++p;
gen_assert (ch == 'd' && ch != 'M');
gen_assert (ch == 'd' && start_ch != 'M');
ch = *++p;
if (ch != '0')
p--;
else
br0_p = TRUE;
l_p = TRUE;
p--;
else
br0_p = TRUE;
l_p = TRUE;
type = MIR_T_LD;
type2 = MIR_T_BOUND;
break;
@ -1492,11 +1520,11 @@ static int pattern_match_p (MIR_context_t ctx, const struct pattern *pat,
if (ds_p
&& (op.u.hard_reg_mem.index != MIR_NON_HARD_REG || op.u.hard_reg_mem.base == R0_HARD_REG
|| op.u.hard_reg_mem.disp % 4 != 0 || !int16_p (op.u.hard_reg_mem.disp)))
return FALSE;
return FALSE;
if (!ds_p && start_ch == 'm'
&& (op.u.hard_reg_mem.index != MIR_NON_HARD_REG
|| (!br0_p && op.u.hard_reg_mem.base == R0_HARD_REG)
|| (br0_p && op.u.hard_reg_mem.base != R0_HARD_REG)
|| (!br0_p && op.u.hard_reg_mem.base == R0_HARD_REG)
|| (br0_p && op.u.hard_reg_mem.base != R0_HARD_REG)
|| !int16_p (op.u.hard_reg_mem.disp) || l_p && !int16_p (op.u.hard_reg_mem.disp + 8)))
return FALSE;
if (!ds_p && start_ch == 'M'
@ -1511,10 +1539,10 @@ static int pattern_match_p (MIR_context_t ctx, const struct pattern *pat,
if (op.mode != MIR_OP_INT && op.mode != MIR_OP_UINT) return FALSE;
ch = *++p;
if (ch == 'a') {
if (!int16_p ((op.u.i + 15) / 16 * 16)) return FALSE;
if (!int16_p ((op.u.i + 15) / 16 * 16)) return FALSE;
} else {
p--;
if (!int16_p (op.u.i)) return FALSE;
if (!int16_p (op.u.i)) return FALSE;
}
break;
case 'u':
@ -1535,23 +1563,23 @@ static int pattern_match_p (MIR_context_t ctx, const struct pattern *pat,
if (op.mode != MIR_OP_INT && op.mode != MIR_OP_UINT && op.mode != MIR_OP_REF) return FALSE;
if (op.mode != MIR_OP_REF) {
v = op.u.u;
v = op.u.u;
} else if (op.u.ref->item_type == MIR_data_item && op.u.ref->u.data->name != NULL
&& _MIR_reserved_ref_name_p (ctx, op.u.ref->u.data->name)) {
v = (uint64_t) op.u.ref->u.data->u.els;
&& _MIR_reserved_ref_name_p (ctx, op.u.ref->u.data->name)) {
v = (uint64_t) op.u.ref->u.data->u.els;
} else {
v = (uint64_t) op.u.ref->addr;
v = (uint64_t) op.u.ref->addr;
}
if (start_ch == 'x') {
if (!negative32_p (v, &n)) return FALSE;
if (!negative32_p (v, &n)) return FALSE;
} else {
ch = *++p;
if (ch == 's') {
if (start_ch == 'z' ? !uint31_p (v) : !uint47_p (op.u.u)) return FALSE;
} else {
p--;
if (start_ch == 'z' && !uint32_p (v)) return FALSE;
}
ch = *++p;
if (ch == 's') {
if (start_ch == 'z' ? !uint31_p (v) : !uint47_p (op.u.u)) return FALSE;
} else {
p--;
if (start_ch == 'z' && !uint32_p (v)) return FALSE;
}
}
break;
}
@ -1577,7 +1605,7 @@ static int pattern_match_p (MIR_context_t ctx, const struct pattern *pat,
}
static const char *find_insn_pattern_replacement (MIR_context_t ctx, MIR_insn_t insn,
int use_short_label_p) {
int use_short_label_p) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
int i;
const struct pattern *pat;
@ -1649,8 +1677,10 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
MIR_op_t op;
char ch, ch2, start_ch;
uint32_t binsn = 0;
int opcode = -1, opcode2 = -1, opcode3 = -1, opcode4 = -1, rt = -1, rs = -1, ra = -1, rb = -1, rc = -1, spreg = -1, sh = -1, Sh = -1;
int disp = -1, disp4 = -1, mb = -1, me = -1, Mb = -1, Me = -1, bf = -1, BO = -1, BI = -1, imm = -1, LK = -1;
int opcode = -1, opcode2 = -1, opcode3 = -1, opcode4 = -1, rt = -1, rs = -1, ra = -1, rb = -1,
rc = -1, spreg = -1, sh = -1, Sh = -1;
int disp = -1, disp4 = -1, mb = -1, me = -1, Mb = -1, Me = -1, bf = -1, BO = -1, BI = -1,
imm = -1, LK = -1;
int d = -1, lab_off = -1, lb = -1, label_ref_num = -1, n;
uint32_t binsn_mask = 0;
int switch_table_addr_p = FALSE;
@ -1698,7 +1728,7 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
gen_assert (op.mode == MIR_OP_HARD_REG);
reg = op.u.hard_reg + (start_ch == 'n' ? 1 : 0);
}
if (reg > R31_HARD_REG) reg -= F0_HARD_REG;
if (reg > R31_HARD_REG) reg -= F0_HARD_REG;
gen_assert (reg <= 31);
if (ch2 == 't') {
gen_assert (rt < 0);
@ -1747,13 +1777,13 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
if (dec_value (ch2) >= 0) {
Sh = read_dec (&p);
} else if (ch2 == 'r') {
op = insn->ops[2];
op = insn->ops[2];
gen_assert (op.mode == MIR_OP_INT || op.mode == MIR_OP_UINT);
Sh = 64 - op.u.u;
} else {
--p;
op = insn->ops[2];
gen_assert (op.mode == MIR_OP_INT || op.mode == MIR_OP_UINT);
op = insn->ops[2];
gen_assert (op.mode == MIR_OP_INT || op.mode == MIR_OP_UINT);
Sh = op.u.u;
}
break;
@ -1773,10 +1803,10 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
gen_assert (dec_value (ch2) >= 0 && Mb < 0 && Me < 0);
if (b_p) {
Mb = read_dec (&p);
Mb = ((Mb & 0x1f) << 1) | (Mb >> 5) & 1;
Mb = ((Mb & 0x1f) << 1) | (Mb >> 5) & 1;
} else {
Me = read_dec (&p);
Me = ((Me & 0x1f) << 1) | (Me >> 5) & 1;
Me = ((Me & 0x1f) << 1) | (Me >> 5) & 1;
}
} else {
op = insn->ops[0].mode == MIR_OP_HARD_REG_MEM ? insn->ops[0] : insn->ops[1];
@ -1787,7 +1817,7 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
ra = op.u.hard_reg_mem.base;
if (ra == MIR_NON_HARD_REG) ra = R0_HARD_REG;
disp4 = op.u.hard_reg_mem.disp & 0xffff;
gen_assert ((disp4 & 0x3) == 0);
gen_assert ((disp4 & 0x3) == 0);
} else {
--p;
gen_assert (ra < 0 && rb < 0);
@ -1835,10 +1865,10 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
gen_assert (Mb < 0 && Me < 0);
if (b_p) {
Mb = op.u.i;
Mb = ((Mb & 0x1f) << 1) | (Mb >> 5) & 1;
Mb = ((Mb & 0x1f) << 1) | (Mb >> 5) & 1;
} else {
Me = 63 - op.u.i;
Me = ((Me & 0x1f) << 1) | (Me >> 5) & 1;
Me = ((Me & 0x1f) << 1) | (Me >> 5) & 1;
}
} else if (b_p) {
gen_assert (mb < 0);
@ -1857,8 +1887,8 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
ra = op.u.hard_reg_mem.base;
if (ra == MIR_NON_HARD_REG) ra = R0_HARD_REG;
disp4 = op.u.hard_reg_mem.disp & 0xffff;
gen_assert ((disp4 & 0x3) == 0);
} else {
gen_assert ((disp4 & 0x3) == 0);
} else {
if (ch2 != 'n') --p;
gen_assert (ra < 0 && disp < 0);
ra = op.u.hard_reg_mem.base;
@ -1869,29 +1899,29 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
break;
}
case 'd':
ch2 = *++p;
gen_assert (d < 0 && dec_value (ch2) >= 0);
ch2 = *++p;
gen_assert (d < 0 && dec_value (ch2) >= 0);
d = read_dec (&p);
break;
break;
case 'i':
ch2 = *++p;
if (ch2 == 'a') {
op = insn->ops[nops - 1];
gen_assert (op.mode == MIR_OP_INT || op.mode == MIR_OP_UINT);
gen_assert (imm < 0);
imm = (op.u.i + 15) / 16 * 16;
break;
} else if (ch2 == 'h') {
gen_assert (imm < 0);
imm = PPC64_STACK_HEADER_SIZE + param_save_area_size;
break;
} else if (dec_value (ch2) >= 0) {
gen_assert (imm < 0);
imm = read_dec (&p);
break;
}
p--;
/* fall through: */
ch2 = *++p;
if (ch2 == 'a') {
op = insn->ops[nops - 1];
gen_assert (op.mode == MIR_OP_INT || op.mode == MIR_OP_UINT);
gen_assert (imm < 0);
imm = (op.u.i + 15) / 16 * 16;
break;
} else if (ch2 == 'h') {
gen_assert (imm < 0);
imm = PPC64_STACK_HEADER_SIZE + param_save_area_size;
break;
} else if (dec_value (ch2) >= 0) {
gen_assert (imm < 0);
imm = read_dec (&p);
break;
}
p--;
/* fall through: */
case 'u':
case 'I':
case 'U':
@ -1902,30 +1932,30 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
break;
case 'x':
case 'z': {
int ok_p;
uint64_t v, n;
int ok_p;
uint64_t v, n;
op = insn->ops[nops - 1];
gen_assert (op.mode == MIR_OP_INT || op.mode == MIR_OP_UINT || op.mode == MIR_OP_REF);
if (op.mode != MIR_OP_REF) {
v = op.u.u;
} else if (op.u.ref->item_type == MIR_data_item && op.u.ref->u.data->name != NULL
if (op.mode != MIR_OP_REF) {
v = op.u.u;
} else if (op.u.ref->item_type == MIR_data_item && op.u.ref->u.data->name != NULL
&& _MIR_reserved_ref_name_p (ctx, op.u.ref->u.data->name)) {
v = (uint64_t) op.u.ref->u.data->u.els;
} else {
v = (uint64_t) op.u.ref->addr;
}
if (start_ch == 'x') {
ok_p = negative32_p (v, &n);
n = 32 - n;
gen_assert (Mb < 0 && ok_p);
Mb = ((n & 0x1f) << 1) | (n >> 5) & 1;
} else {
gen_assert (imm < 0);
n = dec_value (*++p);
gen_assert (n >= 0 && n <= 3);
imm = (v >> (3 - n) * 16) & 0xffff;
}
if (start_ch == 'x') {
ok_p = negative32_p (v, &n);
n = 32 - n;
gen_assert (Mb < 0 && ok_p);
Mb = ((n & 0x1f) << 1) | (n >> 5) & 1;
} else {
gen_assert (imm < 0);
n = dec_value (*++p);
gen_assert (n >= 0 && n <= 3);
imm = (v >> (3 - n) * 16) & 0xffff;
}
break;
}
case 'b':
@ -1933,9 +1963,9 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
gen_assert (ch2 == 'f');
ch2 = *++p;
gen_assert (dec_value (ch2) >= 0);
gen_assert (bf < 0);
bf = read_dec (&p);
break;
gen_assert (bf < 0);
bf = read_dec (&p);
break;
case 'B': {
int o_p;
@ -1955,16 +1985,16 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
}
case 'l': {
ch2 = *++p;
if ((n = dec_value (ch2)) >= 0) {
if ((n = dec_value (ch2)) >= 0) {
gen_assert (lab_off < 0 && (n & 0x3) == 0);
lab_off = n;
} else {
--p;
gen_assert (insn->code != MIR_CALL);
gen_assert (insn->code != MIR_CALL);
op = insn->ops[0];
gen_assert (op.mode == MIR_OP_LABEL);
lr.abs_addr_p = FALSE;
lr.short_addr_p = TRUE;
lr.short_addr_p = TRUE;
lr.label_val_disp = 0;
lr.label = op.u.label;
label_ref_num = VARR_LENGTH (label_ref_t, label_refs);
@ -1975,8 +2005,8 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
case 'L': {
ch2 = *++p;
if (ch2 == 'K') {
ch2 = *++p;
gen_assert (LK < 0 && dec_value (ch2) >= 0);
ch2 = *++p;
gen_assert (LK < 0 && dec_value (ch2) >= 0);
LK = read_dec (&p);
gen_assert (LK <= 1);
} else if ((n = dec_value (ch2)) >= 0) {
@ -1995,10 +2025,10 @@ static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacemen
break;
}
case 'a':
gen_assert (imm < 0);
ch2 = *++p;
gen_assert (ch2 == 't' || ch2 == 'a');
imm = ch2 == 't' ? PPC64_TOC_OFFSET : 15 + PPC64_STACK_HEADER_SIZE + param_save_area_size;
gen_assert (imm < 0);
ch2 = *++p;
gen_assert (ch2 == 't' || ch2 == 'a');
imm = ch2 == 't' ? PPC64_TOC_OFFSET : 15 + PPC64_STACK_HEADER_SIZE + param_save_area_size;
break;
case 'T':
gen_assert (!switch_table_addr_p && switch_table_addr_insn_start < 0);
@ -2187,82 +2217,83 @@ static uint8_t *target_translate (MIR_context_t ctx, size_t *len) {
VARR_TRUNC (uint64_t, abs_address_locs, 0);
short_label_disp_fail_p = FALSE;
for (insn = DLIST_HEAD (MIR_insn_t, curr_func_item->u.func->insns); insn != NULL;
insn = DLIST_NEXT (MIR_insn_t, insn)) {
insn = DLIST_NEXT (MIR_insn_t, insn)) {
MIR_insn_code_t code = insn->code;
if ((code == MIR_RSH || code == MIR_LSH || code == MIR_URSH
|| code == MIR_RSHS || code == MIR_LSHS || code == MIR_URSHS)
&& (insn->ops[2].mode == MIR_OP_INT || insn->ops[2].mode == MIR_OP_UINT)) {
if (insn->ops[2].u.i == 0) {
gen_mov (ctx, insn, MIR_MOV, insn->ops[0], insn->ops[1]);
old_insn = insn;
insn = DLIST_NEXT (MIR_insn_t, insn);
gen_delete_insn (ctx, old_insn);
} else {
if (insn->ops[2].mode == MIR_OP_INT && insn->ops[2].u.i < 0) {
switch (code) {
case MIR_RSH: insn->code = MIR_LSH; break;
case MIR_URSH: insn->code = MIR_LSH; break;
case MIR_LSH: insn->code = MIR_RSH; break;
case MIR_RSHS: insn->code = MIR_LSHS; break;
case MIR_URSHS: insn->code = MIR_LSHS; break;
case MIR_LSHS: insn->code = MIR_RSHS; break;
}
insn->ops[2].u.i = -insn->ops[2].u.i;
}
if (code == MIR_RSH || code == MIR_LSH || code == MIR_URSH) {
if (insn->ops[2].u.i > 64) insn->ops[2].u.i = 64;
} else if (insn->ops[2].u.i > 32) {
insn->ops[2].u.i = 32;
}
}
if ((code == MIR_RSH || code == MIR_LSH || code == MIR_URSH || code == MIR_RSHS
|| code == MIR_LSHS || code == MIR_URSHS)
&& (insn->ops[2].mode == MIR_OP_INT || insn->ops[2].mode == MIR_OP_UINT)) {
if (insn->ops[2].u.i == 0) {
gen_mov (ctx, insn, MIR_MOV, insn->ops[0], insn->ops[1]);
old_insn = insn;
insn = DLIST_NEXT (MIR_insn_t, insn);
gen_delete_insn (ctx, old_insn);
} else {
if (insn->ops[2].mode == MIR_OP_INT && insn->ops[2].u.i < 0) {
switch (code) {
case MIR_RSH: insn->code = MIR_LSH; break;
case MIR_URSH: insn->code = MIR_LSH; break;
case MIR_LSH: insn->code = MIR_RSH; break;
case MIR_RSHS: insn->code = MIR_LSHS; break;
case MIR_URSHS: insn->code = MIR_LSHS; break;
case MIR_LSHS: insn->code = MIR_RSHS; break;
}
insn->ops[2].u.i = -insn->ops[2].u.i;
}
if (code == MIR_RSH || code == MIR_LSH || code == MIR_URSH) {
if (insn->ops[2].u.i > 64) insn->ops[2].u.i = 64;
} else if (insn->ops[2].u.i > 32) {
insn->ops[2].u.i = 32;
}
}
}
if (insn->code == MIR_LABEL) {
set_label_disp (insn, VARR_LENGTH (uint8_t, result_code));
set_label_disp (insn, VARR_LENGTH (uint8_t, result_code));
} else {
int use_short_label_p = TRUE;
if (n_iter > 0 && MIR_branch_code_p (code)) {
MIR_label_t label = insn->ops[0].u.label;
int64_t offset = (int64_t) get_label_disp (label) - (int64_t) VARR_LENGTH (uint8_t, result_code);
use_short_label_p = ((offset < 0 ? -offset : offset) & ~(int64_t) 0x7fff) == 0;
}
replacement = find_insn_pattern_replacement (ctx, insn, use_short_label_p);
if (replacement == NULL) {
fprintf (stderr, "fatal failure in matching insn:");
MIR_output_insn (ctx, stderr, insn, curr_func_item->u.func, TRUE);
exit (1);
} else {
gen_assert (replacement != NULL);
out_insn (ctx, insn, replacement);
}
int use_short_label_p = TRUE;
if (n_iter > 0 && MIR_branch_code_p (code)) {
MIR_label_t label = insn->ops[0].u.label;
int64_t offset
= (int64_t) get_label_disp (label) - (int64_t) VARR_LENGTH (uint8_t, result_code);
use_short_label_p = ((offset < 0 ? -offset : offset) & ~(int64_t) 0x7fff) == 0;
}
replacement = find_insn_pattern_replacement (ctx, insn, use_short_label_p);
if (replacement == NULL) {
fprintf (stderr, "fatal failure in matching insn:");
MIR_output_insn (ctx, stderr, insn, curr_func_item->u.func, TRUE);
exit (1);
} else {
gen_assert (replacement != NULL);
out_insn (ctx, insn, replacement);
}
}
}
/* Setting up labels */
for (i = 0; i < VARR_LENGTH (label_ref_t, label_refs); i++) {
label_ref_t lr = VARR_GET (label_ref_t, label_refs, i);
if (lr.abs_addr_p) {
set_int64 (&VARR_ADDR (uint8_t, result_code)[lr.label_val_disp],
(int64_t) get_label_disp (lr.label));
VARR_PUSH (uint64_t, abs_address_locs, lr.label_val_disp);
set_int64 (&VARR_ADDR (uint8_t, result_code)[lr.label_val_disp],
(int64_t) get_label_disp (lr.label));
VARR_PUSH (uint64_t, abs_address_locs, lr.label_val_disp);
} else if (lr.short_addr_p) { /* 14-bit relative addressing */
int64_t offset = (int64_t) get_label_disp (lr.label) - (int64_t) lr.label_val_disp;
gen_assert ((offset & 0x3) == 0);
if (((offset < 0 ? -offset : offset) & ~(int64_t) 0x7fff) != 0) {
short_label_disp_fail_p = TRUE;
} else {
*(uint32_t *) (VARR_ADDR (uint8_t, result_code) + lr.label_val_disp)
|= ((offset / 4) & 0x3fff) << 2;
}
int64_t offset = (int64_t) get_label_disp (lr.label) - (int64_t) lr.label_val_disp;
gen_assert ((offset & 0x3) == 0);
if (((offset < 0 ? -offset : offset) & ~(int64_t) 0x7fff) != 0) {
short_label_disp_fail_p = TRUE;
} else {
*(uint32_t *) (VARR_ADDR (uint8_t, result_code) + lr.label_val_disp)
|= ((offset / 4) & 0x3fff) << 2;
}
} else { /* 24-bit relative address */
int64_t offset = (int64_t) get_label_disp (lr.label) - (int64_t) lr.label_val_disp;
gen_assert ((offset & 0x3) == 0
&& ((offset < 0 ? -offset : offset) & ~(int64_t) 0x1ffffff) == 0);
*(uint32_t *) (VARR_ADDR (uint8_t, result_code) + lr.label_val_disp)
|= ((offset / 4) & 0xffffff) << 2;
int64_t offset = (int64_t) get_label_disp (lr.label) - (int64_t) lr.label_val_disp;
gen_assert ((offset & 0x3) == 0
&& ((offset < 0 ? -offset : offset) & ~(int64_t) 0x1ffffff) == 0);
*(uint32_t *) (VARR_ADDR (uint8_t, result_code) + lr.label_val_disp)
|= ((offset / 4) & 0xffffff) << 2;
}
}
n_iter++;

File diff suppressed because it is too large Load Diff

@ -22,6 +22,8 @@ static int target_locs_num (MIR_reg_t loc, MIR_type_t type) {
return loc > MAX_HARD_REG && type == MIR_T_LD ? 2 : 1;
}
static inline MIR_reg_t target_nth_loc (MIR_reg_t loc, MIR_type_t type, int n) { return loc + n; }
/* Hard regs not used in machinized code, preferably call used ones. */
const MIR_reg_t TEMP_INT_HARD_REG1 = R10_HARD_REG, TEMP_INT_HARD_REG2 = R11_HARD_REG;
const MIR_reg_t TEMP_FLOAT_HARD_REG1 = XMM8_HARD_REG, TEMP_FLOAT_HARD_REG2 = XMM9_HARD_REG;
@ -693,7 +695,7 @@ static void target_machinize (MIR_context_t ctx) {
|| code == MIR_LE || code == MIR_ULE || code == MIR_GT || code == MIR_UGT
|| code == MIR_GE || code == MIR_UGE || code == MIR_EQS || code == MIR_NES
|| code == MIR_LTS || code == MIR_ULTS || code == MIR_LES || code == MIR_ULES
|| code == MIR_GTS || code == MIR_UGT || code == MIR_GES || code == MIR_UGES
|| code == MIR_GTS || code == MIR_UGTS || code == MIR_GES || code == MIR_UGES
|| code == MIR_FEQ || code == MIR_FNE || code == MIR_FLT || code == MIR_FLE
|| code == MIR_FGT || code == MIR_FGE || code == MIR_DEQ || code == MIR_DNE
|| code == MIR_DLT || code == MIR_DLE || code == MIR_DGT || code == MIR_DGE) {

@ -172,12 +172,14 @@ static inline struct gen_ctx **gen_ctx_loc (MIR_context_t ctx) { return (struct
#define max_int_hard_regs gen_ctx->max_int_hard_regs
#define max_fp_hard_regs gen_ctx->max_fp_hard_regs
#ifdef __x86_64__
#if defined(__x86_64__)
#include "mir-gen-x86_64.c"
#elif defined(__aarch64__)
#include "mir-gen-aarch64.c"
#elif defined(__PPC64__)
#include "mir-gen-ppc64.c"
#elif defined(__s390x__)
#include "mir-gen-s390x.c"
#else
#error "undefined or unsupported generation target"
#endif
@ -4302,7 +4304,7 @@ struct ra_ctx {
size_t curr_age;
/* Slots num for variables. Some variable can take several slots. */
size_t func_stack_slots_num;
bitmap_t func_assigned_hard_regs;
bitmap_t func_used_hard_regs;
};
#define breg_renumber gen_ctx->ra_ctx->breg_renumber
@ -4314,7 +4316,7 @@ struct ra_ctx {
#define loc_profit_ages gen_ctx->ra_ctx->loc_profit_ages
#define curr_age gen_ctx->ra_ctx->curr_age
#define func_stack_slots_num gen_ctx->ra_ctx->func_stack_slots_num
#define func_assigned_hard_regs gen_ctx->ra_ctx->func_assigned_hard_regs
#define func_used_hard_regs gen_ctx->ra_ctx->func_used_hard_regs
static void process_move_to_form_thread (MIR_context_t ctx, mv_t mv) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
@ -4385,9 +4387,19 @@ static void setup_loc_profits (MIR_context_t ctx, MIR_reg_t breg) {
setup_loc_profit_from_op (ctx, mv->bb_insn->insn->ops[1], mv->freq);
}
static void setup_used_hard_regs (MIR_context_t ctx, MIR_type_t type, MIR_reg_t hard_reg) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
MIR_reg_t curr_hard_reg;
int i, slots_num = target_locs_num (hard_reg, type);
for (i = 0; i < slots_num; i++)
if ((curr_hard_reg = target_nth_loc (hard_reg, type, i)) <= MAX_HARD_REG)
bitmap_set_bit_p (func_used_hard_regs, curr_hard_reg);
}
static void assign (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
MIR_reg_t loc, best_loc, i, reg, breg, var, nregs = get_nregs (ctx);
MIR_reg_t loc, curr_loc, best_loc, i, reg, breg, var, nregs = get_nregs (ctx);
MIR_type_t type;
int slots_num;
int j, k;
@ -4437,7 +4449,7 @@ static void assign (MIR_context_t ctx) {
for (lr = VARR_GET (live_range_t, var_live_ranges, i); lr != NULL; lr = lr->next)
for (j = lr->start; j <= lr->finish; j++) bitmap_set_bit_p (point_used_locs_addr[j], i);
}
bitmap_clear (func_assigned_hard_regs);
bitmap_clear (func_used_hard_regs);
for (i = 0; i < nregs; i++) { /* hard reg and stack slot assignment */
breg = VARR_GET (breg_info_t, sorted_bregs, i).breg;
if (VARR_GET (MIR_reg_t, breg_renumber, breg) != MIR_NON_HARD_REG) continue;
@ -4455,13 +4467,16 @@ static void assign (MIR_context_t ctx) {
for (loc = 0; loc <= func_stack_slots_num + MAX_HARD_REG; loc++) {
if (loc <= MAX_HARD_REG && !target_hard_reg_type_ok_p (loc, type)) continue;
slots_num = target_locs_num (loc, type);
if (loc + slots_num - 1 > func_stack_slots_num + MAX_HARD_REG) break;
for (k = 0; k < slots_num; k++)
if ((loc + k <= MAX_HARD_REG
&& (target_fixed_hard_reg_p (loc + k)
|| (target_call_used_hard_reg_p (loc + k) && curr_breg_infos[breg].calls_num > 0)))
|| bitmap_bit_p (conflict_locs, loc + k))
if (target_nth_loc (loc, type, slots_num - 1) > func_stack_slots_num + MAX_HARD_REG) break;
for (k = 0; k < slots_num; k++) {
curr_loc = target_nth_loc (loc, type, k);
if ((curr_loc <= MAX_HARD_REG
&& (target_fixed_hard_reg_p (curr_loc)
|| (target_call_used_hard_reg_p (curr_loc)
&& curr_breg_infos[breg].calls_num > 0)))
|| bitmap_bit_p (conflict_locs, curr_loc))
break;
}
if (k < slots_num) continue;
if (loc > MAX_HARD_REG && (loc - MAX_HARD_REG - 1) % slots_num != 0)
continue; /* we align stack slots according to the type size */
@ -4476,7 +4491,7 @@ static void assign (MIR_context_t ctx) {
}
slots_num = target_locs_num (best_loc, type);
if (best_loc <= MAX_HARD_REG) {
for (k = 0; k < slots_num; k++) bitmap_set_bit_p (func_assigned_hard_regs, best_loc + k);
setup_used_hard_regs (ctx, type, best_loc);
} else if (best_loc == MIR_NON_HARD_REG) { /* Add stack slot ??? */
for (k = 0; k < slots_num; k++) {
if (k == 0) best_loc = VARR_LENGTH (size_t, loc_profits);
@ -4499,9 +4514,11 @@ static void assign (MIR_context_t ctx) {
}
#endif
VARR_SET (MIR_reg_t, breg_renumber, breg, best_loc);
slots_num = target_locs_num (best_loc, type);
for (lr = VARR_GET (live_range_t, var_live_ranges, var); lr != NULL; lr = lr->next)
for (j = lr->start; j <= lr->finish; j++)
for (k = 0; k < slots_num; k++) bitmap_set_bit_p (point_used_locs_addr[j], best_loc + k);
for (k = 0; k < slots_num; k++)
bitmap_set_bit_p (point_used_locs_addr[j], target_nth_loc (best_loc, type, k));
}
for (i = 0; i <= curr_point; i++) bitmap_destroy (VARR_POP (bitmap_t, point_used_locs));
#if !MIR_NO_GEN_DEBUG
@ -4551,6 +4568,7 @@ static MIR_reg_t change_reg (MIR_context_t ctx, MIR_op_t *mem_op, MIR_reg_t reg,
code = MIR_LDMOV;
hard_reg = first_p ? TEMP_LDOUBLE_HARD_REG1 : TEMP_LDOUBLE_HARD_REG2;
}
setup_used_hard_regs (ctx, type, hard_reg);
offset = target_get_stack_slot_offset (ctx, type, loc - MAX_HARD_REG - 1);
*mem_op = _MIR_new_hard_reg_mem_op (ctx, type, offset, FP_HARD_REG, MIR_NON_HARD_REG, 0);
if (hard_reg == MIR_NON_HARD_REG) return hard_reg;
@ -4602,6 +4620,13 @@ static void rewrite (MIR_context_t ctx) {
in_op = *op;
#endif
switch (op->mode) {
case MIR_OP_HARD_REG: bitmap_set_bit_p (func_used_hard_regs, op->u.hard_reg); break;
case MIR_OP_HARD_REG_MEM:
if (op->u.hard_reg_mem.base != MIR_NON_HARD_REG)
bitmap_set_bit_p (func_used_hard_regs, op->u.hard_reg_mem.base);
if (op->u.hard_reg_mem.index != MIR_NON_HARD_REG)
bitmap_set_bit_p (func_used_hard_regs, op->u.hard_reg_mem.index);
break;
case MIR_OP_REG:
hard_reg
= change_reg (ctx, &mem_op, op->u.reg, data_mode, out_p || first_in_p, bb_insn, out_p);
@ -4673,7 +4698,7 @@ static void init_ra (MIR_context_t ctx) {
VARR_CREATE (size_t, loc_profits, 0);
VARR_CREATE (size_t, loc_profit_ages, 0);
conflict_locs = bitmap_create2 (3 * MAX_HARD_REG / 2);
func_assigned_hard_regs = bitmap_create2 (MAX_HARD_REG + 1);
func_used_hard_regs = bitmap_create2 (MAX_HARD_REG + 1);
}
static void finish_ra (MIR_context_t ctx) {
@ -4685,7 +4710,7 @@ static void finish_ra (MIR_context_t ctx) {
VARR_DESTROY (size_t, loc_profits);
VARR_DESTROY (size_t, loc_profit_ages);
bitmap_destroy (conflict_locs);
bitmap_destroy (func_assigned_hard_regs);
bitmap_destroy (func_used_hard_regs);
free (gen_ctx->ra_ctx);
gen_ctx->ra_ctx = NULL;
}
@ -5636,7 +5661,7 @@ void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
#endif
}
#endif /* #ifndef NO_COMBINE */
target_make_prolog_epilog (ctx, func_assigned_hard_regs, func_stack_slots_num);
target_make_prolog_epilog (ctx, func_used_hard_regs, func_stack_slots_num);
#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, "+++++++++++++MIR after forming prolog/epilog:\n");

@ -0,0 +1,392 @@
/* This file is a part of MIR project.
Copyright (C) 2018-2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* Long doubles (-mlong-double=128) are always passed by its address (for args and results) */
#if 0 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#error "s390x works only in BE mode"
#endif
#define VA_LIST_IS_ARRAY_P 1 /* one element array of struct s390x_va_list */
#define S390X_STACK_HEADER_SIZE 160
static void push_insns (MIR_context_t ctx, const uint8_t *pat, size_t pat_len) {
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, machine_insns, pat[i]);
}
static void s390x_gen_mov (MIR_context_t ctx, unsigned to, unsigned from) {
uint32_t lgr = (0xb904 << 16) | (to << 4) | from; /* lgr to,from: */
assert (to < 16 && from < 16);
push_insns (ctx, (uint8_t *) &lgr, 4);
}
static void s390x_gen_mvi (MIR_context_t ctx, int val, unsigned base, int disp) {
uint64_t mvghi /* mvghi disp(base), val: */
= ((0xe548l << 32) | ((uint64_t) base << 28) | ((disp & 0xfff) << 16) | (val & 0xffff)) << 16;
assert (base < 16 && 0 <= disp && disp < (1 << 12) && -(1 << 15) < val && val < (1 << 15));
push_insns (ctx, (uint8_t *) &mvghi, 6);
}
static void s390x_gen_ld_st (MIR_context_t ctx, unsigned reg, unsigned base, int disp,
MIR_type_t type, int ld_p) {
int single_p = type == MIR_T_F;
int double_p = type == MIR_T_D;
uint64_t dl = disp & 0xfff, dh = (disp >> 12) & 0xff;
uint64_t common = ((uint64_t) reg << 36) | ((uint64_t) base << 28) | (dl << 16) | (dh << 8);
uint64_t lgopcode
= (type == MIR_T_I8
? (ld_p ? 0x77 : 0x72)
: type == MIR_T_U8 ? (ld_p ? 0x90 : 0x72)
: type == MIR_T_I16
? (ld_p ? 0x78 : 0x70)
: type == MIR_T_U16
? (ld_p ? 0x91 : 0x70)
: type == MIR_T_I32 ? (ld_p ? 0x14 : 0x50)
: type == MIR_T_U32 ? (ld_p ? 0x16 : 0x50)
: (ld_p ? 0x04 : 0x24));
uint64_t g = ((0xe3l << 40) | common | lgopcode) << 16;
uint64_t ey = ((0xedl << 40) | common | (ld_p ? 0x64 : 0x66)) << 16;
uint64_t dy = ((0xedl << 40) | common | (ld_p ? 0x65 : 0x67)) << 16;
/* (lg|lgf|llgf|lgb|llgc|lhy|llgh|ley|ldy|stg|sty|sthy|stcy|stey|stdy) reg, disp(base): */
assert (type != MIR_T_LD && reg < 16 && base < 16 && -(1 << 19) < disp && disp < (1 << 19));
push_insns (ctx, (uint8_t *) (single_p ? &ey : double_p ? &dy : &g), 6);
}
static void s390x_gen_ld (MIR_context_t ctx, unsigned to, unsigned base, int disp,
MIR_type_t type) {
s390x_gen_ld_st (ctx, to, base, disp, type, TRUE);
}
static void s390x_gen_st (MIR_context_t ctx, unsigned from, unsigned base, int disp,
MIR_type_t type) {
s390x_gen_ld_st (ctx, from, base, disp, type, FALSE);
}
static void s390x_gen_ldstm (MIR_context_t ctx, unsigned from, unsigned to, unsigned base, int disp,
int ld_p) {
uint64_t dl = disp & 0xfff, dh = (disp >> 12) & 0xff;
uint64_t common = ((uint64_t) from << 36) | ((uint64_t) to << 32) | ((uint64_t) base << 28)
| (dl << 16) | (dh << 8);
uint64_t g = ((0xebl << 40) | common | (ld_p ? 0x4 : 0x24)) << 16;
/* (lmg|stmg) from,to,disp(base): */
assert (from < 16 && to < 16 && base < 16 && -(1 << 19) < disp && disp < (1 << 19));
push_insns (ctx, (uint8_t *) &g, 6);
}
static void s390x_gen_jump (MIR_context_t ctx, unsigned int reg, int call_p) {
uint16_t bcr = (0x7 << 8) | (15 << 4) | reg; /* bcr 15,reg: */
uint16_t balr = (0x5 << 8) | (14 << 4) | reg; /* balr 14,reg: */
assert (reg < 16);
push_insns (ctx, (uint8_t *) (call_p ? &balr : &bcr), 2);
}
static void s390x_gen_addi (MIR_context_t ctx, unsigned dst, unsigned src, int disp) {
uint64_t dl = disp & 0xfff, dh = (disp >> 12) & 0xff;
uint64_t ops = ((uint64_t) dst << 36) | ((uint64_t) src << 28) | (dl << 16) | (dh << 8);
uint64_t lay = ((0xe3l << 40) | ops | 0x71) << 16; /* lay dst,disp(src) */
assert (dst < 16 && src < 16 && -(1 << 19) < disp && disp < (1 << 19));
push_insns (ctx, (uint8_t *) &lay, 6);
}
static void s390x_gen_3addrs (MIR_context_t ctx, unsigned int r1, void *a1, unsigned int r2,
void *a2, unsigned int r3, void *a3) {
/* 6b:lalr r3,22+align;6b:lg r1,0(r3);6b:lg r2,8(r3);6b:lg r3,16(r3);4b:bc m15,28;align;a1-a3 */
size_t rem = (VARR_LENGTH (uint8_t, machine_insns) + 28) % 8;
size_t padding = rem == 0 ? 0 : 8 - rem;
uint64_t lalr = ((0xc0l << 40) | ((uint64_t) r1 << 36) | (28 + padding) / 2) << 16;
uint32_t brc = (0xa7 << 24) | (15 << 20) | (4 << 16) | (28 + padding) / 2; /* brc m15,28: */
assert (r1 != 0);
push_insns (ctx, (uint8_t *) &lalr, 6);
s390x_gen_ld (ctx, r3, r1, 16, MIR_T_I64); /* lg r3,16(r1) */
s390x_gen_ld (ctx, r2, r1, 8, MIR_T_I64); /* lg r2,8(r1) */
s390x_gen_ld (ctx, r1, r1, 0, MIR_T_I64); /* lg r1,0(r1) */
push_insns (ctx, (uint8_t *) &brc, 4);
for (size_t i = 0; i < padding; i++) VARR_PUSH (uint8_t, machine_insns, 0);
push_insns (ctx, (uint8_t *) &a1, 8);
push_insns (ctx, (uint8_t *) &a2, 8);
push_insns (ctx, (uint8_t *) &a3, 8);
}
void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
VARR_TRUNC (uint8_t, machine_insns, 0);
s390x_gen_mov (ctx, 2, 15); /* lgr r2,15 */
s390x_gen_jump (ctx, 14, FALSE); /* bcr m15,r14 */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}
void *_MIR_get_bend_builtin (MIR_context_t ctx) {
VARR_TRUNC (uint8_t, machine_insns, 0);
s390x_gen_ld (ctx, 0, 15, 0, MIR_T_I64); /* r0 = 0(r15) */
s390x_gen_st (ctx, 0, 2, 0, MIR_T_I64); /* 0(r2) = r0 */
s390x_gen_mov (ctx, 15, 2); /* lgr r15,2 */
s390x_gen_jump (ctx, 14, FALSE); /* bcr m15,r14 */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}
void *_MIR_get_thunk (MIR_context_t ctx) {
const int max_thunk_len = (4 * 8); /* see _MIR_redirect_thunk */
VARR_TRUNC (uint8_t, machine_insns, 0);
for (int i = 0; i < max_thunk_len; i++) VARR_PUSH (uint8_t, machine_insns, 0);
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}
void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
int64_t offset = (uint8_t *) to - (uint8_t *) thunk;
VARR_TRUNC (uint8_t, machine_insns, 0);
assert (offset % 2 == 0);
offset /= 2;
if (-(1l << 31) < offset && offset < (1l << 31)) { /* brcl m15,offset: */
uint64_t brcl = ((0xc0l << 40) | (15l << 36) | (4l << 32) | offset & 0xffffffff) << 16;
push_insns (ctx, (uint8_t *) &brcl, 6);
} else { /* 6b:lalr r1,8+padding; 6b:lg r1,0(r1); 2b:bcr m15,r1;padding; 64-bit address: */
size_t rem = (VARR_LENGTH (uint8_t, machine_insns) + 14) % 8;
size_t padding = rem == 0 ? 0 : 8 - rem;
uint64_t lalr = ((0xc0l << 40) | (1l << 36) | (14 + padding) / 2) << 16;
uint64_t lg = ((0xe3l << 40) | (1l << 36) | (1l << 28) | 0x4) << 16;
uint16_t bcr = (0x7 << 8) | (15 << 4) | 1; /* bcr 15,r1: */
push_insns (ctx, (uint8_t *) &lalr, 6);
push_insns (ctx, (uint8_t *) &lg, 6);
push_insns (ctx, (uint8_t *) &bcr, 2);
for (size_t i = 0; i < padding; i++) VARR_PUSH (uint8_t, machine_insns, 0);
push_insns (ctx, (uint8_t *) &to, 8);
}
_MIR_change_code (ctx, thunk, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}
struct s390x_va_list {
long __gpr, __fpr; /* number of args read until now */
void *__overflow_arg_area; /* argument on the stack to read next */
void *__reg_save_area; /* curr func frame start */
};
void *va_arg_builtin (void *p, uint64_t t) {
struct s390x_va_list *va = p;
MIR_type_t type = t;
int fp_p = type == MIR_T_F || type == MIR_T_D;
void *a;
if (!fp_p) {
if (va->__gpr < 5) {
a = (char *) va->__reg_save_area + 16 + 8 * va->__gpr;
} else {
a = va->__overflow_arg_area;
va->__overflow_arg_area = (char *) va->__overflow_arg_area + 8;
}
va->__gpr++;
if (type == MIR_T_LD) a = *(void **) a; /* always passed by address */
} else {
if (va->__fpr < 4) {
a = (char *) va->__reg_save_area + 128 + 8 * va->__fpr;
} else {
a = va->__overflow_arg_area;
va->__overflow_arg_area = (char *) va->__overflow_arg_area + 8;
}
va->__fpr++;
}
if (type == MIR_T_F || type == MIR_T_I32) a = (char *) a + 4; /* 2nd word of doubleword */
return a;
}
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
struct s390x_va_list *va = p;
va_list *vap = a;
assert (sizeof (struct s390x_va_list) == sizeof (va_list));
*va = *(struct s390x_va_list *) vap;
}
void va_end_interp_builtin (MIR_context_t ctx, void *p) {}
/* Generation: fun (fun_addr, res_arg_addresses):
save r6, r7, r14 (r15 + 48,112);
allocate and stack frame (S390X_STACK_HEADER_SIZE + param area size + ld arg values size);
r1=r2 (fun_addr);
r7=r3 (res_arg_addresses);
(arg_reg=mem[r7,arg_offset] or (f1,r0)=mem[r7,arg_offset];mem[r15,S390X_STACK_HEADER_SIZE+offset]=(f1,r0)) ...
call *r1;
r0=mem[r7,<res_offset>]; res_reg=mem[r0]; ...
restore r15; restore r6, r7, r14; return. */
void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
MIR_type_t *arg_types, int vararg_p) {
MIR_type_t type;
int n_gpregs = 0, n_fpregs = 0, res_reg = 7, frame_size, disp, param_offset, param_size = 0;
VARR_TRUNC (uint8_t, machine_insns, 0);
frame_size = S390X_STACK_HEADER_SIZE;
if (nres > 0 && res_types[0] == MIR_T_LD) n_gpregs++; /* ld address */
for (uint32_t i = 0; i < nargs; i++) { /* calculate param area size: */
type = arg_types[i];
if (type == MIR_T_LD) frame_size += 16; /* address for ld value */
if ((type == MIR_T_F || type == MIR_T_D) && n_fpregs < 4) {
n_fpregs++;
} else if (type != MIR_T_F && type != MIR_T_D && n_gpregs < 5) {
n_gpregs++;
} else {
frame_size += 8;
param_size += 8;
}
}
s390x_gen_ldstm (ctx, 6, 7, 15, 48, FALSE); /* stmg 6,7,48(r15) : */
s390x_gen_st (ctx, 14, 15, 112, MIR_T_I64); /* stg r14,112(r15) */
s390x_gen_addi (ctx, 15, 15, -frame_size); /* lay r15,-frame_size(r15) */
s390x_gen_mov (ctx, 1, 2); /* fun_addr */
s390x_gen_mov (ctx, res_reg, 3); /* results & args */
n_gpregs = n_fpregs = 0;
param_offset = nres * 16; /* args start */
disp = S390X_STACK_HEADER_SIZE; /* param area start */
if (nres > 0 && res_types[0] == MIR_T_LD) { /* ld address: */
s390x_gen_mov (ctx, 2, res_reg); /* lgr r2,r7 */
n_gpregs++;
}
for (uint32_t i = 0; i < nargs; i++) { /* load args: */
type = arg_types[i];
if ((type == MIR_T_F || type == MIR_T_D) && n_fpregs < 4) {
/* (le,ld) (f0,f2,f4,f6),param_ofset(r7) */
s390x_gen_ld (ctx, n_fpregs * 2, res_reg, param_offset, type);
n_fpregs++;
} else if (type == MIR_T_F || type == MIR_T_D) {
s390x_gen_ld (ctx, 1, res_reg, param_offset, type); /* (le,ld) f1,param_offset(r7) */
s390x_gen_st (ctx, 1, 15, disp, type); /* (ste,std) f1,disp(r15) */
disp += 8;
} else if (type == MIR_T_LD && n_gpregs < 5) { /* ld address */
s390x_gen_addi (ctx, n_gpregs + 2, res_reg, param_offset); /* lay rn,param_offset(r7) */
n_gpregs++;
} else if (type == MIR_T_LD) { /* pass address of location in the result: */
s390x_gen_addi (ctx, 0, res_reg, param_offset); /* lay r0,param_offset(r7) */
s390x_gen_st (ctx, 0, 15, disp, MIR_T_I64); /* stg r0,disp(r15) */
disp += 8;
} else if (n_gpregs < 5) {
s390x_gen_ld (ctx, n_gpregs + 2, res_reg, param_offset, MIR_T_I64); /* lg* rn,param_offset(r7) */
n_gpregs++;
} else {
s390x_gen_ld (ctx, 0, res_reg, param_offset, MIR_T_I64); /* lg* r0,param_offset(r7) */
s390x_gen_st (ctx, 0, 15, disp, MIR_T_I64); /* stg* r0,disp(r15) */
disp += 8;
}
param_offset += 16;
}
s390x_gen_jump (ctx, 1, TRUE); /* call *r1 */
n_gpregs = n_fpregs = 0;
disp = 0;
for (uint32_t i = 0; i < nres; i++) {
type = res_types[i];
if (type == MIR_T_LD) continue; /* do nothing: the result value is already in results */
if ((type == MIR_T_F || type == MIR_T_D) && n_fpregs < 4) {
s390x_gen_st (ctx, n_fpregs * 2, res_reg, disp, type);
n_fpregs++;
} else if (type != MIR_T_F && type != MIR_T_D && n_gpregs < 1) { // just one gp reg
s390x_gen_st (ctx, n_gpregs + 2, res_reg, disp, MIR_T_I64);
n_gpregs++;
} else {
(*error_func) (MIR_ret_error, "s390x can not handle this combination of return values");
}
disp += 16;
}
s390x_gen_addi (ctx, 15, 15, frame_size); /* lay 15,frame_size(15) */
s390x_gen_ldstm (ctx, 6, 7, 15, 48, TRUE); /* lmg 6,7,48(r15) : */
s390x_gen_ld (ctx, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (ctx, 14, FALSE); /* bcr m15,r14 */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}
/* Transform C call to call of void handler (MIR_context_t ctx, MIR_item_t func_item,
va_list va, MIR_val_t *results):
Brief: save all C call args to register save area; save r7, r14;
allocate shim stack frame (S390X_STACK_HEADER_SIZE + space for results and va);
call handler with args; move results to return regs; restore r7,r14,r15; return */
void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler) {
MIR_func_t func = func_item->u.func;
uint32_t nres = func->nres, nargs = func->nargs;
MIR_type_t type, *res_types = func->res_types;
int disp, frame_size, local_var_size, n_gpregs, n_fpregs, va_list_disp, results_disp;
VARR_TRUNC (uint8_t, machine_insns, 0);
frame_size = S390X_STACK_HEADER_SIZE; /* register save area */
s390x_gen_st (ctx, 14, 15, 112, MIR_T_I64); /* stg 14,112(r15) */
s390x_gen_ldstm (ctx, 2, 6, 15, 16, FALSE); /* stmg 2,6,16(r15) : */
for (unsigned reg = 0; reg <= 6; reg += 2) /* stdy f0,f2,f4,f6,128(r15) : */
s390x_gen_st (ctx, reg, 15, reg * 4 + 128, MIR_T_D);
local_var_size = sizeof (struct s390x_va_list) + nres * 16; /* allocate va and results */
va_list_disp = frame_size;
results_disp = va_list_disp + sizeof (struct s390x_va_list);
frame_size += local_var_size;
assert (frame_size % 8 == 0);
s390x_gen_addi (ctx, 15, 15, -frame_size);
/* setup va: mvghi va(15),(0,1): __gpr */
s390x_gen_mvi (ctx, nres > 0 && res_types[0] == MIR_T_LD ? 1 : 0, 15, va_list_disp);
s390x_gen_mvi (ctx, 0, 15, va_list_disp + 8); /* mvghi va+8(15),0: __fpr */
s390x_gen_addi (ctx, 1, 15, frame_size); /* lay 1,frame_size(15) */
s390x_gen_st (ctx, 1, 15, va_list_disp + 24, MIR_T_I64); /* stg 1,va+24(r15): __reg_save_area */
s390x_gen_addi (ctx, 1, 1, S390X_STACK_HEADER_SIZE); /* lay 1,S390X_STACK_HEADER_SIZE(1) */
/* stg 1,va+16(r15):__overflow_arg_area: */
s390x_gen_st (ctx, 1, 15, va_list_disp + 16, MIR_T_I64);
/* call handler: */
s390x_gen_3addrs (ctx, 2, ctx, 3, func_item, 1, handler);
s390x_gen_addi (ctx, 4, 15, va_list_disp);
s390x_gen_addi (ctx, 5, 15, results_disp);
s390x_gen_jump (ctx, 1, TRUE);
/* setup result regs: */
disp = results_disp;
n_gpregs = n_fpregs = 0;
for (uint32_t i = 0; i < nres; i++) {
type = res_types[i];
if ((type == MIR_T_F || type == MIR_T_D) && n_fpregs < 4) {
s390x_gen_ld (ctx, n_fpregs * 2, 15, disp, type);
n_fpregs++;
} else if (type != MIR_T_F && type != MIR_T_D && n_gpregs < 1) { // just one gp reg
if (type != MIR_T_LD) {
s390x_gen_ld (ctx, n_gpregs + 2, 15, disp, MIR_T_I64);
} else {
/* ld address: lg r2,16+frame_size(r15) */
s390x_gen_ld (ctx, 2, 15, 16 + frame_size, MIR_T_I64);
s390x_gen_ld (ctx, 0, 15, disp, MIR_T_D); /* ld f0,disp(r15) */
s390x_gen_ld (ctx, 2, 15, disp + 8, MIR_T_D); /* ld f2,disp + 8(r15) */
s390x_gen_st (ctx, 0, 2, 0, MIR_T_D); /* st f0,0(r2) */
s390x_gen_st (ctx, 2, 2, 8, MIR_T_D); /* st f2,8(r2) */
}
n_gpregs++;
} else {
(*error_func) (MIR_ret_error, "s390x can not handle this combination of return values");
}
disp += 16;
}
s390x_gen_addi (ctx, 15, 15, frame_size); /* lay 15,frame_size(15) */
s390x_gen_ld (ctx, 6, 15, 48, MIR_T_I64); /* lg 6,48(r15) : */
s390x_gen_ld (ctx, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (ctx, 14, FALSE); /* bcr m15,r14 */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}
/* Brief: save r14 (r15+120); save all param regs r2-r6 (r15+16),f0,f2,f4,f6 (r15+128);
update r15; allocate and form minimal wrapper stack frame (S390X_STACK_HEADER_SIZE);
r2 = call hook_address (ctx, called_func); r1=r2; restore all params regs, r15, r14; bcr r1 */
void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_address) {
int frame_size = S390X_STACK_HEADER_SIZE;
VARR_TRUNC (uint8_t, machine_insns, 0);
s390x_gen_st (ctx, 14, 15, 112, MIR_T_I64); /* stg 14,112(r15) */
s390x_gen_ldstm (ctx, 2, 6, 15, 16, FALSE); /* stmg 2,6,16(r15) : */
for (unsigned reg = 0; reg <= 6; reg += 2) /* stdy f0,f2,f4,f6,128(r15) : */
s390x_gen_st (ctx, reg, 15, reg * 4 + 128, MIR_T_D);
/* r15 -= frame_size: */
s390x_gen_addi (ctx, 15, 15, -frame_size);
s390x_gen_3addrs (ctx, 2, ctx, 3, called_func, 4, hook_address);
s390x_gen_jump (ctx, 4, TRUE);
s390x_gen_mov (ctx, 1, 2);
s390x_gen_addi (ctx, 15, 15, frame_size);
for (unsigned reg = 0; reg <= 6; reg += 2) /* ldy fn,disp(r15) : */
s390x_gen_ld (ctx, reg, 15, reg * 4 + 128, MIR_T_D);
s390x_gen_ldstm (ctx, 2, 6, 15, 16, TRUE); /* lmg 2,6,16(r15) : */
s390x_gen_ld (ctx, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (ctx, 1, FALSE);
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}

@ -5451,6 +5451,8 @@ static void scan_finish (MIR_context_t ctx) {
#include "mir-aarch64.c"
#elif defined(__PPC64__)
#include "mir-ppc64.c"
#elif defined(__s390x__)
#include "mir-s390x.c"
#else
#error "undefined or unsupported generation target"
#endif

Loading…
Cancel
Save