2008-07-23 23:17:46 +04:00
|
|
|
/*
|
|
|
|
* Tiny Code Generator for QEMU
|
|
|
|
*
|
|
|
|
* Copyright (c) 2008 Fabrice Bellard
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2017-07-31 09:03:03 +03:00
|
|
|
#include "elf.h"
|
2020-02-04 14:41:01 +03:00
|
|
|
#include "../tcg-pool.c.inc"
|
2021-08-04 01:08:55 +03:00
|
|
|
#include "../tcg-ldst.c.inc"
|
2017-07-31 09:03:03 +03:00
|
|
|
|
2021-07-13 00:29:10 +03:00
|
|
|
/*
|
|
|
|
* Standardize on the _CALL_FOO symbols used by GCC:
|
|
|
|
* Apple XCode does not define _CALL_DARWIN.
|
2023-06-06 00:40:31 +03:00
|
|
|
* Clang defines _CALL_ELF (64-bit) but not _CALL_SYSV or _CALL_AIX.
|
2021-07-13 00:29:10 +03:00
|
|
|
*/
|
2023-06-06 00:40:31 +03:00
|
|
|
#if TCG_TARGET_REG_BITS == 64
|
|
|
|
# ifdef _CALL_AIX
|
|
|
|
/* ok */
|
|
|
|
# elif defined(_CALL_ELF) && _CALL_ELF == 1
|
|
|
|
# define _CALL_AIX
|
|
|
|
# elif defined(_CALL_ELF) && _CALL_ELF == 2
|
|
|
|
/* ok */
|
|
|
|
# else
|
|
|
|
# error "Unknown ABI"
|
|
|
|
# endif
|
|
|
|
#else
|
|
|
|
# if defined(_CALL_SYSV) || defined(_CALL_DARWIN)
|
|
|
|
/* ok */
|
|
|
|
# elif defined(__APPLE__)
|
2021-07-13 00:29:10 +03:00
|
|
|
# define _CALL_DARWIN
|
2023-06-06 00:40:31 +03:00
|
|
|
# elif defined(__ELF__)
|
2021-07-13 00:29:10 +03:00
|
|
|
# define _CALL_SYSV
|
|
|
|
# else
|
|
|
|
# error "Unknown ABI"
|
|
|
|
# endif
|
2022-12-01 09:38:25 +03:00
|
|
|
#endif
|
2021-07-13 00:29:10 +03:00
|
|
|
|
2022-10-16 13:07:48 +03:00
|
|
|
#if TCG_TARGET_REG_BITS == 64
|
|
|
|
# define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EXTEND
|
2023-04-08 18:36:40 +03:00
|
|
|
# define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL
|
2022-10-16 13:07:48 +03:00
|
|
|
#else
|
|
|
|
# define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL
|
2023-04-08 18:36:40 +03:00
|
|
|
# define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_BY_REF
|
2022-10-16 13:07:48 +03:00
|
|
|
#endif
|
2014-03-25 23:11:48 +04:00
|
|
|
#ifdef _CALL_SYSV
|
2022-10-16 05:48:48 +03:00
|
|
|
# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN
|
2023-04-08 18:36:40 +03:00
|
|
|
# define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_BY_REF
|
2022-10-16 05:48:48 +03:00
|
|
|
#else
|
|
|
|
# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL
|
2023-04-08 18:36:40 +03:00
|
|
|
# define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL
|
2014-03-25 23:11:48 +04:00
|
|
|
#endif
|
2014-03-25 20:13:38 +04:00
|
|
|
|
2014-04-30 23:12:16 +04:00
|
|
|
/* For some memory operations, we need a scratch that isn't R0. For the AIX
|
|
|
|
calling convention, we can re-use the TOC register since we'll be reloading
|
|
|
|
it at every call. Otherwise R12 will do nicely as neither a call-saved
|
|
|
|
register nor a parameter register. */
|
|
|
|
#ifdef _CALL_AIX
|
|
|
|
# define TCG_REG_TMP1 TCG_REG_R2
|
|
|
|
#else
|
|
|
|
# define TCG_REG_TMP1 TCG_REG_R12
|
|
|
|
#endif
|
2023-04-04 01:25:06 +03:00
|
|
|
#define TCG_REG_TMP2 TCG_REG_R11
|
2014-04-30 23:12:16 +04:00
|
|
|
|
2019-06-23 20:04:34 +03:00
|
|
|
#define TCG_VEC_TMP1 TCG_REG_V0
|
|
|
|
#define TCG_VEC_TMP2 TCG_REG_V1
|
|
|
|
|
2017-07-31 07:16:10 +03:00
|
|
|
#define TCG_REG_TB TCG_REG_R31
|
|
|
|
#define USE_REG_TB (TCG_TARGET_REG_BITS == 64)
|
2014-03-28 17:53:53 +04:00
|
|
|
|
2014-03-25 02:22:35 +04:00
|
|
|
/* Shorthand for size of a pointer. Avoid promotion to unsigned. */
|
|
|
|
#define SZP ((int)sizeof(void *))
|
|
|
|
|
2014-03-25 03:03:59 +04:00
|
|
|
/* Shorthand for size of a register. */
|
|
|
|
#define SZR (TCG_TARGET_REG_BITS / 8)
|
|
|
|
|
2013-02-02 04:51:53 +04:00
|
|
|
#define TCG_CT_CONST_S16 0x100
|
|
|
|
#define TCG_CT_CONST_S32 0x400
|
|
|
|
#define TCG_CT_CONST_U32 0x800
|
|
|
|
#define TCG_CT_CONST_ZERO 0x1000
|
2013-03-05 02:26:52 +04:00
|
|
|
#define TCG_CT_CONST_MONE 0x2000
|
2016-11-16 14:48:55 +03:00
|
|
|
#define TCG_CT_CONST_WSZ 0x4000
|
2008-07-29 03:46:06 +04:00
|
|
|
|
2020-10-15 23:04:49 +03:00
|
|
|
#define ALL_GENERAL_REGS 0xffffffffu
|
|
|
|
#define ALL_VECTOR_REGS 0xffffffff00000000ull
|
|
|
|
|
2023-06-05 18:29:04 +03:00
|
|
|
#define have_isel (cpuinfo & CPUINFO_ISEL)
|
2013-02-02 12:58:14 +04:00
|
|
|
|
2015-08-24 02:42:07 +03:00
|
|
|
#ifndef CONFIG_SOFTMMU
|
2009-07-18 10:08:40 +04:00
|
|
|
#define TCG_GUEST_BASE_REG 30
|
|
|
|
#endif
|
|
|
|
|
2016-04-21 11:48:50 +03:00
|
|
|
#ifdef CONFIG_DEBUG_TCG
|
2019-06-23 20:04:34 +03:00
|
|
|
static const char tcg_target_reg_names[TCG_TARGET_NB_REGS][4] = {
|
|
|
|
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
|
|
|
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
|
|
|
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
|
|
|
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
|
|
|
|
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
|
|
|
|
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
|
|
|
|
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
|
|
|
|
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
|
2008-07-23 23:17:46 +04:00
|
|
|
};
|
2008-10-05 13:59:14 +04:00
|
|
|
#endif
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
static const int tcg_target_reg_alloc_order[] = {
|
2013-07-31 21:18:49 +04:00
|
|
|
TCG_REG_R14, /* call saved registers */
|
2008-07-23 23:17:46 +04:00
|
|
|
TCG_REG_R15,
|
|
|
|
TCG_REG_R16,
|
|
|
|
TCG_REG_R17,
|
|
|
|
TCG_REG_R18,
|
|
|
|
TCG_REG_R19,
|
|
|
|
TCG_REG_R20,
|
|
|
|
TCG_REG_R21,
|
|
|
|
TCG_REG_R22,
|
|
|
|
TCG_REG_R23,
|
2013-07-31 21:18:49 +04:00
|
|
|
TCG_REG_R24,
|
|
|
|
TCG_REG_R25,
|
|
|
|
TCG_REG_R26,
|
|
|
|
TCG_REG_R27,
|
2008-07-23 23:17:46 +04:00
|
|
|
TCG_REG_R28,
|
|
|
|
TCG_REG_R29,
|
|
|
|
TCG_REG_R30,
|
|
|
|
TCG_REG_R31,
|
2013-07-31 21:18:49 +04:00
|
|
|
TCG_REG_R12, /* call clobbered, non-arguments */
|
|
|
|
TCG_REG_R11,
|
2014-04-30 23:12:16 +04:00
|
|
|
TCG_REG_R2,
|
|
|
|
TCG_REG_R13,
|
2013-07-31 21:18:49 +04:00
|
|
|
TCG_REG_R10, /* call clobbered, arguments */
|
2008-07-23 23:17:46 +04:00
|
|
|
TCG_REG_R9,
|
2013-07-31 21:18:49 +04:00
|
|
|
TCG_REG_R8,
|
|
|
|
TCG_REG_R7,
|
|
|
|
TCG_REG_R6,
|
|
|
|
TCG_REG_R5,
|
|
|
|
TCG_REG_R4,
|
|
|
|
TCG_REG_R3,
|
2019-06-23 20:04:34 +03:00
|
|
|
|
|
|
|
/* V0 and V1 reserved as temporaries; V20 - V31 are call-saved */
|
|
|
|
TCG_REG_V2, /* call clobbered, vectors */
|
|
|
|
TCG_REG_V3,
|
|
|
|
TCG_REG_V4,
|
|
|
|
TCG_REG_V5,
|
|
|
|
TCG_REG_V6,
|
|
|
|
TCG_REG_V7,
|
|
|
|
TCG_REG_V8,
|
|
|
|
TCG_REG_V9,
|
|
|
|
TCG_REG_V10,
|
|
|
|
TCG_REG_V11,
|
|
|
|
TCG_REG_V12,
|
|
|
|
TCG_REG_V13,
|
|
|
|
TCG_REG_V14,
|
|
|
|
TCG_REG_V15,
|
|
|
|
TCG_REG_V16,
|
|
|
|
TCG_REG_V17,
|
|
|
|
TCG_REG_V18,
|
|
|
|
TCG_REG_V19,
|
2008-07-23 23:17:46 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static const int tcg_target_call_iarg_regs[] = {
|
|
|
|
TCG_REG_R3,
|
|
|
|
TCG_REG_R4,
|
|
|
|
TCG_REG_R5,
|
|
|
|
TCG_REG_R6,
|
|
|
|
TCG_REG_R7,
|
|
|
|
TCG_REG_R8,
|
|
|
|
TCG_REG_R9,
|
|
|
|
TCG_REG_R10
|
|
|
|
};
|
|
|
|
|
2022-10-19 17:55:36 +03:00
|
|
|
static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
|
|
|
|
{
|
|
|
|
tcg_debug_assert(kind == TCG_CALL_RET_NORMAL);
|
|
|
|
tcg_debug_assert(slot >= 0 && slot <= 1);
|
|
|
|
return TCG_REG_R3 + slot;
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
static const int tcg_target_callee_save_regs[] = {
|
2021-07-13 00:17:37 +03:00
|
|
|
#ifdef _CALL_DARWIN
|
2009-12-06 16:00:24 +03:00
|
|
|
TCG_REG_R11,
|
|
|
|
#endif
|
2008-07-23 23:17:46 +04:00
|
|
|
TCG_REG_R14,
|
|
|
|
TCG_REG_R15,
|
|
|
|
TCG_REG_R16,
|
|
|
|
TCG_REG_R17,
|
|
|
|
TCG_REG_R18,
|
|
|
|
TCG_REG_R19,
|
|
|
|
TCG_REG_R20,
|
|
|
|
TCG_REG_R21,
|
|
|
|
TCG_REG_R22,
|
|
|
|
TCG_REG_R23,
|
2009-02-11 21:54:02 +03:00
|
|
|
TCG_REG_R24,
|
|
|
|
TCG_REG_R25,
|
|
|
|
TCG_REG_R26,
|
2011-05-15 20:03:25 +04:00
|
|
|
TCG_REG_R27, /* currently used for the global env */
|
2008-07-23 23:17:46 +04:00
|
|
|
TCG_REG_R28,
|
|
|
|
TCG_REG_R29,
|
|
|
|
TCG_REG_R30,
|
|
|
|
TCG_REG_R31
|
|
|
|
};
|
|
|
|
|
2023-08-15 19:58:19 +03:00
|
|
|
/* For PPC, we use TB+4 instead of TB as the base. */
|
|
|
|
static inline ptrdiff_t ppc_tbrel_diff(TCGContext *s, const void *target)
|
|
|
|
{
|
|
|
|
return tcg_tbrel_diff(s, target) - 4;
|
|
|
|
}
|
|
|
|
|
2013-08-31 17:30:45 +04:00
|
|
|
static inline bool in_range_b(tcg_target_long target)
|
|
|
|
{
|
|
|
|
return target == sextract64(target, 0, 26);
|
|
|
|
}
|
|
|
|
|
2020-11-04 21:17:46 +03:00
|
|
|
static uint32_t reloc_pc24_val(const tcg_insn_unit *pc,
|
2023-08-04 23:35:53 +03:00
|
|
|
const tcg_insn_unit *target)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2014-03-29 01:58:38 +04:00
|
|
|
ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
|
2016-04-21 11:48:49 +03:00
|
|
|
tcg_debug_assert(in_range_b(disp));
|
2008-07-23 23:17:46 +04:00
|
|
|
return disp & 0x3fffffc;
|
|
|
|
}
|
|
|
|
|
2020-11-04 21:17:46 +03:00
|
|
|
static bool reloc_pc24(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2020-11-04 21:17:46 +03:00
|
|
|
const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw);
|
|
|
|
ptrdiff_t disp = tcg_ptr_byte_diff(target, src_rx);
|
|
|
|
|
2018-12-01 00:25:13 +03:00
|
|
|
if (in_range_b(disp)) {
|
2020-11-04 21:17:46 +03:00
|
|
|
*src_rw = (*src_rw & ~0x3fffffc) | (disp & 0x3fffffc);
|
2018-12-01 00:25:13 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2020-11-04 21:17:46 +03:00
|
|
|
static uint16_t reloc_pc14_val(const tcg_insn_unit *pc,
|
2023-08-04 23:35:53 +03:00
|
|
|
const tcg_insn_unit *target)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2014-03-29 01:58:38 +04:00
|
|
|
ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
|
2016-04-21 11:48:49 +03:00
|
|
|
tcg_debug_assert(disp == (int16_t) disp);
|
2008-07-23 23:17:46 +04:00
|
|
|
return disp & 0xfffc;
|
|
|
|
}
|
|
|
|
|
2020-11-04 21:17:46 +03:00
|
|
|
static bool reloc_pc14(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2020-11-04 21:17:46 +03:00
|
|
|
const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw);
|
|
|
|
ptrdiff_t disp = tcg_ptr_byte_diff(target, src_rx);
|
|
|
|
|
2018-12-01 00:25:13 +03:00
|
|
|
if (disp == (int16_t) disp) {
|
2020-11-04 21:17:46 +03:00
|
|
|
*src_rw = (*src_rw & ~0xfffc) | (disp & 0xfffc);
|
2018-12-01 00:25:13 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* test if a constant matches the constraint */
|
2023-09-08 05:21:10 +03:00
|
|
|
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2013-02-02 04:51:53 +04:00
|
|
|
if (ct & TCG_CT_CONST) {
|
|
|
|
return 1;
|
2014-03-31 09:07:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The only 32-bit constraint we use aside from
|
|
|
|
TCG_CT_CONST is TCG_CT_CONST_S16. */
|
|
|
|
if (type == TCG_TYPE_I32) {
|
|
|
|
val = (int32_t)val;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) {
|
2013-02-02 04:51:53 +04:00
|
|
|
return 1;
|
|
|
|
} else if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) {
|
2008-07-29 03:46:06 +04:00
|
|
|
return 1;
|
2013-02-02 04:51:53 +04:00
|
|
|
} else if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val) {
|
|
|
|
return 1;
|
|
|
|
} else if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
|
|
|
|
return 1;
|
2013-03-05 02:26:52 +04:00
|
|
|
} else if ((ct & TCG_CT_CONST_MONE) && val == -1) {
|
|
|
|
return 1;
|
2016-11-16 14:48:55 +03:00
|
|
|
} else if ((ct & TCG_CT_CONST_WSZ)
|
|
|
|
&& val == (type == TCG_TYPE_I32 ? 32 : 64)) {
|
|
|
|
return 1;
|
2013-02-02 04:51:53 +04:00
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define OPCD(opc) ((opc)<<26)
|
|
|
|
#define XO19(opc) (OPCD(19)|((opc)<<1))
|
2013-06-11 15:19:35 +04:00
|
|
|
#define MD30(opc) (OPCD(30)|((opc)<<2))
|
|
|
|
#define MDS30(opc) (OPCD(30)|((opc)<<1))
|
2008-07-23 23:17:46 +04:00
|
|
|
#define XO31(opc) (OPCD(31)|((opc)<<1))
|
|
|
|
#define XO58(opc) (OPCD(58)|(opc))
|
|
|
|
#define XO62(opc) (OPCD(62)|(opc))
|
2019-06-23 20:04:36 +03:00
|
|
|
#define VX4(opc) (OPCD(4)|(opc))
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
#define B OPCD( 18)
|
|
|
|
#define BC OPCD( 16)
|
2023-04-19 16:13:22 +03:00
|
|
|
|
2008-07-23 23:17:46 +04:00
|
|
|
#define LBZ OPCD( 34)
|
|
|
|
#define LHZ OPCD( 40)
|
|
|
|
#define LHA OPCD( 42)
|
|
|
|
#define LWZ OPCD( 32)
|
2018-12-26 04:31:26 +03:00
|
|
|
#define LWZUX XO31( 55)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define LD XO58( 0)
|
|
|
|
#define LDX XO31( 21)
|
|
|
|
#define LDU XO58( 1)
|
2018-12-26 04:31:26 +03:00
|
|
|
#define LDUX XO31( 53)
|
2008-07-27 14:28:15 +04:00
|
|
|
#define LWA XO58( 2)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define LWAX XO31(341)
|
2023-04-19 16:13:22 +03:00
|
|
|
#define LQ OPCD( 56)
|
|
|
|
|
|
|
|
#define STB OPCD( 38)
|
|
|
|
#define STH OPCD( 44)
|
|
|
|
#define STW OPCD( 36)
|
|
|
|
#define STD XO62( 0)
|
|
|
|
#define STDU XO62( 1)
|
|
|
|
#define STDX XO31(149)
|
|
|
|
#define STQ XO62( 2)
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2023-08-04 20:16:32 +03:00
|
|
|
#define PLWA OPCD( 41)
|
|
|
|
#define PLD OPCD( 57)
|
|
|
|
#define PLXSD OPCD( 42)
|
|
|
|
#define PLXV OPCD(25 * 2 + 1) /* force tx=1 */
|
|
|
|
|
|
|
|
#define PSTD OPCD( 61)
|
|
|
|
#define PSTXSD OPCD( 46)
|
|
|
|
#define PSTXV OPCD(27 * 2 + 1) /* force sx=1 */
|
|
|
|
|
2010-02-07 02:48:53 +03:00
|
|
|
#define ADDIC OPCD( 12)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define ADDI OPCD( 14)
|
|
|
|
#define ADDIS OPCD( 15)
|
|
|
|
#define ORI OPCD( 24)
|
|
|
|
#define ORIS OPCD( 25)
|
|
|
|
#define XORI OPCD( 26)
|
|
|
|
#define XORIS OPCD( 27)
|
|
|
|
#define ANDI OPCD( 28)
|
|
|
|
#define ANDIS OPCD( 29)
|
|
|
|
#define MULLI OPCD( 7)
|
|
|
|
#define CMPLI OPCD( 10)
|
|
|
|
#define CMPI OPCD( 11)
|
2013-04-04 18:30:20 +04:00
|
|
|
#define SUBFIC OPCD( 8)
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
#define LWZU OPCD( 33)
|
|
|
|
#define STWU OPCD( 37)
|
|
|
|
|
2013-01-31 07:24:06 +04:00
|
|
|
#define RLWIMI OPCD( 20)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define RLWINM OPCD( 21)
|
2013-01-31 07:24:06 +04:00
|
|
|
#define RLWNM OPCD( 23)
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2013-06-11 15:19:35 +04:00
|
|
|
#define RLDICL MD30( 0)
|
|
|
|
#define RLDICR MD30( 1)
|
|
|
|
#define RLDIMI MD30( 3)
|
|
|
|
#define RLDCL MDS30( 8)
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
#define BCLR XO19( 16)
|
|
|
|
#define BCCTR XO19(528)
|
|
|
|
#define CRAND XO19(257)
|
|
|
|
#define CRANDC XO19(129)
|
|
|
|
#define CRNAND XO19(225)
|
|
|
|
#define CROR XO19(449)
|
2010-02-07 02:48:53 +03:00
|
|
|
#define CRNOR XO19( 33)
|
2023-08-15 20:04:42 +03:00
|
|
|
#define ADDPCIS XO19( 2)
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
#define EXTSB XO31(954)
|
|
|
|
#define EXTSH XO31(922)
|
|
|
|
#define EXTSW XO31(986)
|
|
|
|
#define ADD XO31(266)
|
|
|
|
#define ADDE XO31(138)
|
2013-03-05 02:26:52 +04:00
|
|
|
#define ADDME XO31(234)
|
|
|
|
#define ADDZE XO31(202)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define ADDC XO31( 10)
|
|
|
|
#define AND XO31( 28)
|
|
|
|
#define SUBF XO31( 40)
|
|
|
|
#define SUBFC XO31( 8)
|
|
|
|
#define SUBFE XO31(136)
|
2013-03-05 02:26:52 +04:00
|
|
|
#define SUBFME XO31(232)
|
|
|
|
#define SUBFZE XO31(200)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define OR XO31(444)
|
|
|
|
#define XOR XO31(316)
|
|
|
|
#define MULLW XO31(235)
|
2014-03-26 22:37:06 +04:00
|
|
|
#define MULHW XO31( 75)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define MULHWU XO31( 11)
|
|
|
|
#define DIVW XO31(491)
|
|
|
|
#define DIVWU XO31(459)
|
2022-06-13 17:43:59 +03:00
|
|
|
#define MODSW XO31(779)
|
|
|
|
#define MODUW XO31(267)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define CMP XO31( 0)
|
|
|
|
#define CMPL XO31( 32)
|
|
|
|
#define LHBRX XO31(790)
|
|
|
|
#define LWBRX XO31(534)
|
2013-02-02 12:58:14 +04:00
|
|
|
#define LDBRX XO31(532)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define STHBRX XO31(918)
|
|
|
|
#define STWBRX XO31(662)
|
2013-02-02 12:58:14 +04:00
|
|
|
#define STDBRX XO31(660)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define MFSPR XO31(339)
|
|
|
|
#define MTSPR XO31(467)
|
|
|
|
#define SRAWI XO31(824)
|
|
|
|
#define NEG XO31(104)
|
2010-02-07 02:48:53 +03:00
|
|
|
#define MFCR XO31( 19)
|
2013-04-03 02:09:52 +04:00
|
|
|
#define MFOCRF (MFCR | (1u << 20))
|
2011-08-22 14:40:00 +04:00
|
|
|
#define NOR XO31(124)
|
2010-02-07 02:48:53 +03:00
|
|
|
#define CNTLZW XO31( 26)
|
|
|
|
#define CNTLZD XO31( 58)
|
2016-11-16 14:48:55 +03:00
|
|
|
#define CNTTZW XO31(538)
|
|
|
|
#define CNTTZD XO31(570)
|
2016-11-22 14:43:12 +03:00
|
|
|
#define CNTPOPW XO31(378)
|
|
|
|
#define CNTPOPD XO31(506)
|
2013-01-31 19:49:13 +04:00
|
|
|
#define ANDC XO31( 60)
|
|
|
|
#define ORC XO31(412)
|
|
|
|
#define EQV XO31(284)
|
|
|
|
#define NAND XO31(476)
|
2013-04-03 02:16:10 +04:00
|
|
|
#define ISEL XO31( 15)
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
#define MULLD XO31(233)
|
|
|
|
#define MULHD XO31( 73)
|
|
|
|
#define MULHDU XO31( 9)
|
|
|
|
#define DIVD XO31(489)
|
|
|
|
#define DIVDU XO31(457)
|
2022-06-13 17:43:59 +03:00
|
|
|
#define MODSD XO31(777)
|
|
|
|
#define MODUD XO31(265)
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
#define LBZX XO31( 87)
|
2009-07-18 13:15:55 +04:00
|
|
|
#define LHZX XO31(279)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define LHAX XO31(343)
|
|
|
|
#define LWZX XO31( 23)
|
|
|
|
#define STBX XO31(215)
|
|
|
|
#define STHX XO31(407)
|
|
|
|
#define STWX XO31(151)
|
|
|
|
|
2016-07-14 23:20:19 +03:00
|
|
|
#define EIEIO XO31(854)
|
|
|
|
#define HWSYNC XO31(598)
|
|
|
|
#define LWSYNC (HWSYNC | (1u << 21))
|
|
|
|
|
2013-08-31 16:14:53 +04:00
|
|
|
#define SPR(a, b) ((((a)<<5)|(b))<<11)
|
2008-07-23 23:17:46 +04:00
|
|
|
#define LR SPR(8, 0)
|
|
|
|
#define CTR SPR(9, 0)
|
|
|
|
|
|
|
|
#define SLW XO31( 24)
|
|
|
|
#define SRW XO31(536)
|
|
|
|
#define SRAW XO31(792)
|
|
|
|
|
|
|
|
#define SLD XO31( 27)
|
|
|
|
#define SRD XO31(539)
|
|
|
|
#define SRAD XO31(794)
|
2008-07-29 03:46:06 +04:00
|
|
|
#define SRADI XO31(413<<1)
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2021-06-13 20:45:07 +03:00
|
|
|
#define BRH XO31(219)
|
|
|
|
#define BRW XO31(155)
|
|
|
|
#define BRD XO31(187)
|
|
|
|
|
2008-07-23 23:17:46 +04:00
|
|
|
#define TW XO31( 4)
|
2013-08-31 16:14:53 +04:00
|
|
|
#define TRAP (TW | TO(31))
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2023-08-05 05:04:56 +03:00
|
|
|
#define SETBC XO31(384) /* v3.10 */
|
|
|
|
#define SETBCR XO31(416) /* v3.10 */
|
|
|
|
#define SETNBC XO31(448) /* v3.10 */
|
|
|
|
#define SETNBCR XO31(480) /* v3.10 */
|
|
|
|
|
2014-03-28 17:53:53 +04:00
|
|
|
#define NOP ORI /* ori 0,0,0 */
|
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
#define LVX XO31(103)
|
|
|
|
#define LVEBX XO31(7)
|
|
|
|
#define LVEHX XO31(39)
|
|
|
|
#define LVEWX XO31(71)
|
2019-06-23 20:04:47 +03:00
|
|
|
#define LXSDX (XO31(588) | 1) /* v2.06, force tx=1 */
|
|
|
|
#define LXVDSX (XO31(332) | 1) /* v2.06, force tx=1 */
|
2019-09-30 06:50:41 +03:00
|
|
|
#define LXSIWZX (XO31(12) | 1) /* v2.07, force tx=1 */
|
2019-09-30 07:36:26 +03:00
|
|
|
#define LXV (OPCD(61) | 8 | 1) /* v3.00, force tx=1 */
|
|
|
|
#define LXSD (OPCD(57) | 2) /* v3.00 */
|
|
|
|
#define LXVWSX (XO31(364) | 1) /* v3.00, force tx=1 */
|
2019-06-23 20:04:38 +03:00
|
|
|
|
|
|
|
#define STVX XO31(231)
|
|
|
|
#define STVEWX XO31(199)
|
2019-06-23 20:04:47 +03:00
|
|
|
#define STXSDX (XO31(716) | 1) /* v2.06, force sx=1 */
|
2019-09-30 06:50:41 +03:00
|
|
|
#define STXSIWX (XO31(140) | 1) /* v2.07, force sx=1 */
|
2019-09-30 07:36:26 +03:00
|
|
|
#define STXV (OPCD(61) | 8 | 5) /* v3.00, force sx=1 */
|
|
|
|
#define STXSD (OPCD(61) | 2) /* v3.00 */
|
2019-06-23 20:04:38 +03:00
|
|
|
|
tcg/ppc: Add support for vector saturated add/subtract
Add support for vector saturated add/subtract using Altivec
instructions:
VADDSBS, VADDSHS, VADDSWS, VADDUBS, VADDUHS, VADDUWS, and
VSUBSBS, VSUBSHS, VSUBSWS, VSUBUBS, VSUBUHS, VSUBUWS.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:41 +03:00
|
|
|
#define VADDSBS VX4(768)
|
|
|
|
#define VADDUBS VX4(512)
|
2019-06-23 20:04:40 +03:00
|
|
|
#define VADDUBM VX4(0)
|
tcg/ppc: Add support for vector saturated add/subtract
Add support for vector saturated add/subtract using Altivec
instructions:
VADDSBS, VADDSHS, VADDSWS, VADDUBS, VADDUHS, VADDUWS, and
VSUBSBS, VSUBSHS, VSUBSWS, VSUBUBS, VSUBUHS, VSUBUWS.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:41 +03:00
|
|
|
#define VADDSHS VX4(832)
|
|
|
|
#define VADDUHS VX4(576)
|
2019-06-23 20:04:40 +03:00
|
|
|
#define VADDUHM VX4(64)
|
tcg/ppc: Add support for vector saturated add/subtract
Add support for vector saturated add/subtract using Altivec
instructions:
VADDSBS, VADDSHS, VADDSWS, VADDUBS, VADDUHS, VADDUWS, and
VSUBSBS, VSUBSHS, VSUBSWS, VSUBUBS, VSUBUHS, VSUBUWS.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:41 +03:00
|
|
|
#define VADDSWS VX4(896)
|
|
|
|
#define VADDUWS VX4(640)
|
2019-06-23 20:04:40 +03:00
|
|
|
#define VADDUWM VX4(128)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VADDUDM VX4(192) /* v2.07 */
|
2019-06-23 20:04:40 +03:00
|
|
|
|
tcg/ppc: Add support for vector saturated add/subtract
Add support for vector saturated add/subtract using Altivec
instructions:
VADDSBS, VADDSHS, VADDSWS, VADDUBS, VADDUHS, VADDUWS, and
VSUBSBS, VSUBSHS, VSUBSWS, VSUBUBS, VSUBUHS, VSUBUWS.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:41 +03:00
|
|
|
#define VSUBSBS VX4(1792)
|
|
|
|
#define VSUBUBS VX4(1536)
|
2019-06-23 20:04:40 +03:00
|
|
|
#define VSUBUBM VX4(1024)
|
tcg/ppc: Add support for vector saturated add/subtract
Add support for vector saturated add/subtract using Altivec
instructions:
VADDSBS, VADDSHS, VADDSWS, VADDUBS, VADDUHS, VADDUWS, and
VSUBSBS, VSUBSHS, VSUBSWS, VSUBUBS, VSUBUHS, VSUBUWS.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:41 +03:00
|
|
|
#define VSUBSHS VX4(1856)
|
|
|
|
#define VSUBUHS VX4(1600)
|
2019-06-23 20:04:40 +03:00
|
|
|
#define VSUBUHM VX4(1088)
|
tcg/ppc: Add support for vector saturated add/subtract
Add support for vector saturated add/subtract using Altivec
instructions:
VADDSBS, VADDSHS, VADDSWS, VADDUBS, VADDUHS, VADDUWS, and
VSUBSBS, VSUBSHS, VSUBSWS, VSUBUBS, VSUBUHS, VSUBUWS.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:41 +03:00
|
|
|
#define VSUBSWS VX4(1920)
|
|
|
|
#define VSUBUWS VX4(1664)
|
2019-06-23 20:04:40 +03:00
|
|
|
#define VSUBUWM VX4(1152)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VSUBUDM VX4(1216) /* v2.07 */
|
2019-06-23 20:04:40 +03:00
|
|
|
|
2019-09-30 07:21:22 +03:00
|
|
|
#define VNEGW (VX4(1538) | (6 << 16)) /* v3.00 */
|
|
|
|
#define VNEGD (VX4(1538) | (7 << 16)) /* v3.00 */
|
|
|
|
|
tcg/ppc: Add support for vector maximum/minimum
Add support for vector maximum/minimum using Altivec instructions
VMAXSB, VMAXSH, VMAXSW, VMAXUB, VMAXUH, VMAXUW, and
VMINSB, VMINSH, VMINSW, VMINUB, VMINUH, VMINUW.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:39 +03:00
|
|
|
#define VMAXSB VX4(258)
|
|
|
|
#define VMAXSH VX4(322)
|
|
|
|
#define VMAXSW VX4(386)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VMAXSD VX4(450) /* v2.07 */
|
tcg/ppc: Add support for vector maximum/minimum
Add support for vector maximum/minimum using Altivec instructions
VMAXSB, VMAXSH, VMAXSW, VMAXUB, VMAXUH, VMAXUW, and
VMINSB, VMINSH, VMINSW, VMINUB, VMINUH, VMINUW.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:39 +03:00
|
|
|
#define VMAXUB VX4(2)
|
|
|
|
#define VMAXUH VX4(66)
|
|
|
|
#define VMAXUW VX4(130)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VMAXUD VX4(194) /* v2.07 */
|
tcg/ppc: Add support for vector maximum/minimum
Add support for vector maximum/minimum using Altivec instructions
VMAXSB, VMAXSH, VMAXSW, VMAXUB, VMAXUH, VMAXUW, and
VMINSB, VMINSH, VMINSW, VMINUB, VMINUH, VMINUW.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:39 +03:00
|
|
|
#define VMINSB VX4(770)
|
|
|
|
#define VMINSH VX4(834)
|
|
|
|
#define VMINSW VX4(898)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VMINSD VX4(962) /* v2.07 */
|
tcg/ppc: Add support for vector maximum/minimum
Add support for vector maximum/minimum using Altivec instructions
VMAXSB, VMAXSH, VMAXSW, VMAXUB, VMAXUH, VMAXUW, and
VMINSB, VMINSH, VMINSW, VMINUB, VMINUH, VMINUW.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:39 +03:00
|
|
|
#define VMINUB VX4(514)
|
|
|
|
#define VMINUH VX4(578)
|
|
|
|
#define VMINUW VX4(642)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VMINUD VX4(706) /* v2.07 */
|
tcg/ppc: Add support for vector maximum/minimum
Add support for vector maximum/minimum using Altivec instructions
VMAXSB, VMAXSH, VMAXSW, VMAXUB, VMAXUH, VMAXUW, and
VMINSB, VMINSH, VMINSW, VMINUB, VMINUH, VMINUW.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:39 +03:00
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
#define VCMPEQUB VX4(6)
|
|
|
|
#define VCMPEQUH VX4(70)
|
|
|
|
#define VCMPEQUW VX4(134)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VCMPEQUD VX4(199) /* v2.07 */
|
2019-06-23 20:04:38 +03:00
|
|
|
#define VCMPGTSB VX4(774)
|
|
|
|
#define VCMPGTSH VX4(838)
|
|
|
|
#define VCMPGTSW VX4(902)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VCMPGTSD VX4(967) /* v2.07 */
|
2019-06-23 20:04:38 +03:00
|
|
|
#define VCMPGTUB VX4(518)
|
|
|
|
#define VCMPGTUH VX4(582)
|
|
|
|
#define VCMPGTUW VX4(646)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VCMPGTUD VX4(711) /* v2.07 */
|
2019-09-30 07:21:22 +03:00
|
|
|
#define VCMPNEB VX4(7) /* v3.00 */
|
|
|
|
#define VCMPNEH VX4(71) /* v3.00 */
|
|
|
|
#define VCMPNEW VX4(135) /* v3.00 */
|
2019-06-23 20:04:38 +03:00
|
|
|
|
2019-06-23 20:04:44 +03:00
|
|
|
#define VSLB VX4(260)
|
|
|
|
#define VSLH VX4(324)
|
|
|
|
#define VSLW VX4(388)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VSLD VX4(1476) /* v2.07 */
|
2019-06-23 20:04:44 +03:00
|
|
|
#define VSRB VX4(516)
|
|
|
|
#define VSRH VX4(580)
|
|
|
|
#define VSRW VX4(644)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VSRD VX4(1732) /* v2.07 */
|
2019-06-23 20:04:44 +03:00
|
|
|
#define VSRAB VX4(772)
|
|
|
|
#define VSRAH VX4(836)
|
|
|
|
#define VSRAW VX4(900)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VSRAD VX4(964) /* v2.07 */
|
2019-06-23 20:04:42 +03:00
|
|
|
#define VRLB VX4(4)
|
|
|
|
#define VRLH VX4(68)
|
|
|
|
#define VRLW VX4(132)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VRLD VX4(196) /* v2.07 */
|
2019-06-23 20:04:42 +03:00
|
|
|
|
|
|
|
#define VMULEUB VX4(520)
|
|
|
|
#define VMULEUH VX4(584)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VMULEUW VX4(648) /* v2.07 */
|
2019-06-23 20:04:42 +03:00
|
|
|
#define VMULOUB VX4(8)
|
|
|
|
#define VMULOUH VX4(72)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VMULOUW VX4(136) /* v2.07 */
|
|
|
|
#define VMULUWM VX4(137) /* v2.07 */
|
2020-07-24 07:58:41 +03:00
|
|
|
#define VMULLD VX4(457) /* v3.10 */
|
2019-06-23 20:04:42 +03:00
|
|
|
#define VMSUMUHM VX4(38)
|
|
|
|
|
|
|
|
#define VMRGHB VX4(12)
|
|
|
|
#define VMRGHH VX4(76)
|
|
|
|
#define VMRGHW VX4(140)
|
|
|
|
#define VMRGLB VX4(268)
|
|
|
|
#define VMRGLH VX4(332)
|
|
|
|
#define VMRGLW VX4(396)
|
|
|
|
|
|
|
|
#define VPKUHUM VX4(14)
|
|
|
|
#define VPKUWUM VX4(78)
|
2019-06-23 20:04:44 +03:00
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
#define VAND VX4(1028)
|
|
|
|
#define VANDC VX4(1092)
|
|
|
|
#define VNOR VX4(1284)
|
|
|
|
#define VOR VX4(1156)
|
|
|
|
#define VXOR VX4(1220)
|
2019-09-30 06:39:24 +03:00
|
|
|
#define VEQV VX4(1668) /* v2.07 */
|
|
|
|
#define VNAND VX4(1412) /* v2.07 */
|
|
|
|
#define VORC VX4(1348) /* v2.07 */
|
2019-06-23 20:04:38 +03:00
|
|
|
|
|
|
|
#define VSPLTB VX4(524)
|
|
|
|
#define VSPLTH VX4(588)
|
|
|
|
#define VSPLTW VX4(652)
|
|
|
|
#define VSPLTISB VX4(780)
|
|
|
|
#define VSPLTISH VX4(844)
|
|
|
|
#define VSPLTISW VX4(908)
|
|
|
|
|
|
|
|
#define VSLDOI VX4(44)
|
|
|
|
|
2019-06-23 20:04:47 +03:00
|
|
|
#define XXPERMDI (OPCD(60) | (10 << 3) | 7) /* v2.06, force ax=bx=tx=1 */
|
|
|
|
#define XXSEL (OPCD(60) | (3 << 4) | 0xf) /* v2.06, force ax=bx=cx=tx=1 */
|
2019-09-30 07:44:44 +03:00
|
|
|
#define XXSPLTIB (OPCD(60) | (360 << 1) | 1) /* v3.00, force tx=1 */
|
2019-06-23 20:04:47 +03:00
|
|
|
|
2019-09-30 06:59:46 +03:00
|
|
|
#define MFVSRD (XO31(51) | 1) /* v2.07, force sx=1 */
|
|
|
|
#define MFVSRWZ (XO31(115) | 1) /* v2.07, force sx=1 */
|
|
|
|
#define MTVSRD (XO31(179) | 1) /* v2.07, force tx=1 */
|
|
|
|
#define MTVSRWZ (XO31(243) | 1) /* v2.07, force tx=1 */
|
2019-09-30 07:44:44 +03:00
|
|
|
#define MTVSRDD (XO31(435) | 1) /* v3.00, force tx=1 */
|
|
|
|
#define MTVSRWS (XO31(403) | 1) /* v3.00, force tx=1 */
|
2019-09-30 06:59:46 +03:00
|
|
|
|
2008-07-23 23:17:46 +04:00
|
|
|
#define RT(r) ((r)<<21)
|
|
|
|
#define RS(r) ((r)<<21)
|
|
|
|
#define RA(r) ((r)<<16)
|
|
|
|
#define RB(r) ((r)<<11)
|
|
|
|
#define TO(t) ((t)<<21)
|
|
|
|
#define SH(s) ((s)<<11)
|
|
|
|
#define MB(b) ((b)<<6)
|
|
|
|
#define ME(e) ((e)<<1)
|
|
|
|
#define BO(o) ((o)<<21)
|
|
|
|
#define MB64(b) ((b)<<5)
|
2013-04-03 02:09:52 +04:00
|
|
|
#define FXM(b) (1 << (19 - (b)))
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2019-06-23 20:04:37 +03:00
|
|
|
#define VRT(r) (((r) & 31) << 21)
|
|
|
|
#define VRA(r) (((r) & 31) << 16)
|
|
|
|
#define VRB(r) (((r) & 31) << 11)
|
|
|
|
#define VRC(r) (((r) & 31) << 6)
|
|
|
|
|
2008-07-23 23:17:46 +04:00
|
|
|
#define LK 1
|
|
|
|
|
2013-02-02 04:08:50 +04:00
|
|
|
#define TAB(t, a, b) (RT(t) | RA(a) | RB(b))
|
|
|
|
#define SAB(s, a, b) (RS(s) | RA(a) | RB(b))
|
|
|
|
#define TAI(s, a, i) (RT(s) | RA(a) | ((i) & 0xffff))
|
|
|
|
#define SAI(s, a, i) (RS(s) | RA(a) | ((i) & 0xffff))
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
#define BF(n) ((n)<<23)
|
|
|
|
#define BI(n, c) (((c)+((n)*4))<<16)
|
|
|
|
#define BT(n, c) (((c)+((n)*4))<<21)
|
|
|
|
#define BA(n, c) (((c)+((n)*4))<<16)
|
|
|
|
#define BB(n, c) (((c)+((n)*4))<<11)
|
2013-04-03 02:16:10 +04:00
|
|
|
#define BC_(n, c) (((c)+((n)*4))<<6)
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2013-08-31 16:14:53 +04:00
|
|
|
#define BO_COND_TRUE BO(12)
|
|
|
|
#define BO_COND_FALSE BO( 4)
|
|
|
|
#define BO_ALWAYS BO(20)
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
enum {
|
|
|
|
CR_LT,
|
|
|
|
CR_GT,
|
|
|
|
CR_EQ,
|
|
|
|
CR_SO
|
|
|
|
};
|
|
|
|
|
2012-09-25 01:21:40 +04:00
|
|
|
static const uint32_t tcg_to_bc[] = {
|
2013-08-31 16:14:53 +04:00
|
|
|
[TCG_COND_EQ] = BC | BI(7, CR_EQ) | BO_COND_TRUE,
|
|
|
|
[TCG_COND_NE] = BC | BI(7, CR_EQ) | BO_COND_FALSE,
|
|
|
|
[TCG_COND_LT] = BC | BI(7, CR_LT) | BO_COND_TRUE,
|
|
|
|
[TCG_COND_GE] = BC | BI(7, CR_LT) | BO_COND_FALSE,
|
|
|
|
[TCG_COND_LE] = BC | BI(7, CR_GT) | BO_COND_FALSE,
|
|
|
|
[TCG_COND_GT] = BC | BI(7, CR_GT) | BO_COND_TRUE,
|
|
|
|
[TCG_COND_LTU] = BC | BI(7, CR_LT) | BO_COND_TRUE,
|
|
|
|
[TCG_COND_GEU] = BC | BI(7, CR_LT) | BO_COND_FALSE,
|
|
|
|
[TCG_COND_LEU] = BC | BI(7, CR_GT) | BO_COND_FALSE,
|
|
|
|
[TCG_COND_GTU] = BC | BI(7, CR_GT) | BO_COND_TRUE,
|
2008-07-23 23:17:46 +04:00
|
|
|
};
|
|
|
|
|
2013-04-03 02:16:10 +04:00
|
|
|
/* The low bit here is set if the RA and RB fields must be inverted. */
|
|
|
|
static const uint32_t tcg_to_isel[] = {
|
|
|
|
[TCG_COND_EQ] = ISEL | BC_(7, CR_EQ),
|
|
|
|
[TCG_COND_NE] = ISEL | BC_(7, CR_EQ) | 1,
|
|
|
|
[TCG_COND_LT] = ISEL | BC_(7, CR_LT),
|
|
|
|
[TCG_COND_GE] = ISEL | BC_(7, CR_LT) | 1,
|
|
|
|
[TCG_COND_LE] = ISEL | BC_(7, CR_GT) | 1,
|
|
|
|
[TCG_COND_GT] = ISEL | BC_(7, CR_GT),
|
|
|
|
[TCG_COND_LTU] = ISEL | BC_(7, CR_LT),
|
|
|
|
[TCG_COND_GEU] = ISEL | BC_(7, CR_LT) | 1,
|
|
|
|
[TCG_COND_LEU] = ISEL | BC_(7, CR_GT) | 1,
|
|
|
|
[TCG_COND_GTU] = ISEL | BC_(7, CR_GT),
|
|
|
|
};
|
|
|
|
|
2018-11-30 22:52:48 +03:00
|
|
|
static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
|
2018-01-10 10:31:46 +03:00
|
|
|
intptr_t value, intptr_t addend)
|
|
|
|
{
|
2020-11-04 21:17:46 +03:00
|
|
|
const tcg_insn_unit *target;
|
2019-06-23 20:04:38 +03:00
|
|
|
int16_t lo;
|
|
|
|
int32_t hi;
|
2018-01-10 10:31:46 +03:00
|
|
|
|
|
|
|
value += addend;
|
2020-11-04 21:17:46 +03:00
|
|
|
target = (const tcg_insn_unit *)value;
|
2018-01-10 10:31:46 +03:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case R_PPC_REL14:
|
2018-12-01 00:25:13 +03:00
|
|
|
return reloc_pc14(code_ptr, target);
|
2018-01-10 10:31:46 +03:00
|
|
|
case R_PPC_REL24:
|
2018-12-01 00:25:13 +03:00
|
|
|
return reloc_pc24(code_ptr, target);
|
2018-01-10 10:31:46 +03:00
|
|
|
case R_PPC_ADDR16:
|
2019-04-22 20:12:33 +03:00
|
|
|
/*
|
|
|
|
* We are (slightly) abusing this relocation type. In particular,
|
|
|
|
* assert that the low 2 bits are zero, and do not modify them.
|
|
|
|
* That way we can use this with LD et al that have opcode bits
|
|
|
|
* in the low 2 bits of the insn.
|
|
|
|
*/
|
|
|
|
if ((value & 3) || value != (int16_t)value) {
|
|
|
|
return false;
|
2018-01-10 10:31:46 +03:00
|
|
|
}
|
2019-04-22 20:12:33 +03:00
|
|
|
*code_ptr = (*code_ptr & ~0xfffc) | (value & 0xfffc);
|
2018-01-10 10:31:46 +03:00
|
|
|
break;
|
2019-06-23 20:04:38 +03:00
|
|
|
case R_PPC_ADDR32:
|
|
|
|
/*
|
|
|
|
* We are abusing this relocation type. Again, this points to
|
|
|
|
* a pair of insns, lis + load. This is an absolute address
|
|
|
|
* relocation for PPC32 so the lis cannot be removed.
|
|
|
|
*/
|
|
|
|
lo = value;
|
|
|
|
hi = value - lo;
|
|
|
|
if (hi + lo != value) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
code_ptr[0] = deposit32(code_ptr[0], 0, 16, hi >> 16);
|
|
|
|
code_ptr[1] = deposit32(code_ptr[1], 0, 16, lo);
|
|
|
|
break;
|
2018-01-10 10:31:46 +03:00
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
2018-11-30 22:52:48 +03:00
|
|
|
return true;
|
2018-01-10 10:31:46 +03:00
|
|
|
}
|
|
|
|
|
2023-06-26 21:02:18 +03:00
|
|
|
/* Ensure that the prefixed instruction does not cross a 64-byte boundary. */
|
|
|
|
static bool tcg_out_need_prefix_align(TCGContext *s)
|
|
|
|
{
|
|
|
|
return ((uintptr_t)s->code_ptr & 0x3f) == 0x3c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tcg_out_prefix_align(TCGContext *s)
|
|
|
|
{
|
|
|
|
if (tcg_out_need_prefix_align(s)) {
|
|
|
|
tcg_out32(s, NOP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static ptrdiff_t tcg_pcrel_diff_for_prefix(TCGContext *s, const void *target)
|
|
|
|
{
|
|
|
|
return tcg_pcrel_diff(s, target) - (tcg_out_need_prefix_align(s) ? 4 : 0);
|
|
|
|
}
|
|
|
|
|
2023-08-04 20:16:32 +03:00
|
|
|
/* Output Type 00 Prefix - 8-Byte Load/Store Form (8LS:D) */
|
|
|
|
static void tcg_out_8ls_d(TCGContext *s, tcg_insn_unit opc, unsigned rt,
|
|
|
|
unsigned ra, tcg_target_long imm, bool r)
|
|
|
|
{
|
|
|
|
tcg_insn_unit p, i;
|
|
|
|
|
|
|
|
p = OPCD(1) | (r << 20) | ((imm >> 16) & 0x3ffff);
|
|
|
|
i = opc | TAI(rt, ra, imm);
|
|
|
|
|
|
|
|
tcg_out_prefix_align(s);
|
|
|
|
tcg_out32(s, p);
|
|
|
|
tcg_out32(s, i);
|
|
|
|
}
|
|
|
|
|
2023-06-26 21:02:18 +03:00
|
|
|
/* Output Type 10 Prefix - Modified Load/Store Form (MLS:D) */
|
|
|
|
static void tcg_out_mls_d(TCGContext *s, tcg_insn_unit opc, unsigned rt,
|
|
|
|
unsigned ra, tcg_target_long imm, bool r)
|
|
|
|
{
|
|
|
|
tcg_insn_unit p, i;
|
|
|
|
|
|
|
|
p = OPCD(1) | (2 << 24) | (r << 20) | ((imm >> 16) & 0x3ffff);
|
|
|
|
i = opc | TAI(rt, ra, imm);
|
|
|
|
|
|
|
|
tcg_out_prefix_align(s);
|
|
|
|
tcg_out32(s, p);
|
|
|
|
tcg_out32(s, i);
|
|
|
|
}
|
|
|
|
|
2014-03-28 17:53:53 +04:00
|
|
|
static void tcg_out_mem_long(TCGContext *s, int opi, int opx, TCGReg rt,
|
|
|
|
TCGReg base, tcg_target_long offset);
|
|
|
|
|
2019-03-16 20:48:18 +03:00
|
|
|
static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2019-06-23 20:04:38 +03:00
|
|
|
if (ret == arg) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
switch (type) {
|
|
|
|
case TCG_TYPE_I64:
|
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
|
|
|
|
/* fallthru */
|
|
|
|
case TCG_TYPE_I32:
|
2019-09-30 06:59:46 +03:00
|
|
|
if (ret < TCG_REG_V0) {
|
|
|
|
if (arg < TCG_REG_V0) {
|
|
|
|
tcg_out32(s, OR | SAB(arg, ret, arg));
|
|
|
|
break;
|
|
|
|
} else if (have_isa_2_07) {
|
|
|
|
tcg_out32(s, (type == TCG_TYPE_I32 ? MFVSRWZ : MFVSRD)
|
|
|
|
| VRT(arg) | RA(ret));
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
/* Altivec does not support vector->integer moves. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (arg < TCG_REG_V0) {
|
|
|
|
if (have_isa_2_07) {
|
|
|
|
tcg_out32(s, (type == TCG_TYPE_I32 ? MTVSRWZ : MTVSRD)
|
|
|
|
| VRT(ret) | RA(arg));
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
/* Altivec does not support integer->vector moves. */
|
|
|
|
return false;
|
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
}
|
|
|
|
/* fallthru */
|
|
|
|
case TCG_TYPE_V64:
|
|
|
|
case TCG_TYPE_V128:
|
|
|
|
tcg_debug_assert(ret >= TCG_REG_V0 && arg >= TCG_REG_V0);
|
|
|
|
tcg_out32(s, VOR | VRT(ret) | VRA(arg) | VRB(arg));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
2013-07-31 08:26:04 +04:00
|
|
|
}
|
2019-03-16 20:48:18 +03:00
|
|
|
return true;
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2013-02-02 02:48:37 +04:00
|
|
|
static inline void tcg_out_rld(TCGContext *s, int op, TCGReg ra, TCGReg rs,
|
|
|
|
int sh, int mb)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2016-04-21 11:48:49 +03:00
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
|
2013-08-31 16:14:53 +04:00
|
|
|
sh = SH(sh & 0x1f) | (((sh >> 5) & 1) << 1);
|
|
|
|
mb = MB64((mb >> 5) | ((mb << 1) & 0x3f));
|
|
|
|
tcg_out32(s, op | RA(ra) | RS(rs) | sh | mb);
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2013-02-02 03:00:45 +04:00
|
|
|
static inline void tcg_out_rlw(TCGContext *s, int op, TCGReg ra, TCGReg rs,
|
|
|
|
int sh, int mb, int me)
|
|
|
|
{
|
|
|
|
tcg_out32(s, op | RA(ra) | RS(rs) | SH(sh) | MB(mb) | ME(me));
|
|
|
|
}
|
|
|
|
|
2023-04-05 21:17:01 +03:00
|
|
|
static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg dst, TCGReg src)
|
2021-06-13 18:52:30 +03:00
|
|
|
{
|
|
|
|
tcg_out32(s, EXTSB | RA(dst) | RS(src));
|
|
|
|
}
|
|
|
|
|
2023-04-05 23:26:51 +03:00
|
|
|
static void tcg_out_ext8u(TCGContext *s, TCGReg dst, TCGReg src)
|
|
|
|
{
|
|
|
|
tcg_out32(s, ANDI | SAI(src, dst, 0xff));
|
|
|
|
}
|
|
|
|
|
2023-04-06 00:49:59 +03:00
|
|
|
static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg dst, TCGReg src)
|
2021-06-13 18:52:30 +03:00
|
|
|
{
|
|
|
|
tcg_out32(s, EXTSH | RA(dst) | RS(src));
|
|
|
|
}
|
|
|
|
|
2023-04-06 02:25:22 +03:00
|
|
|
static void tcg_out_ext16u(TCGContext *s, TCGReg dst, TCGReg src)
|
2021-06-13 20:45:07 +03:00
|
|
|
{
|
|
|
|
tcg_out32(s, ANDI | SAI(src, dst, 0xffff));
|
|
|
|
}
|
|
|
|
|
2023-04-06 03:50:09 +03:00
|
|
|
static void tcg_out_ext32s(TCGContext *s, TCGReg dst, TCGReg src)
|
2021-06-13 18:52:30 +03:00
|
|
|
{
|
2023-04-06 03:50:09 +03:00
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
|
2021-06-13 18:52:30 +03:00
|
|
|
tcg_out32(s, EXTSW | RA(dst) | RS(src));
|
|
|
|
}
|
|
|
|
|
2023-04-06 04:07:05 +03:00
|
|
|
static void tcg_out_ext32u(TCGContext *s, TCGReg dst, TCGReg src)
|
2013-02-02 03:06:30 +04:00
|
|
|
{
|
2023-04-06 04:07:05 +03:00
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
|
2013-02-02 03:06:30 +04:00
|
|
|
tcg_out_rld(s, RLDICL, dst, src, 0, 32);
|
|
|
|
}
|
|
|
|
|
2023-04-06 04:30:56 +03:00
|
|
|
static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg dst, TCGReg src)
|
|
|
|
{
|
|
|
|
tcg_out_ext32s(s, dst, src);
|
|
|
|
}
|
|
|
|
|
2023-04-06 04:56:28 +03:00
|
|
|
static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg dst, TCGReg src)
|
|
|
|
{
|
|
|
|
tcg_out_ext32u(s, dst, src);
|
|
|
|
}
|
|
|
|
|
2023-04-06 05:58:35 +03:00
|
|
|
static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rn)
|
|
|
|
{
|
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
|
|
|
|
tcg_out_mov(s, TCG_TYPE_I32, rd, rn);
|
|
|
|
}
|
|
|
|
|
2014-03-27 05:10:43 +04:00
|
|
|
static inline void tcg_out_shli32(TCGContext *s, TCGReg dst, TCGReg src, int c)
|
|
|
|
{
|
|
|
|
tcg_out_rlw(s, RLWINM, dst, src, c, 0, 31 - c);
|
|
|
|
}
|
|
|
|
|
2013-02-02 03:12:14 +04:00
|
|
|
static inline void tcg_out_shli64(TCGContext *s, TCGReg dst, TCGReg src, int c)
|
|
|
|
{
|
|
|
|
tcg_out_rld(s, RLDICR, dst, src, c, 63 - c);
|
|
|
|
}
|
|
|
|
|
2021-06-13 19:04:40 +03:00
|
|
|
static inline void tcg_out_sari32(TCGContext *s, TCGReg dst, TCGReg src, int c)
|
|
|
|
{
|
|
|
|
/* Limit immediate shift count lest we create an illegal insn. */
|
|
|
|
tcg_out32(s, SRAWI | RA(dst) | RS(src) | SH(c & 31));
|
|
|
|
}
|
|
|
|
|
2014-03-27 05:10:43 +04:00
|
|
|
static inline void tcg_out_shri32(TCGContext *s, TCGReg dst, TCGReg src, int c)
|
|
|
|
{
|
|
|
|
tcg_out_rlw(s, RLWINM, dst, src, 32 - c, c, 31);
|
|
|
|
}
|
|
|
|
|
2013-02-02 03:19:05 +04:00
|
|
|
static inline void tcg_out_shri64(TCGContext *s, TCGReg dst, TCGReg src, int c)
|
|
|
|
{
|
|
|
|
tcg_out_rld(s, RLDICL, dst, src, 64 - c, c);
|
|
|
|
}
|
|
|
|
|
2021-06-13 19:04:40 +03:00
|
|
|
static inline void tcg_out_sari64(TCGContext *s, TCGReg dst, TCGReg src, int c)
|
|
|
|
{
|
|
|
|
tcg_out32(s, SRADI | RA(dst) | RS(src) | SH(c & 0x1f) | ((c >> 4) & 2));
|
|
|
|
}
|
|
|
|
|
2023-08-15 20:04:42 +03:00
|
|
|
static void tcg_out_addpcis(TCGContext *s, TCGReg dst, intptr_t imm)
|
|
|
|
{
|
|
|
|
uint32_t d0, d1, d2;
|
|
|
|
|
|
|
|
tcg_debug_assert((imm & 0xffff) == 0);
|
|
|
|
tcg_debug_assert(imm == (int32_t)imm);
|
|
|
|
|
|
|
|
d2 = extract32(imm, 16, 1);
|
|
|
|
d1 = extract32(imm, 17, 5);
|
|
|
|
d0 = extract32(imm, 22, 10);
|
|
|
|
tcg_out32(s, ADDPCIS | RT(dst) | (d1 << 16) | (d0 << 6) | d2);
|
|
|
|
}
|
|
|
|
|
2021-06-13 19:48:02 +03:00
|
|
|
static void tcg_out_bswap16(TCGContext *s, TCGReg dst, TCGReg src, int flags)
|
2021-06-13 19:16:25 +03:00
|
|
|
{
|
|
|
|
TCGReg tmp = dst == src ? TCG_REG_R0 : dst;
|
|
|
|
|
2021-06-13 20:45:07 +03:00
|
|
|
if (have_isa_3_10) {
|
|
|
|
tcg_out32(s, BRH | RA(dst) | RS(src));
|
|
|
|
if (flags & TCG_BSWAP_OS) {
|
2023-04-06 00:49:59 +03:00
|
|
|
tcg_out_ext16s(s, TCG_TYPE_REG, dst, dst);
|
2021-06-13 20:45:07 +03:00
|
|
|
} else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
|
|
|
|
tcg_out_ext16u(s, dst, dst);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-13 19:16:25 +03:00
|
|
|
/*
|
|
|
|
* In the following,
|
|
|
|
* dep(a, b, m) -> (a & ~m) | (b & m)
|
|
|
|
*
|
|
|
|
* Begin with: src = xxxxabcd
|
|
|
|
*/
|
|
|
|
/* tmp = rol32(src, 24) & 0x000000ff = 0000000c */
|
|
|
|
tcg_out_rlw(s, RLWINM, tmp, src, 24, 24, 31);
|
|
|
|
/* tmp = dep(tmp, rol32(src, 8), 0x0000ff00) = 000000dc */
|
|
|
|
tcg_out_rlw(s, RLWIMI, tmp, src, 8, 16, 23);
|
|
|
|
|
2021-06-13 19:48:02 +03:00
|
|
|
if (flags & TCG_BSWAP_OS) {
|
2023-04-06 00:49:59 +03:00
|
|
|
tcg_out_ext16s(s, TCG_TYPE_REG, dst, tmp);
|
2021-06-13 19:48:02 +03:00
|
|
|
} else {
|
|
|
|
tcg_out_mov(s, TCG_TYPE_REG, dst, tmp);
|
|
|
|
}
|
2021-06-13 19:16:25 +03:00
|
|
|
}
|
|
|
|
|
2021-06-13 19:48:02 +03:00
|
|
|
static void tcg_out_bswap32(TCGContext *s, TCGReg dst, TCGReg src, int flags)
|
2021-06-13 19:27:18 +03:00
|
|
|
{
|
|
|
|
TCGReg tmp = dst == src ? TCG_REG_R0 : dst;
|
|
|
|
|
2021-06-13 20:45:07 +03:00
|
|
|
if (have_isa_3_10) {
|
|
|
|
tcg_out32(s, BRW | RA(dst) | RS(src));
|
|
|
|
if (flags & TCG_BSWAP_OS) {
|
|
|
|
tcg_out_ext32s(s, dst, dst);
|
|
|
|
} else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
|
|
|
|
tcg_out_ext32u(s, dst, dst);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-13 19:27:18 +03:00
|
|
|
/*
|
|
|
|
* Stolen from gcc's builtin_bswap32.
|
|
|
|
* In the following,
|
|
|
|
* dep(a, b, m) -> (a & ~m) | (b & m)
|
|
|
|
*
|
|
|
|
* Begin with: src = xxxxabcd
|
|
|
|
*/
|
|
|
|
/* tmp = rol32(src, 8) & 0xffffffff = 0000bcda */
|
|
|
|
tcg_out_rlw(s, RLWINM, tmp, src, 8, 0, 31);
|
|
|
|
/* tmp = dep(tmp, rol32(src, 24), 0xff000000) = 0000dcda */
|
|
|
|
tcg_out_rlw(s, RLWIMI, tmp, src, 24, 0, 7);
|
|
|
|
/* tmp = dep(tmp, rol32(src, 24), 0x0000ff00) = 0000dcba */
|
|
|
|
tcg_out_rlw(s, RLWIMI, tmp, src, 24, 16, 23);
|
|
|
|
|
2021-06-13 19:48:02 +03:00
|
|
|
if (flags & TCG_BSWAP_OS) {
|
|
|
|
tcg_out_ext32s(s, dst, tmp);
|
|
|
|
} else {
|
|
|
|
tcg_out_mov(s, TCG_TYPE_REG, dst, tmp);
|
|
|
|
}
|
2021-06-13 19:27:18 +03:00
|
|
|
}
|
|
|
|
|
2021-06-13 19:37:05 +03:00
|
|
|
static void tcg_out_bswap64(TCGContext *s, TCGReg dst, TCGReg src)
|
|
|
|
{
|
|
|
|
TCGReg t0 = dst == src ? TCG_REG_R0 : dst;
|
|
|
|
TCGReg t1 = dst == src ? dst : TCG_REG_R0;
|
|
|
|
|
2021-06-13 20:45:07 +03:00
|
|
|
if (have_isa_3_10) {
|
|
|
|
tcg_out32(s, BRD | RA(dst) | RS(src));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-13 19:37:05 +03:00
|
|
|
/*
|
|
|
|
* In the following,
|
|
|
|
* dep(a, b, m) -> (a & ~m) | (b & m)
|
|
|
|
*
|
|
|
|
* Begin with: src = abcdefgh
|
|
|
|
*/
|
|
|
|
/* t0 = rol32(src, 8) & 0xffffffff = 0000fghe */
|
|
|
|
tcg_out_rlw(s, RLWINM, t0, src, 8, 0, 31);
|
|
|
|
/* t0 = dep(t0, rol32(src, 24), 0xff000000) = 0000hghe */
|
|
|
|
tcg_out_rlw(s, RLWIMI, t0, src, 24, 0, 7);
|
|
|
|
/* t0 = dep(t0, rol32(src, 24), 0x0000ff00) = 0000hgfe */
|
|
|
|
tcg_out_rlw(s, RLWIMI, t0, src, 24, 16, 23);
|
|
|
|
|
|
|
|
/* t0 = rol64(t0, 32) = hgfe0000 */
|
|
|
|
tcg_out_rld(s, RLDICL, t0, t0, 32, 0);
|
|
|
|
/* t1 = rol64(src, 32) = efghabcd */
|
|
|
|
tcg_out_rld(s, RLDICL, t1, src, 32, 0);
|
|
|
|
|
|
|
|
/* t0 = dep(t0, rol32(t1, 24), 0xffffffff) = hgfebcda */
|
|
|
|
tcg_out_rlw(s, RLWIMI, t0, t1, 8, 0, 31);
|
|
|
|
/* t0 = dep(t0, rol32(t1, 24), 0xff000000) = hgfedcda */
|
|
|
|
tcg_out_rlw(s, RLWIMI, t0, t1, 24, 0, 7);
|
|
|
|
/* t0 = dep(t0, rol32(t1, 24), 0x0000ff00) = hgfedcba */
|
|
|
|
tcg_out_rlw(s, RLWIMI, t0, t1, 24, 16, 23);
|
|
|
|
|
|
|
|
tcg_out_mov(s, TCG_TYPE_REG, dst, t0);
|
|
|
|
}
|
|
|
|
|
2017-07-31 07:54:02 +03:00
|
|
|
/* Emit a move into ret of arg, if it can be done in one insn. */
|
|
|
|
static bool tcg_out_movi_one(TCGContext *s, TCGReg ret, tcg_target_long arg)
|
|
|
|
{
|
|
|
|
if (arg == (int16_t)arg) {
|
|
|
|
tcg_out32(s, ADDI | TAI(ret, 0, arg));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (arg == (int32_t)arg && (arg & 0xffff) == 0) {
|
|
|
|
tcg_out32(s, ADDIS | TAI(ret, 0, arg >> 16));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-07-31 07:16:10 +03:00
|
|
|
static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret,
|
|
|
|
tcg_target_long arg, bool in_prologue)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2017-07-31 07:16:10 +03:00
|
|
|
intptr_t tb_diff;
|
2017-07-31 07:54:02 +03:00
|
|
|
tcg_target_long tmp;
|
|
|
|
int shift;
|
2017-07-31 07:16:10 +03:00
|
|
|
|
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
|
|
|
|
|
|
|
|
if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) {
|
|
|
|
arg = (int32_t)arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load 16-bit immediates with one insn. */
|
2017-07-31 07:54:02 +03:00
|
|
|
if (tcg_out_movi_one(s, ret, arg)) {
|
2017-07-31 07:16:10 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load addresses within the TB with one insn. */
|
2023-08-15 19:58:19 +03:00
|
|
|
tb_diff = ppc_tbrel_diff(s, (void *)arg);
|
2017-07-31 07:16:10 +03:00
|
|
|
if (!in_prologue && USE_REG_TB && tb_diff == (int16_t)tb_diff) {
|
|
|
|
tcg_out32(s, ADDI | TAI(ret, TCG_REG_TB, tb_diff));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-06-26 21:02:18 +03:00
|
|
|
/*
|
|
|
|
* Load values up to 34 bits, and pc-relative addresses,
|
|
|
|
* with one prefixed insn.
|
|
|
|
*/
|
|
|
|
if (have_isa_3_10) {
|
|
|
|
if (arg == sextract64(arg, 0, 34)) {
|
|
|
|
/* pli ret,value = paddi ret,0,value,0 */
|
|
|
|
tcg_out_mls_d(s, ADDI, ret, 0, arg, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = tcg_pcrel_diff_for_prefix(s, (void *)arg);
|
|
|
|
if (tmp == sextract64(tmp, 0, 34)) {
|
|
|
|
/* pla ret,value = paddi ret,0,value,1 */
|
|
|
|
tcg_out_mls_d(s, ADDI, ret, 0, tmp, 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-31 07:54:02 +03:00
|
|
|
/* Load 32-bit immediates with two insns. Note that we've already
|
|
|
|
eliminated bare ADDIS, so we know both insns are required. */
|
2017-07-31 07:16:10 +03:00
|
|
|
if (TCG_TARGET_REG_BITS == 32 || arg == (int32_t)arg) {
|
2013-02-02 04:08:50 +04:00
|
|
|
tcg_out32(s, ADDIS | TAI(ret, 0, arg >> 16));
|
2017-07-31 07:54:02 +03:00
|
|
|
tcg_out32(s, ORI | SAI(ret, ret, arg));
|
2017-07-31 07:16:10 +03:00
|
|
|
return;
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
2017-07-31 07:16:10 +03:00
|
|
|
if (arg == (uint32_t)arg && !(arg & 0x8000)) {
|
2013-02-01 03:52:49 +04:00
|
|
|
tcg_out32(s, ADDI | TAI(ret, 0, arg));
|
|
|
|
tcg_out32(s, ORIS | SAI(ret, ret, arg >> 16));
|
2017-07-31 07:16:10 +03:00
|
|
|
return;
|
|
|
|
}
|
2014-03-28 17:53:53 +04:00
|
|
|
|
2017-07-31 07:54:02 +03:00
|
|
|
/* Load masked 16-bit value. */
|
|
|
|
if (arg > 0 && (arg & 0x8000)) {
|
|
|
|
tmp = arg | 0x7fff;
|
|
|
|
if ((tmp & (tmp + 1)) == 0) {
|
|
|
|
int mb = clz64(tmp + 1) + 1;
|
|
|
|
tcg_out32(s, ADDI | TAI(ret, 0, arg));
|
|
|
|
tcg_out_rld(s, RLDICL, ret, ret, 0, mb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load common masks with 2 insns. */
|
|
|
|
shift = ctz64(arg);
|
|
|
|
tmp = arg >> shift;
|
|
|
|
if (tmp == (int16_t)tmp) {
|
|
|
|
tcg_out32(s, ADDI | TAI(ret, 0, tmp));
|
|
|
|
tcg_out_shli64(s, ret, ret, shift);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
shift = clz64(arg);
|
|
|
|
if (tcg_out_movi_one(s, ret, arg << shift)) {
|
|
|
|
tcg_out_shri64(s, ret, ret, shift);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-15 20:19:37 +03:00
|
|
|
/* Load addresses within 2GB with 2 insns. */
|
|
|
|
if (have_isa_3_00) {
|
|
|
|
intptr_t hi = tcg_pcrel_diff(s, (void *)arg) - 4;
|
|
|
|
int16_t lo = hi;
|
|
|
|
|
|
|
|
hi -= lo;
|
|
|
|
if (hi == (int32_t)hi) {
|
|
|
|
tcg_out_addpcis(s, TCG_REG_TMP2, hi);
|
|
|
|
tcg_out32(s, ADDI | TAI(ret, TCG_REG_TMP2, lo));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-31 07:16:10 +03:00
|
|
|
/* Load addresses within 2GB of TB with 2 (or rarely 3) insns. */
|
|
|
|
if (!in_prologue && USE_REG_TB && tb_diff == (int32_t)tb_diff) {
|
|
|
|
tcg_out_mem_long(s, ADDI, ADD, ret, TCG_REG_TB, tb_diff);
|
|
|
|
return;
|
|
|
|
}
|
2014-03-28 17:53:53 +04:00
|
|
|
|
2017-07-31 09:03:03 +03:00
|
|
|
/* Use the constant pool, if possible. */
|
|
|
|
if (!in_prologue && USE_REG_TB) {
|
|
|
|
new_pool_label(s, arg, R_PPC_ADDR16, s->code_ptr,
|
2023-08-15 19:58:19 +03:00
|
|
|
ppc_tbrel_diff(s, NULL));
|
2019-04-22 20:12:33 +03:00
|
|
|
tcg_out32(s, LD | TAI(ret, TCG_REG_TB, 0));
|
2017-07-31 09:03:03 +03:00
|
|
|
return;
|
|
|
|
}
|
2023-08-15 20:35:21 +03:00
|
|
|
if (have_isa_3_00) {
|
|
|
|
tcg_out_addpcis(s, TCG_REG_TMP2, 0);
|
|
|
|
new_pool_label(s, arg, R_PPC_REL14, s->code_ptr, 0);
|
|
|
|
tcg_out32(s, LD | TAI(ret, TCG_REG_TMP2, 0));
|
|
|
|
return;
|
|
|
|
}
|
2017-07-31 09:03:03 +03:00
|
|
|
|
2017-07-31 07:54:02 +03:00
|
|
|
tmp = arg >> 31 >> 1;
|
|
|
|
tcg_out_movi(s, TCG_TYPE_I32, ret, tmp);
|
|
|
|
if (tmp) {
|
2017-07-31 07:16:10 +03:00
|
|
|
tcg_out_shli64(s, ret, ret, 32);
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
2017-07-31 07:16:10 +03:00
|
|
|
if (arg & 0xffff0000) {
|
|
|
|
tcg_out32(s, ORIS | SAI(ret, ret, arg >> 16));
|
|
|
|
}
|
|
|
|
if (arg & 0xffff) {
|
|
|
|
tcg_out32(s, ORI | SAI(ret, ret, arg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 11:02:08 +03:00
|
|
|
static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
|
|
|
|
TCGReg ret, int64_t val)
|
2017-07-31 07:16:10 +03:00
|
|
|
{
|
2019-06-23 20:04:38 +03:00
|
|
|
uint32_t load_insn;
|
|
|
|
int rel, low;
|
|
|
|
intptr_t add;
|
|
|
|
|
2020-03-31 11:02:08 +03:00
|
|
|
switch (vece) {
|
|
|
|
case MO_8:
|
|
|
|
low = (int8_t)val;
|
|
|
|
if (low >= -16 && low < 16) {
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_out32(s, VSPLTISB | VRT(ret) | ((val & 31) << 16));
|
|
|
|
return;
|
|
|
|
}
|
2020-03-31 11:02:08 +03:00
|
|
|
if (have_isa_3_00) {
|
|
|
|
tcg_out32(s, XXSPLTIB | VRT(ret) | ((val & 0xff) << 11));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MO_16:
|
|
|
|
low = (int16_t)val;
|
|
|
|
if (low >= -16 && low < 16) {
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_out32(s, VSPLTISH | VRT(ret) | ((val & 31) << 16));
|
|
|
|
return;
|
|
|
|
}
|
2020-03-31 11:02:08 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MO_32:
|
|
|
|
low = (int32_t)val;
|
|
|
|
if (low >= -16 && low < 16) {
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_out32(s, VSPLTISW | VRT(ret) | ((val & 31) << 16));
|
|
|
|
return;
|
|
|
|
}
|
2020-03-31 11:02:08 +03:00
|
|
|
break;
|
2019-09-30 07:44:44 +03:00
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise we must load the value from the constant pool.
|
|
|
|
*/
|
|
|
|
if (USE_REG_TB) {
|
|
|
|
rel = R_PPC_ADDR16;
|
2023-08-15 19:58:19 +03:00
|
|
|
add = ppc_tbrel_diff(s, NULL);
|
2023-08-15 20:35:21 +03:00
|
|
|
} else if (have_isa_3_00) {
|
|
|
|
tcg_out_addpcis(s, TCG_REG_TMP1, 0);
|
|
|
|
rel = R_PPC_REL14;
|
|
|
|
add = 0;
|
2019-06-23 20:04:38 +03:00
|
|
|
} else {
|
|
|
|
rel = R_PPC_ADDR32;
|
|
|
|
add = 0;
|
|
|
|
}
|
|
|
|
|
2019-06-23 20:04:47 +03:00
|
|
|
if (have_vsx) {
|
|
|
|
load_insn = type == TCG_TYPE_V64 ? LXSDX : LXVDSX;
|
|
|
|
load_insn |= VRT(ret) | RB(TCG_REG_TMP1);
|
|
|
|
if (TCG_TARGET_REG_BITS == 64) {
|
|
|
|
new_pool_label(s, val, rel, s->code_ptr, add);
|
|
|
|
} else {
|
2020-03-31 11:02:08 +03:00
|
|
|
new_pool_l2(s, rel, s->code_ptr, add, val >> 32, val);
|
2019-06-23 20:04:47 +03:00
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
} else {
|
2019-06-23 20:04:47 +03:00
|
|
|
load_insn = LVX | VRT(ret) | RB(TCG_REG_TMP1);
|
|
|
|
if (TCG_TARGET_REG_BITS == 64) {
|
|
|
|
new_pool_l2(s, rel, s->code_ptr, add, val, val);
|
|
|
|
} else {
|
2020-03-31 11:02:08 +03:00
|
|
|
new_pool_l4(s, rel, s->code_ptr, add,
|
|
|
|
val >> 32, val, val >> 32, val);
|
2019-06-23 20:04:47 +03:00
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (USE_REG_TB) {
|
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_TMP1, 0, 0));
|
|
|
|
load_insn |= RA(TCG_REG_TB);
|
2023-08-15 20:35:21 +03:00
|
|
|
} else if (have_isa_3_00) {
|
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_TMP1, TCG_REG_TMP1, 0));
|
2019-06-23 20:04:38 +03:00
|
|
|
} else {
|
|
|
|
tcg_out32(s, ADDIS | TAI(TCG_REG_TMP1, 0, 0));
|
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_TMP1, TCG_REG_TMP1, 0));
|
|
|
|
}
|
|
|
|
tcg_out32(s, load_insn);
|
2019-06-23 20:04:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg ret,
|
|
|
|
tcg_target_long arg)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case TCG_TYPE_I32:
|
|
|
|
case TCG_TYPE_I64:
|
|
|
|
tcg_debug_assert(ret < TCG_REG_V0);
|
|
|
|
tcg_out_movi_int(s, type, ret, arg, false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2023-04-06 07:39:54 +03:00
|
|
|
static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-18 14:28:04 +03:00
|
|
|
static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs,
|
|
|
|
tcg_target_long imm)
|
|
|
|
{
|
|
|
|
/* This function is only used for passing structs by reference. */
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
2013-02-02 11:58:17 +04:00
|
|
|
static bool mask_operand(uint32_t c, int *mb, int *me)
|
2013-02-02 11:43:42 +04:00
|
|
|
{
|
|
|
|
uint32_t lsb, test;
|
|
|
|
|
|
|
|
/* Accept a bit pattern like:
|
|
|
|
0....01....1
|
|
|
|
1....10....0
|
|
|
|
0..01..10..0
|
|
|
|
Keep track of the transitions. */
|
|
|
|
if (c == 0 || c == -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
test = c;
|
|
|
|
lsb = test & -test;
|
|
|
|
test += lsb;
|
|
|
|
if (test & (test - 1)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
*me = clz32(lsb);
|
|
|
|
*mb = test ? clz32(test & -test) + 1 : 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-02-02 11:58:17 +04:00
|
|
|
static bool mask64_operand(uint64_t c, int *mb, int *me)
|
|
|
|
{
|
|
|
|
uint64_t lsb;
|
|
|
|
|
|
|
|
if (c == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
lsb = c & -c;
|
|
|
|
/* Accept 1..10..0. */
|
|
|
|
if (c == -lsb) {
|
|
|
|
*mb = 0;
|
|
|
|
*me = clz64(lsb);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/* Accept 0..01..1. */
|
|
|
|
if (lsb == 1 && (c & (c + 1)) == 0) {
|
|
|
|
*mb = clz64(c + 1) + 1;
|
|
|
|
*me = 63;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-02-02 11:43:42 +04:00
|
|
|
static void tcg_out_andi32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c)
|
|
|
|
{
|
|
|
|
int mb, me;
|
|
|
|
|
2015-10-03 01:41:01 +03:00
|
|
|
if (mask_operand(c, &mb, &me)) {
|
|
|
|
tcg_out_rlw(s, RLWINM, dst, src, 0, mb, me);
|
|
|
|
} else if ((c & 0xffff) == c) {
|
2013-02-02 11:43:42 +04:00
|
|
|
tcg_out32(s, ANDI | SAI(src, dst, c));
|
|
|
|
return;
|
|
|
|
} else if ((c & 0xffff0000) == c) {
|
|
|
|
tcg_out32(s, ANDIS | SAI(src, dst, c >> 16));
|
|
|
|
return;
|
|
|
|
} else {
|
2013-08-31 16:41:45 +04:00
|
|
|
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R0, c);
|
|
|
|
tcg_out32(s, AND | SAB(src, dst, TCG_REG_R0));
|
2013-02-02 11:43:42 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-02 11:58:17 +04:00
|
|
|
static void tcg_out_andi64(TCGContext *s, TCGReg dst, TCGReg src, uint64_t c)
|
|
|
|
{
|
|
|
|
int mb, me;
|
|
|
|
|
2016-04-21 11:48:49 +03:00
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
|
2015-10-03 01:41:01 +03:00
|
|
|
if (mask64_operand(c, &mb, &me)) {
|
2013-02-02 11:58:17 +04:00
|
|
|
if (mb == 0) {
|
|
|
|
tcg_out_rld(s, RLDICR, dst, src, 0, me);
|
|
|
|
} else {
|
|
|
|
tcg_out_rld(s, RLDICL, dst, src, 0, mb);
|
|
|
|
}
|
2015-10-03 01:41:01 +03:00
|
|
|
} else if ((c & 0xffff) == c) {
|
|
|
|
tcg_out32(s, ANDI | SAI(src, dst, c));
|
|
|
|
return;
|
|
|
|
} else if ((c & 0xffff0000) == c) {
|
|
|
|
tcg_out32(s, ANDIS | SAI(src, dst, c >> 16));
|
|
|
|
return;
|
2013-02-02 11:58:17 +04:00
|
|
|
} else {
|
2013-08-31 16:41:45 +04:00
|
|
|
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R0, c);
|
|
|
|
tcg_out32(s, AND | SAB(src, dst, TCG_REG_R0));
|
2013-02-02 11:58:17 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-02 08:22:05 +04:00
|
|
|
static void tcg_out_zori32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c,
|
|
|
|
int op_lo, int op_hi)
|
|
|
|
{
|
|
|
|
if (c >> 16) {
|
|
|
|
tcg_out32(s, op_hi | SAI(src, dst, c >> 16));
|
|
|
|
src = dst;
|
|
|
|
}
|
|
|
|
if (c & 0xffff) {
|
|
|
|
tcg_out32(s, op_lo | SAI(src, dst, c));
|
|
|
|
src = dst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tcg_out_ori32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c)
|
|
|
|
{
|
|
|
|
tcg_out_zori32(s, dst, src, c, ORI, ORIS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tcg_out_xori32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c)
|
|
|
|
{
|
|
|
|
tcg_out_zori32(s, dst, src, c, XORI, XORIS);
|
|
|
|
}
|
|
|
|
|
2020-10-29 01:29:04 +03:00
|
|
|
static void tcg_out_b(TCGContext *s, int mask, const tcg_insn_unit *target)
|
2009-12-06 16:00:24 +03:00
|
|
|
{
|
2014-03-29 01:58:38 +04:00
|
|
|
ptrdiff_t disp = tcg_pcrel_diff(s, target);
|
2013-08-31 17:30:45 +04:00
|
|
|
if (in_range_b(disp)) {
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out32(s, B | (disp & 0x3fffffc) | mask);
|
|
|
|
} else {
|
2014-03-25 02:22:35 +04:00
|
|
|
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, (uintptr_t)target);
|
2013-08-31 16:41:45 +04:00
|
|
|
tcg_out32(s, MTSPR | RS(TCG_REG_R0) | CTR);
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out32(s, BCCTR | BO_ALWAYS | mask);
|
2009-12-06 16:00:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-31 22:36:42 +04:00
|
|
|
static void tcg_out_mem_long(TCGContext *s, int opi, int opx, TCGReg rt,
|
|
|
|
TCGReg base, tcg_target_long offset)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_target_long orig = offset, l0, l1, extra = 0, align = 0;
|
2019-09-30 07:36:26 +03:00
|
|
|
bool is_int_store = false;
|
2014-04-30 23:12:16 +04:00
|
|
|
TCGReg rs = TCG_REG_TMP1;
|
2013-07-31 22:36:42 +04:00
|
|
|
|
|
|
|
switch (opi) {
|
|
|
|
case LD: case LWA:
|
|
|
|
align = 3;
|
|
|
|
/* FALLTHRU */
|
|
|
|
default:
|
2019-06-23 20:04:38 +03:00
|
|
|
if (rt > TCG_REG_R0 && rt < TCG_REG_V0) {
|
2013-07-31 22:36:42 +04:00
|
|
|
rs = rt;
|
2014-03-25 23:22:18 +04:00
|
|
|
break;
|
2013-07-31 22:36:42 +04:00
|
|
|
}
|
|
|
|
break;
|
2019-09-30 07:36:26 +03:00
|
|
|
case LXSD:
|
|
|
|
case STXSD:
|
|
|
|
align = 3;
|
|
|
|
break;
|
|
|
|
case LXV:
|
|
|
|
case STXV:
|
|
|
|
align = 15;
|
|
|
|
break;
|
2013-07-31 22:36:42 +04:00
|
|
|
case STD:
|
|
|
|
align = 3;
|
2014-03-25 23:22:18 +04:00
|
|
|
/* FALLTHRU */
|
2013-07-31 22:36:42 +04:00
|
|
|
case STB: case STH: case STW:
|
2019-09-30 07:36:26 +03:00
|
|
|
is_int_store = true;
|
2013-07-31 22:36:42 +04:00
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2023-08-04 20:16:32 +03:00
|
|
|
/* For unaligned or large offsets, use the prefixed form. */
|
|
|
|
if (have_isa_3_10
|
|
|
|
&& (offset != (int16_t)offset || (offset & align))
|
|
|
|
&& offset == sextract64(offset, 0, 34)) {
|
|
|
|
/*
|
|
|
|
* Note that the MLS:D insns retain their un-prefixed opcode,
|
|
|
|
* while the 8LS:D insns use a different opcode space.
|
|
|
|
*/
|
|
|
|
switch (opi) {
|
|
|
|
case LBZ:
|
|
|
|
case LHZ:
|
|
|
|
case LHA:
|
|
|
|
case LWZ:
|
|
|
|
case STB:
|
|
|
|
case STH:
|
|
|
|
case STW:
|
|
|
|
case ADDI:
|
|
|
|
tcg_out_mls_d(s, opi, rt, base, offset, 0);
|
|
|
|
return;
|
|
|
|
case LWA:
|
|
|
|
tcg_out_8ls_d(s, PLWA, rt, base, offset, 0);
|
|
|
|
return;
|
|
|
|
case LD:
|
|
|
|
tcg_out_8ls_d(s, PLD, rt, base, offset, 0);
|
|
|
|
return;
|
|
|
|
case STD:
|
|
|
|
tcg_out_8ls_d(s, PSTD, rt, base, offset, 0);
|
|
|
|
return;
|
|
|
|
case LXSD:
|
|
|
|
tcg_out_8ls_d(s, PLXSD, rt & 31, base, offset, 0);
|
|
|
|
return;
|
|
|
|
case STXSD:
|
|
|
|
tcg_out_8ls_d(s, PSTXSD, rt & 31, base, offset, 0);
|
|
|
|
return;
|
|
|
|
case LXV:
|
|
|
|
tcg_out_8ls_d(s, PLXV, rt & 31, base, offset, 0);
|
|
|
|
return;
|
|
|
|
case STXV:
|
|
|
|
tcg_out_8ls_d(s, PSTXV, rt & 31, base, offset, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-31 22:36:42 +04:00
|
|
|
/* For unaligned, or very large offsets, use the indexed form. */
|
2019-06-23 20:04:38 +03:00
|
|
|
if (offset & align || offset != (int32_t)offset || opi == 0) {
|
2014-06-27 08:26:00 +04:00
|
|
|
if (rs == base) {
|
|
|
|
rs = TCG_REG_R0;
|
|
|
|
}
|
2019-09-30 07:36:26 +03:00
|
|
|
tcg_debug_assert(!is_int_store || rs != rt);
|
2014-03-25 23:22:18 +04:00
|
|
|
tcg_out_movi(s, TCG_TYPE_PTR, rs, orig);
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_out32(s, opx | TAB(rt & 31, base, rs));
|
2013-07-31 22:36:42 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
l0 = (int16_t)offset;
|
|
|
|
offset = (offset - l0) >> 16;
|
|
|
|
l1 = (int16_t)offset;
|
|
|
|
|
|
|
|
if (l1 < 0 && orig >= 0) {
|
|
|
|
extra = 0x4000;
|
|
|
|
l1 = (int16_t)(offset - 0x4000);
|
|
|
|
}
|
|
|
|
if (l1) {
|
|
|
|
tcg_out32(s, ADDIS | TAI(rs, base, l1));
|
|
|
|
base = rs;
|
|
|
|
}
|
|
|
|
if (extra) {
|
|
|
|
tcg_out32(s, ADDIS | TAI(rs, base, extra));
|
|
|
|
base = rs;
|
|
|
|
}
|
|
|
|
if (opi != ADDI || base != rt || l0 != 0) {
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_out32(s, opi | TAI(rt & 31, base, l0));
|
2008-11-11 06:04:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
static void tcg_out_vsldoi(TCGContext *s, TCGReg ret,
|
|
|
|
TCGReg va, TCGReg vb, int shb)
|
2014-03-25 02:44:09 +04:00
|
|
|
{
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_out32(s, VSLDOI | VRT(ret) | VRA(va) | VRB(vb) | (shb << 6));
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret,
|
|
|
|
TCGReg base, intptr_t offset)
|
|
|
|
{
|
|
|
|
int shift;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case TCG_TYPE_I32:
|
|
|
|
if (ret < TCG_REG_V0) {
|
|
|
|
tcg_out_mem_long(s, LWZ, LWZX, ret, base, offset);
|
|
|
|
break;
|
|
|
|
}
|
2019-09-30 06:50:41 +03:00
|
|
|
if (have_isa_2_07 && have_vsx) {
|
|
|
|
tcg_out_mem_long(s, 0, LXSIWZX, ret, base, offset);
|
|
|
|
break;
|
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_debug_assert((offset & 3) == 0);
|
|
|
|
tcg_out_mem_long(s, 0, LVEWX, ret, base, offset);
|
|
|
|
shift = (offset - 4) & 0xc;
|
|
|
|
if (shift) {
|
|
|
|
tcg_out_vsldoi(s, ret, ret, ret, shift);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TCG_TYPE_I64:
|
|
|
|
if (ret < TCG_REG_V0) {
|
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
|
|
|
|
tcg_out_mem_long(s, LD, LDX, ret, base, offset);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fallthru */
|
|
|
|
case TCG_TYPE_V64:
|
|
|
|
tcg_debug_assert(ret >= TCG_REG_V0);
|
2019-06-23 20:04:47 +03:00
|
|
|
if (have_vsx) {
|
2019-09-30 07:36:26 +03:00
|
|
|
tcg_out_mem_long(s, have_isa_3_00 ? LXSD : 0, LXSDX,
|
|
|
|
ret, base, offset);
|
2019-06-23 20:04:47 +03:00
|
|
|
break;
|
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_debug_assert((offset & 7) == 0);
|
|
|
|
tcg_out_mem_long(s, 0, LVX, ret, base, offset & -16);
|
|
|
|
if (offset & 8) {
|
|
|
|
tcg_out_vsldoi(s, ret, ret, ret, 8);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TCG_TYPE_V128:
|
|
|
|
tcg_debug_assert(ret >= TCG_REG_V0);
|
|
|
|
tcg_debug_assert((offset & 15) == 0);
|
2019-09-30 07:36:26 +03:00
|
|
|
tcg_out_mem_long(s, have_isa_3_00 ? LXV : 0,
|
|
|
|
LVX, ret, base, offset);
|
2019-06-23 20:04:38 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
2014-03-25 02:44:09 +04:00
|
|
|
}
|
|
|
|
}
|
2013-08-01 02:11:44 +04:00
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
|
|
|
|
TCGReg base, intptr_t offset)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2019-06-23 20:04:38 +03:00
|
|
|
int shift;
|
2013-08-01 02:11:44 +04:00
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
switch (type) {
|
|
|
|
case TCG_TYPE_I32:
|
|
|
|
if (arg < TCG_REG_V0) {
|
|
|
|
tcg_out_mem_long(s, STW, STWX, arg, base, offset);
|
|
|
|
break;
|
|
|
|
}
|
2019-09-30 06:50:41 +03:00
|
|
|
if (have_isa_2_07 && have_vsx) {
|
|
|
|
tcg_out_mem_long(s, 0, STXSIWX, arg, base, offset);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
assert((offset & 3) == 0);
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_debug_assert((offset & 3) == 0);
|
|
|
|
shift = (offset - 4) & 0xc;
|
|
|
|
if (shift) {
|
|
|
|
tcg_out_vsldoi(s, TCG_VEC_TMP1, arg, arg, shift);
|
|
|
|
arg = TCG_VEC_TMP1;
|
|
|
|
}
|
|
|
|
tcg_out_mem_long(s, 0, STVEWX, arg, base, offset);
|
|
|
|
break;
|
|
|
|
case TCG_TYPE_I64:
|
|
|
|
if (arg < TCG_REG_V0) {
|
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
|
|
|
|
tcg_out_mem_long(s, STD, STDX, arg, base, offset);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fallthru */
|
|
|
|
case TCG_TYPE_V64:
|
|
|
|
tcg_debug_assert(arg >= TCG_REG_V0);
|
2019-06-23 20:04:47 +03:00
|
|
|
if (have_vsx) {
|
2019-09-30 07:36:26 +03:00
|
|
|
tcg_out_mem_long(s, have_isa_3_00 ? STXSD : 0,
|
|
|
|
STXSDX, arg, base, offset);
|
2019-06-23 20:04:47 +03:00
|
|
|
break;
|
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_debug_assert((offset & 7) == 0);
|
|
|
|
if (offset & 8) {
|
|
|
|
tcg_out_vsldoi(s, TCG_VEC_TMP1, arg, arg, 8);
|
|
|
|
arg = TCG_VEC_TMP1;
|
|
|
|
}
|
|
|
|
tcg_out_mem_long(s, 0, STVEWX, arg, base, offset);
|
|
|
|
tcg_out_mem_long(s, 0, STVEWX, arg, base, offset + 4);
|
|
|
|
break;
|
|
|
|
case TCG_TYPE_V128:
|
|
|
|
tcg_debug_assert(arg >= TCG_REG_V0);
|
2019-09-30 07:36:26 +03:00
|
|
|
tcg_out_mem_long(s, have_isa_3_00 ? STXV : 0,
|
|
|
|
STVX, arg, base, offset);
|
2019-06-23 20:04:38 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
2013-08-01 02:11:44 +04:00
|
|
|
}
|
2014-03-25 02:44:09 +04:00
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2016-06-20 08:59:13 +03:00
|
|
|
static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
|
|
|
|
TCGReg base, intptr_t ofs)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
|
|
|
|
int const_arg2, int cr, TCGType type)
|
|
|
|
{
|
|
|
|
int imm;
|
|
|
|
uint32_t op;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2014-04-30 22:55:34 +04:00
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
|
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
/* Simplify the comparisons below wrt CMPI. */
|
|
|
|
if (type == TCG_TYPE_I32) {
|
|
|
|
arg2 = (int32_t)arg2;
|
2008-07-27 15:09:21 +04:00
|
|
|
}
|
2013-08-01 02:11:44 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
switch (cond) {
|
|
|
|
case TCG_COND_EQ:
|
|
|
|
case TCG_COND_NE:
|
|
|
|
if (const_arg2) {
|
|
|
|
if ((int16_t) arg2 == arg2) {
|
|
|
|
op = CMPI;
|
|
|
|
imm = 1;
|
|
|
|
break;
|
|
|
|
} else if ((uint16_t) arg2 == arg2) {
|
|
|
|
op = CMPLI;
|
|
|
|
imm = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
op = CMPL;
|
|
|
|
imm = 0;
|
|
|
|
break;
|
2013-08-01 02:11:44 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
case TCG_COND_LT:
|
|
|
|
case TCG_COND_GE:
|
|
|
|
case TCG_COND_LE:
|
|
|
|
case TCG_COND_GT:
|
|
|
|
if (const_arg2) {
|
|
|
|
if ((int16_t) arg2 == arg2) {
|
|
|
|
op = CMPI;
|
|
|
|
imm = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
op = CMP;
|
|
|
|
imm = 0;
|
|
|
|
break;
|
2013-08-01 02:11:44 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
case TCG_COND_LTU:
|
|
|
|
case TCG_COND_GEU:
|
|
|
|
case TCG_COND_LEU:
|
|
|
|
case TCG_COND_GTU:
|
|
|
|
if (const_arg2) {
|
|
|
|
if ((uint16_t) arg2 == arg2) {
|
|
|
|
op = CMPLI;
|
|
|
|
imm = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
op = CMPL;
|
|
|
|
imm = 0;
|
|
|
|
break;
|
2013-08-01 02:11:44 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
default:
|
2023-04-05 22:09:14 +03:00
|
|
|
g_assert_not_reached();
|
2013-08-01 02:11:44 +04:00
|
|
|
}
|
2014-03-25 02:44:09 +04:00
|
|
|
op |= BF(cr) | ((type == TCG_TYPE_I64) << 21);
|
2013-08-01 02:11:44 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
if (imm) {
|
|
|
|
tcg_out32(s, op | RA(arg1) | (arg2 & 0xffff));
|
|
|
|
} else {
|
|
|
|
if (const_arg2) {
|
|
|
|
tcg_out_movi(s, type, TCG_REG_R0, arg2);
|
|
|
|
arg2 = TCG_REG_R0;
|
|
|
|
}
|
|
|
|
tcg_out32(s, op | RA(arg1) | RB(arg2));
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
static void tcg_out_setcond_eq0(TCGContext *s, TCGType type,
|
2023-08-05 04:55:23 +03:00
|
|
|
TCGReg dst, TCGReg src, bool neg)
|
2013-08-01 03:15:18 +04:00
|
|
|
{
|
2023-08-05 04:55:23 +03:00
|
|
|
if (neg && (TCG_TARGET_REG_BITS == 32 || type == TCG_TYPE_I64)) {
|
|
|
|
/*
|
|
|
|
* X != 0 implies X + -1 generates a carry.
|
|
|
|
* RT = (~X + X) + CA
|
|
|
|
* = -1 + CA
|
|
|
|
* = CA ? 0 : -1
|
|
|
|
*/
|
|
|
|
tcg_out32(s, ADDIC | TAI(TCG_REG_R0, src, -1));
|
|
|
|
tcg_out32(s, SUBFE | TAB(dst, src, src));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-27 05:10:43 +04:00
|
|
|
if (type == TCG_TYPE_I32) {
|
|
|
|
tcg_out32(s, CNTLZW | RS(src) | RA(dst));
|
|
|
|
tcg_out_shri32(s, dst, dst, 5);
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, CNTLZD | RS(src) | RA(dst));
|
|
|
|
tcg_out_shri64(s, dst, dst, 6);
|
|
|
|
}
|
2023-08-05 04:55:23 +03:00
|
|
|
if (neg) {
|
|
|
|
tcg_out32(s, NEG | RT(dst) | RA(dst));
|
|
|
|
}
|
2013-08-01 03:15:18 +04:00
|
|
|
}
|
|
|
|
|
2023-08-05 04:55:23 +03:00
|
|
|
static void tcg_out_setcond_ne0(TCGContext *s, TCGType type,
|
|
|
|
TCGReg dst, TCGReg src, bool neg)
|
2013-08-01 03:15:18 +04:00
|
|
|
{
|
2023-08-05 04:55:23 +03:00
|
|
|
if (!neg && (TCG_TARGET_REG_BITS == 32 || type == TCG_TYPE_I64)) {
|
|
|
|
/*
|
|
|
|
* X != 0 implies X + -1 generates a carry. Extra addition
|
|
|
|
* trickery means: R = X-1 + ~X + C = X-1 + (-X+1) + C = C.
|
|
|
|
*/
|
2014-03-25 02:44:09 +04:00
|
|
|
tcg_out32(s, ADDIC | TAI(TCG_REG_R0, src, -1));
|
|
|
|
tcg_out32(s, SUBFE | TAB(dst, TCG_REG_R0, src));
|
2023-08-05 04:55:23 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
tcg_out_setcond_eq0(s, type, dst, src, false);
|
|
|
|
if (neg) {
|
|
|
|
tcg_out32(s, ADDI | TAI(dst, dst, -1));
|
|
|
|
} else {
|
|
|
|
tcg_out_xori32(s, dst, dst, 1);
|
2013-08-01 03:15:18 +04:00
|
|
|
}
|
2014-03-25 02:44:09 +04:00
|
|
|
}
|
2013-08-01 03:15:18 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
static TCGReg tcg_gen_setcond_xor(TCGContext *s, TCGReg arg1, TCGArg arg2,
|
|
|
|
bool const_arg2)
|
|
|
|
{
|
|
|
|
if (const_arg2) {
|
|
|
|
if ((uint32_t)arg2 == arg2) {
|
|
|
|
tcg_out_xori32(s, TCG_REG_R0, arg1, arg2);
|
|
|
|
} else {
|
|
|
|
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R0, arg2);
|
|
|
|
tcg_out32(s, XOR | SAB(arg1, TCG_REG_R0, TCG_REG_R0));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, XOR | SAB(arg1, TCG_REG_R0, arg2));
|
|
|
|
}
|
|
|
|
return TCG_REG_R0;
|
2013-08-01 03:15:18 +04:00
|
|
|
}
|
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond,
|
|
|
|
TCGArg arg0, TCGArg arg1, TCGArg arg2,
|
2023-08-05 04:55:23 +03:00
|
|
|
int const_arg2, bool neg)
|
2013-08-01 03:15:18 +04:00
|
|
|
{
|
2023-08-05 04:55:23 +03:00
|
|
|
int sh;
|
|
|
|
bool inv;
|
2013-08-01 03:15:18 +04:00
|
|
|
|
2016-04-21 11:48:49 +03:00
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
|
2014-03-27 05:10:43 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
/* Ignore high bits of a potential constant arg2. */
|
|
|
|
if (type == TCG_TYPE_I32) {
|
|
|
|
arg2 = (uint32_t)arg2;
|
|
|
|
}
|
2013-08-01 03:15:18 +04:00
|
|
|
|
2023-08-05 05:04:56 +03:00
|
|
|
/* With SETBC/SETBCR, we can always implement with 2 insns. */
|
|
|
|
if (have_isa_3_10) {
|
|
|
|
tcg_insn_unit bi, opc;
|
|
|
|
|
|
|
|
tcg_out_cmp(s, cond, arg1, arg2, const_arg2, 7, type);
|
|
|
|
|
|
|
|
/* Re-use tcg_to_bc for BI and BO_COND_{TRUE,FALSE}. */
|
|
|
|
bi = tcg_to_bc[cond] & (0x1f << 16);
|
|
|
|
if (tcg_to_bc[cond] & BO(8)) {
|
|
|
|
opc = neg ? SETNBC : SETBC;
|
|
|
|
} else {
|
|
|
|
opc = neg ? SETNBCR : SETBCR;
|
|
|
|
}
|
|
|
|
tcg_out32(s, opc | RT(arg0) | bi);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
/* Handle common and trivial cases before handling anything else. */
|
|
|
|
if (arg2 == 0) {
|
|
|
|
switch (cond) {
|
|
|
|
case TCG_COND_EQ:
|
2023-08-05 04:55:23 +03:00
|
|
|
tcg_out_setcond_eq0(s, type, arg0, arg1, neg);
|
2014-03-25 02:44:09 +04:00
|
|
|
return;
|
|
|
|
case TCG_COND_NE:
|
2023-08-05 04:55:23 +03:00
|
|
|
tcg_out_setcond_ne0(s, type, arg0, arg1, neg);
|
2014-03-25 02:44:09 +04:00
|
|
|
return;
|
|
|
|
case TCG_COND_GE:
|
|
|
|
tcg_out32(s, NOR | SAB(arg1, arg0, arg1));
|
|
|
|
arg1 = arg0;
|
|
|
|
/* FALLTHRU */
|
|
|
|
case TCG_COND_LT:
|
|
|
|
/* Extract the sign bit. */
|
2014-03-27 05:10:43 +04:00
|
|
|
if (type == TCG_TYPE_I32) {
|
2023-08-05 04:55:23 +03:00
|
|
|
if (neg) {
|
|
|
|
tcg_out_sari32(s, arg0, arg1, 31);
|
|
|
|
} else {
|
|
|
|
tcg_out_shri32(s, arg0, arg1, 31);
|
|
|
|
}
|
2014-03-27 05:10:43 +04:00
|
|
|
} else {
|
2023-08-05 04:55:23 +03:00
|
|
|
if (neg) {
|
|
|
|
tcg_out_sari64(s, arg0, arg1, 63);
|
|
|
|
} else {
|
|
|
|
tcg_out_shri64(s, arg0, arg1, 63);
|
|
|
|
}
|
2014-03-27 05:10:43 +04:00
|
|
|
}
|
2014-03-25 02:44:09 +04:00
|
|
|
return;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-08-01 03:15:18 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
/* If we have ISEL, we can implement everything with 3 or 4 insns.
|
|
|
|
All other cases below are also at least 3 insns, so speed up the
|
|
|
|
code generator by not considering them and always using ISEL. */
|
2019-09-30 06:06:47 +03:00
|
|
|
if (have_isel) {
|
2014-03-25 02:44:09 +04:00
|
|
|
int isel, tab;
|
2013-08-01 03:15:18 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
tcg_out_cmp(s, cond, arg1, arg2, const_arg2, 7, type);
|
2013-08-01 03:15:18 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
isel = tcg_to_isel[cond];
|
2013-08-01 03:15:18 +04:00
|
|
|
|
2023-08-05 04:55:23 +03:00
|
|
|
tcg_out_movi(s, type, arg0, neg ? -1 : 1);
|
2014-03-25 02:44:09 +04:00
|
|
|
if (isel & 1) {
|
|
|
|
/* arg0 = (bc ? 0 : 1) */
|
|
|
|
tab = TAB(arg0, 0, arg0);
|
|
|
|
isel &= ~1;
|
|
|
|
} else {
|
|
|
|
/* arg0 = (bc ? 1 : 0) */
|
|
|
|
tcg_out_movi(s, type, TCG_REG_R0, 0);
|
|
|
|
tab = TAB(arg0, arg0, TCG_REG_R0);
|
|
|
|
}
|
|
|
|
tcg_out32(s, isel | tab);
|
|
|
|
return;
|
|
|
|
}
|
2013-02-02 12:58:14 +04:00
|
|
|
|
2023-08-05 04:55:23 +03:00
|
|
|
inv = false;
|
2014-03-25 02:44:09 +04:00
|
|
|
switch (cond) {
|
|
|
|
case TCG_COND_EQ:
|
|
|
|
arg1 = tcg_gen_setcond_xor(s, arg1, arg2, const_arg2);
|
2023-08-05 04:55:23 +03:00
|
|
|
tcg_out_setcond_eq0(s, type, arg0, arg1, neg);
|
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
case TCG_COND_NE:
|
|
|
|
arg1 = tcg_gen_setcond_xor(s, arg1, arg2, const_arg2);
|
2023-08-05 04:55:23 +03:00
|
|
|
tcg_out_setcond_ne0(s, type, arg0, arg1, neg);
|
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2023-08-05 04:55:23 +03:00
|
|
|
case TCG_COND_LE:
|
|
|
|
case TCG_COND_LEU:
|
|
|
|
inv = true;
|
|
|
|
/* fall through */
|
2014-03-25 02:44:09 +04:00
|
|
|
case TCG_COND_GT:
|
|
|
|
case TCG_COND_GTU:
|
2023-08-05 04:55:23 +03:00
|
|
|
sh = 30; /* CR7 CR_GT */
|
2014-03-25 02:44:09 +04:00
|
|
|
goto crtest;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
case TCG_COND_GE:
|
|
|
|
case TCG_COND_GEU:
|
2023-08-05 04:55:23 +03:00
|
|
|
inv = true;
|
|
|
|
/* fall through */
|
|
|
|
case TCG_COND_LT:
|
|
|
|
case TCG_COND_LTU:
|
|
|
|
sh = 29; /* CR7 CR_LT */
|
2014-03-25 02:44:09 +04:00
|
|
|
goto crtest;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
crtest:
|
|
|
|
tcg_out_cmp(s, cond, arg1, arg2, const_arg2, 7, type);
|
|
|
|
tcg_out32(s, MFOCRF | RT(TCG_REG_R0) | FXM(7));
|
|
|
|
tcg_out_rlw(s, RLWINM, arg0, TCG_REG_R0, sh, 31, 31);
|
2023-08-05 04:55:23 +03:00
|
|
|
if (neg && inv) {
|
|
|
|
tcg_out32(s, ADDI | TAI(arg0, arg0, -1));
|
|
|
|
} else if (neg) {
|
|
|
|
tcg_out32(s, NEG | RT(arg0) | RA(arg0));
|
|
|
|
} else if (inv) {
|
|
|
|
tcg_out_xori32(s, arg0, arg0, 1);
|
|
|
|
}
|
2014-03-25 02:44:09 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2023-04-05 22:09:14 +03:00
|
|
|
g_assert_not_reached();
|
2014-03-25 02:44:09 +04:00
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2015-02-14 00:39:54 +03:00
|
|
|
static void tcg_out_bc(TCGContext *s, int bc, TCGLabel *l)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2014-03-25 02:44:09 +04:00
|
|
|
if (l->has_value) {
|
2020-11-04 21:17:46 +03:00
|
|
|
bc |= reloc_pc14_val(tcg_splitwx_to_rx(s->code_ptr), l->u.value_ptr);
|
2013-02-02 12:58:14 +04:00
|
|
|
} else {
|
2015-02-14 00:39:54 +03:00
|
|
|
tcg_out_reloc(s, s->code_ptr, R_PPC_REL14, l, 0);
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
2018-11-30 01:48:26 +03:00
|
|
|
tcg_out32(s, bc);
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
static void tcg_out_brcond(TCGContext *s, TCGCond cond,
|
|
|
|
TCGArg arg1, TCGArg arg2, int const_arg2,
|
2015-02-14 00:39:54 +03:00
|
|
|
TCGLabel *l, TCGType type)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2014-03-25 02:44:09 +04:00
|
|
|
tcg_out_cmp(s, cond, arg1, arg2, const_arg2, 7, type);
|
2015-02-14 00:39:54 +03:00
|
|
|
tcg_out_bc(s, tcg_to_bc[cond], l);
|
2014-03-25 02:44:09 +04:00
|
|
|
}
|
2013-08-31 15:44:21 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond,
|
|
|
|
TCGArg dest, TCGArg c1, TCGArg c2, TCGArg v1,
|
|
|
|
TCGArg v2, bool const_c2)
|
|
|
|
{
|
|
|
|
/* If for some reason both inputs are zero, don't produce bad code. */
|
|
|
|
if (v1 == 0 && v2 == 0) {
|
|
|
|
tcg_out_movi(s, type, dest, 0);
|
|
|
|
return;
|
2010-05-06 09:50:45 +04:00
|
|
|
}
|
2009-07-18 10:08:40 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
tcg_out_cmp(s, cond, c1, c2, const_c2, 7, type);
|
2008-07-24 21:37:09 +04:00
|
|
|
|
2019-09-30 06:06:47 +03:00
|
|
|
if (have_isel) {
|
2014-03-25 02:44:09 +04:00
|
|
|
int isel = tcg_to_isel[cond];
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
/* Swap the V operands if the operation indicates inversion. */
|
|
|
|
if (isel & 1) {
|
|
|
|
int t = v1;
|
|
|
|
v1 = v2;
|
|
|
|
v2 = t;
|
|
|
|
isel &= ~1;
|
|
|
|
}
|
|
|
|
/* V1 == 0 is handled by isel; V2 == 0 must be handled by hand. */
|
|
|
|
if (v2 == 0) {
|
|
|
|
tcg_out_movi(s, type, TCG_REG_R0, 0);
|
|
|
|
}
|
|
|
|
tcg_out32(s, isel | TAB(dest, v1, v2));
|
|
|
|
} else {
|
|
|
|
if (dest == v2) {
|
|
|
|
cond = tcg_invert_cond(cond);
|
|
|
|
v2 = v1;
|
|
|
|
} else if (dest != v1) {
|
|
|
|
if (v1 == 0) {
|
|
|
|
tcg_out_movi(s, type, dest, 0);
|
|
|
|
} else {
|
|
|
|
tcg_out_mov(s, type, dest, v1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Branch forward over one insn */
|
|
|
|
tcg_out32(s, tcg_to_bc[cond] | 8);
|
|
|
|
if (v2 == 0) {
|
|
|
|
tcg_out_movi(s, type, dest, 0);
|
|
|
|
} else {
|
|
|
|
tcg_out_mov(s, type, dest, v2);
|
|
|
|
}
|
2013-08-31 16:23:23 +04:00
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2016-11-16 14:48:55 +03:00
|
|
|
static void tcg_out_cntxz(TCGContext *s, TCGType type, uint32_t opc,
|
|
|
|
TCGArg a0, TCGArg a1, TCGArg a2, bool const_a2)
|
|
|
|
{
|
|
|
|
if (const_a2 && a2 == (type == TCG_TYPE_I32 ? 32 : 64)) {
|
|
|
|
tcg_out32(s, opc | RA(a0) | RS(a1));
|
|
|
|
} else {
|
|
|
|
tcg_out_cmp(s, TCG_COND_EQ, a1, 0, 1, 7, type);
|
|
|
|
/* Note that the only other valid constant for a2 is 0. */
|
2019-09-30 06:06:47 +03:00
|
|
|
if (have_isel) {
|
2016-11-16 14:48:55 +03:00
|
|
|
tcg_out32(s, opc | RA(TCG_REG_R0) | RS(a1));
|
|
|
|
tcg_out32(s, tcg_to_isel[TCG_COND_EQ] | TAB(a0, a2, TCG_REG_R0));
|
|
|
|
} else if (!const_a2 && a0 == a2) {
|
|
|
|
tcg_out32(s, tcg_to_bc[TCG_COND_EQ] | 8);
|
|
|
|
tcg_out32(s, opc | RA(a0) | RS(a1));
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, opc | RA(a0) | RS(a1));
|
|
|
|
tcg_out32(s, tcg_to_bc[TCG_COND_NE] | 8);
|
|
|
|
if (const_a2) {
|
|
|
|
tcg_out_movi(s, type, a0, 0);
|
|
|
|
} else {
|
|
|
|
tcg_out_mov(s, type, a0, a2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-30 22:55:34 +04:00
|
|
|
static void tcg_out_cmp2(TCGContext *s, const TCGArg *args,
|
|
|
|
const int *const_args)
|
|
|
|
{
|
|
|
|
static const struct { uint8_t bit1, bit2; } bits[] = {
|
|
|
|
[TCG_COND_LT ] = { CR_LT, CR_LT },
|
|
|
|
[TCG_COND_LE ] = { CR_LT, CR_GT },
|
|
|
|
[TCG_COND_GT ] = { CR_GT, CR_GT },
|
|
|
|
[TCG_COND_GE ] = { CR_GT, CR_LT },
|
|
|
|
[TCG_COND_LTU] = { CR_LT, CR_LT },
|
|
|
|
[TCG_COND_LEU] = { CR_LT, CR_GT },
|
|
|
|
[TCG_COND_GTU] = { CR_GT, CR_GT },
|
|
|
|
[TCG_COND_GEU] = { CR_GT, CR_LT },
|
|
|
|
};
|
|
|
|
|
|
|
|
TCGCond cond = args[4], cond2;
|
|
|
|
TCGArg al, ah, bl, bh;
|
|
|
|
int blconst, bhconst;
|
|
|
|
int op, bit1, bit2;
|
|
|
|
|
|
|
|
al = args[0];
|
|
|
|
ah = args[1];
|
|
|
|
bl = args[2];
|
|
|
|
bh = args[3];
|
|
|
|
blconst = const_args[2];
|
|
|
|
bhconst = const_args[3];
|
|
|
|
|
|
|
|
switch (cond) {
|
|
|
|
case TCG_COND_EQ:
|
|
|
|
op = CRAND;
|
|
|
|
goto do_equality;
|
|
|
|
case TCG_COND_NE:
|
|
|
|
op = CRNAND;
|
|
|
|
do_equality:
|
|
|
|
tcg_out_cmp(s, cond, al, bl, blconst, 6, TCG_TYPE_I32);
|
|
|
|
tcg_out_cmp(s, cond, ah, bh, bhconst, 7, TCG_TYPE_I32);
|
|
|
|
tcg_out32(s, op | BT(7, CR_EQ) | BA(6, CR_EQ) | BB(7, CR_EQ));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TCG_COND_LT:
|
|
|
|
case TCG_COND_LE:
|
|
|
|
case TCG_COND_GT:
|
|
|
|
case TCG_COND_GE:
|
|
|
|
case TCG_COND_LTU:
|
|
|
|
case TCG_COND_LEU:
|
|
|
|
case TCG_COND_GTU:
|
|
|
|
case TCG_COND_GEU:
|
|
|
|
bit1 = bits[cond].bit1;
|
|
|
|
bit2 = bits[cond].bit2;
|
|
|
|
op = (bit1 != bit2 ? CRANDC : CRAND);
|
|
|
|
cond2 = tcg_unsigned_cond(cond);
|
|
|
|
|
|
|
|
tcg_out_cmp(s, cond, ah, bh, bhconst, 6, TCG_TYPE_I32);
|
|
|
|
tcg_out_cmp(s, cond2, al, bl, blconst, 7, TCG_TYPE_I32);
|
|
|
|
tcg_out32(s, op | BT(7, CR_EQ) | BA(6, CR_EQ) | BB(7, bit2));
|
|
|
|
tcg_out32(s, CROR | BT(7, CR_EQ) | BA(6, bit1) | BB(7, CR_EQ));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2023-04-05 22:09:14 +03:00
|
|
|
g_assert_not_reached();
|
2014-04-30 22:55:34 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
|
|
|
|
const int *const_args)
|
|
|
|
{
|
|
|
|
tcg_out_cmp2(s, args + 1, const_args + 1);
|
|
|
|
tcg_out32(s, MFOCRF | RT(TCG_REG_R0) | FXM(7));
|
|
|
|
tcg_out_rlw(s, RLWINM, args[0], TCG_REG_R0, 31, 31, 31);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args,
|
|
|
|
const int *const_args)
|
|
|
|
{
|
|
|
|
tcg_out_cmp2(s, args, const_args);
|
2015-02-14 00:39:54 +03:00
|
|
|
tcg_out_bc(s, BC | BI(7, CR_EQ) | BO_COND_TRUE, arg_label(args[5]));
|
2014-04-30 22:55:34 +04:00
|
|
|
}
|
|
|
|
|
2016-07-14 23:20:19 +03:00
|
|
|
static void tcg_out_mb(TCGContext *s, TCGArg a0)
|
|
|
|
{
|
2022-05-19 16:59:07 +03:00
|
|
|
uint32_t insn;
|
|
|
|
|
|
|
|
if (a0 & TCG_MO_ST_LD) {
|
|
|
|
insn = HWSYNC;
|
|
|
|
} else {
|
2016-07-14 23:20:19 +03:00
|
|
|
insn = LWSYNC;
|
|
|
|
}
|
2022-05-19 16:59:07 +03:00
|
|
|
|
2016-07-14 23:20:19 +03:00
|
|
|
tcg_out32(s, insn);
|
|
|
|
}
|
|
|
|
|
2021-08-04 01:08:55 +03:00
|
|
|
static void tcg_out_call_int(TCGContext *s, int lk,
|
|
|
|
const tcg_insn_unit *target)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2014-04-30 22:57:11 +04:00
|
|
|
#ifdef _CALL_AIX
|
2014-03-25 02:44:09 +04:00
|
|
|
/* Look through the descriptor. If the branch is in range, and we
|
|
|
|
don't have to spend too much effort on building the toc. */
|
2020-10-29 01:29:04 +03:00
|
|
|
const void *tgt = ((const void * const *)target)[0];
|
|
|
|
uintptr_t toc = ((const uintptr_t *)target)[1];
|
2014-03-25 02:44:09 +04:00
|
|
|
intptr_t diff = tcg_pcrel_diff(s, tgt);
|
2013-07-31 22:36:42 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
if (in_range_b(diff) && toc == (uint32_t)toc) {
|
2014-04-30 23:12:16 +04:00
|
|
|
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP1, toc);
|
2021-08-04 01:08:55 +03:00
|
|
|
tcg_out_b(s, lk, tgt);
|
2013-08-31 16:14:53 +04:00
|
|
|
} else {
|
2014-03-25 02:44:09 +04:00
|
|
|
/* Fold the low bits of the constant into the addresses below. */
|
|
|
|
intptr_t arg = (intptr_t)target;
|
|
|
|
int ofs = (int16_t)arg;
|
|
|
|
|
|
|
|
if (ofs + 8 < 0x8000) {
|
|
|
|
arg -= ofs;
|
|
|
|
} else {
|
|
|
|
ofs = 0;
|
|
|
|
}
|
2014-04-30 23:12:16 +04:00
|
|
|
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP1, arg);
|
|
|
|
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R0, TCG_REG_TMP1, ofs);
|
2014-03-25 02:44:09 +04:00
|
|
|
tcg_out32(s, MTSPR | RA(TCG_REG_R0) | CTR);
|
2014-04-30 23:12:16 +04:00
|
|
|
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R2, TCG_REG_TMP1, ofs + SZP);
|
2021-08-04 01:08:55 +03:00
|
|
|
tcg_out32(s, BCCTR | BO_ALWAYS | lk);
|
2013-08-31 16:14:53 +04:00
|
|
|
}
|
2014-05-01 01:33:05 +04:00
|
|
|
#elif defined(_CALL_ELF) && _CALL_ELF == 2
|
|
|
|
intptr_t diff;
|
|
|
|
|
|
|
|
/* In the ELFv2 ABI, we have to set up r12 to contain the destination
|
|
|
|
address, which the callee uses to compute its TOC address. */
|
|
|
|
/* FIXME: when the branch is in range, we could avoid r12 load if we
|
|
|
|
knew that the destination uses the same TOC, and what its local
|
|
|
|
entry point offset is. */
|
|
|
|
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R12, (intptr_t)target);
|
|
|
|
|
|
|
|
diff = tcg_pcrel_diff(s, target);
|
|
|
|
if (in_range_b(diff)) {
|
2021-08-04 01:08:55 +03:00
|
|
|
tcg_out_b(s, lk, target);
|
2014-05-01 01:33:05 +04:00
|
|
|
} else {
|
|
|
|
tcg_out32(s, MTSPR | RS(TCG_REG_R12) | CTR);
|
2021-08-04 01:08:55 +03:00
|
|
|
tcg_out32(s, BCCTR | BO_ALWAYS | lk);
|
2014-05-01 01:33:05 +04:00
|
|
|
}
|
2014-04-30 22:57:11 +04:00
|
|
|
#else
|
2021-08-04 01:08:55 +03:00
|
|
|
tcg_out_b(s, lk, target);
|
2014-03-25 02:44:09 +04:00
|
|
|
#endif
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2022-10-18 10:51:41 +03:00
|
|
|
static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
|
|
|
|
const TCGHelperInfo *info)
|
2021-08-04 01:08:55 +03:00
|
|
|
{
|
|
|
|
tcg_out_call_int(s, LK, target);
|
|
|
|
}
|
|
|
|
|
2021-07-26 23:32:17 +03:00
|
|
|
static const uint32_t qemu_ldx_opc[(MO_SSIZE + MO_BSWAP) + 1] = {
|
2014-03-25 02:44:09 +04:00
|
|
|
[MO_UB] = LBZX,
|
|
|
|
[MO_UW] = LHZX,
|
|
|
|
[MO_UL] = LWZX,
|
2022-01-07 00:00:51 +03:00
|
|
|
[MO_UQ] = LDX,
|
2014-03-25 02:44:09 +04:00
|
|
|
[MO_SW] = LHAX,
|
|
|
|
[MO_SL] = LWAX,
|
|
|
|
[MO_BSWAP | MO_UB] = LBZX,
|
|
|
|
[MO_BSWAP | MO_UW] = LHBRX,
|
|
|
|
[MO_BSWAP | MO_UL] = LWBRX,
|
2022-01-07 00:00:51 +03:00
|
|
|
[MO_BSWAP | MO_UQ] = LDBRX,
|
2014-03-25 02:44:09 +04:00
|
|
|
};
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2021-07-26 23:32:17 +03:00
|
|
|
static const uint32_t qemu_stx_opc[(MO_SIZE + MO_BSWAP) + 1] = {
|
2014-03-25 02:44:09 +04:00
|
|
|
[MO_UB] = STBX,
|
|
|
|
[MO_UW] = STHX,
|
|
|
|
[MO_UL] = STWX,
|
2022-01-07 00:00:51 +03:00
|
|
|
[MO_UQ] = STDX,
|
2014-03-25 02:44:09 +04:00
|
|
|
[MO_BSWAP | MO_UB] = STBX,
|
|
|
|
[MO_BSWAP | MO_UW] = STHBRX,
|
|
|
|
[MO_BSWAP | MO_UL] = STWBRX,
|
2022-01-07 00:00:51 +03:00
|
|
|
[MO_BSWAP | MO_UQ] = STDBRX,
|
2014-03-25 02:44:09 +04:00
|
|
|
};
|
2013-04-03 01:14:23 +04:00
|
|
|
|
2023-04-10 21:09:42 +03:00
|
|
|
static TCGReg ldst_ra_gen(TCGContext *s, const TCGLabelQemuLdst *l, int arg)
|
|
|
|
{
|
|
|
|
if (arg < 0) {
|
|
|
|
arg = TCG_REG_TMP1;
|
|
|
|
}
|
|
|
|
tcg_out32(s, MFSPR | RT(arg) | LR);
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For the purposes of ppc32 sorting 4 input registers into 4 argument
|
|
|
|
* registers, there is an outside chance we would require 3 temps.
|
|
|
|
*/
|
|
|
|
static const TCGLdstHelperParam ldst_helper_param = {
|
|
|
|
.ra_gen = ldst_ra_gen,
|
|
|
|
.ntmp = 3,
|
2023-04-04 01:25:06 +03:00
|
|
|
.tmp = { TCG_REG_TMP1, TCG_REG_TMP2, TCG_REG_R0 }
|
2023-04-10 21:09:42 +03:00
|
|
|
};
|
|
|
|
|
2019-04-22 00:51:00 +03:00
|
|
|
static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
|
2013-04-03 02:16:10 +04:00
|
|
|
{
|
2023-04-10 21:09:42 +03:00
|
|
|
MemOp opc = get_memop(lb->oi);
|
2013-04-03 02:16:10 +04:00
|
|
|
|
2020-11-04 21:17:46 +03:00
|
|
|
if (!reloc_pc14(lb->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
|
2019-04-22 00:51:00 +03:00
|
|
|
return false;
|
|
|
|
}
|
2013-04-03 02:16:10 +04:00
|
|
|
|
2023-04-10 21:09:42 +03:00
|
|
|
tcg_out_ld_helper_args(s, lb, &ldst_helper_param);
|
2022-11-01 04:51:04 +03:00
|
|
|
tcg_out_call_int(s, LK, qemu_ld_helpers[opc & MO_SIZE]);
|
2023-04-10 21:09:42 +03:00
|
|
|
tcg_out_ld_helper_ret(s, lb, false, &ldst_helper_param);
|
2013-04-03 02:16:10 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
tcg_out_b(s, 0, lb->raddr);
|
2019-04-22 00:51:00 +03:00
|
|
|
return true;
|
2014-03-25 02:44:09 +04:00
|
|
|
}
|
2013-04-03 02:16:10 +04:00
|
|
|
|
2019-04-22 00:51:00 +03:00
|
|
|
static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
|
2014-03-25 02:44:09 +04:00
|
|
|
{
|
2023-04-10 21:09:42 +03:00
|
|
|
MemOp opc = get_memop(lb->oi);
|
2010-02-07 02:48:53 +03:00
|
|
|
|
2020-11-04 21:17:46 +03:00
|
|
|
if (!reloc_pc14(lb->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
|
2019-04-22 00:51:00 +03:00
|
|
|
return false;
|
|
|
|
}
|
2010-02-07 02:48:53 +03:00
|
|
|
|
2023-04-10 21:09:42 +03:00
|
|
|
tcg_out_st_helper_args(s, lb, &ldst_helper_param);
|
2022-11-01 04:51:04 +03:00
|
|
|
tcg_out_call_int(s, LK, qemu_st_helpers[opc & MO_SIZE]);
|
2014-03-25 02:44:09 +04:00
|
|
|
|
|
|
|
tcg_out_b(s, 0, lb->raddr);
|
2019-04-22 00:51:00 +03:00
|
|
|
return true;
|
2010-02-07 02:48:53 +03:00
|
|
|
}
|
|
|
|
|
2023-04-23 22:10:00 +03:00
|
|
|
typedef struct {
|
|
|
|
TCGReg base;
|
|
|
|
TCGReg index;
|
2023-04-19 11:45:00 +03:00
|
|
|
TCGAtomAlign aa;
|
2023-04-23 22:10:00 +03:00
|
|
|
} HostAddress;
|
|
|
|
|
2023-04-19 13:43:17 +03:00
|
|
|
bool tcg_target_has_memory_bswap(MemOp memop)
|
|
|
|
{
|
2023-04-19 16:13:22 +03:00
|
|
|
TCGAtomAlign aa;
|
|
|
|
|
|
|
|
if ((memop & MO_SIZE) <= MO_64) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reject 16-byte memop with 16-byte atomicity,
|
|
|
|
* but do allow a pair of 64-bit operations.
|
|
|
|
*/
|
|
|
|
aa = atom_and_align_for_opc(tcg_ctx, memop, MO_ATOM_IFALIGN, true);
|
|
|
|
return aa.atom <= MO_64;
|
2023-04-19 13:43:17 +03:00
|
|
|
}
|
|
|
|
|
2023-03-28 02:07:15 +03:00
|
|
|
/* We expect to use a 16-bit negative offset from ENV. */
|
|
|
|
#define MIN_TLB_MASK_TABLE_OFS -32768
|
|
|
|
|
2023-04-23 22:26:05 +03:00
|
|
|
/*
|
2023-10-04 12:06:20 +03:00
|
|
|
* For system-mode, perform the TLB load and compare.
|
|
|
|
* For user-mode, perform any required alignment tests.
|
2023-04-23 22:26:05 +03:00
|
|
|
* In both cases, return a TCGLabelQemuLdst structure if the slow path
|
|
|
|
* is required and fill in @h with the host address for the fast path.
|
|
|
|
*/
|
|
|
|
static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
|
|
|
|
TCGReg addrlo, TCGReg addrhi,
|
|
|
|
MemOpIdx oi, bool is_ld)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2023-04-27 17:45:50 +03:00
|
|
|
TCGType addr_type = s->addr_type;
|
2023-04-23 22:26:05 +03:00
|
|
|
TCGLabelQemuLdst *ldst = NULL;
|
2023-04-06 22:53:46 +03:00
|
|
|
MemOp opc = get_memop(oi);
|
2023-04-19 16:13:22 +03:00
|
|
|
MemOp a_bits, s_bits;
|
2023-04-19 11:45:00 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Book II, Section 1.4, Single-Copy Atomicity, specifies:
|
|
|
|
*
|
|
|
|
* Before 3.0, "An access that is not atomic is performed as a set of
|
|
|
|
* smaller disjoint atomic accesses. In general, the number and alignment
|
|
|
|
* of these accesses are implementation-dependent." Thus MO_ATOM_IFALIGN.
|
|
|
|
*
|
|
|
|
* As of 3.0, "the non-atomic access is performed as described in
|
|
|
|
* the corresponding list", which matches MO_ATOM_SUBALIGN.
|
|
|
|
*/
|
2023-04-19 16:13:22 +03:00
|
|
|
s_bits = opc & MO_SIZE;
|
2023-04-19 11:45:00 +03:00
|
|
|
h->aa = atom_and_align_for_opc(s, opc,
|
|
|
|
have_isa_3_00 ? MO_ATOM_SUBALIGN
|
|
|
|
: MO_ATOM_IFALIGN,
|
2023-04-19 16:13:22 +03:00
|
|
|
s_bits == MO_128);
|
2023-04-19 11:45:00 +03:00
|
|
|
a_bits = h->aa.align;
|
2023-04-06 22:53:46 +03:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
#ifdef CONFIG_SOFTMMU
|
2023-04-23 22:26:05 +03:00
|
|
|
int mem_index = get_mmuidx(oi);
|
|
|
|
int cmp_off = is_ld ? offsetof(CPUTLBEntry, addr_read)
|
|
|
|
: offsetof(CPUTLBEntry, addr_write);
|
2023-03-28 02:07:15 +03:00
|
|
|
int fast_off = tlb_mask_table_ofs(s, mem_index);
|
2023-04-23 22:26:05 +03:00
|
|
|
int mask_off = fast_off + offsetof(CPUTLBDescFast, mask);
|
|
|
|
int table_off = fast_off + offsetof(CPUTLBDescFast, table);
|
|
|
|
|
|
|
|
ldst = new_ldst_label(s);
|
|
|
|
ldst->is_ld = is_ld;
|
|
|
|
ldst->oi = oi;
|
|
|
|
ldst->addrlo_reg = addrlo;
|
|
|
|
ldst->addrhi_reg = addrhi;
|
|
|
|
|
|
|
|
/* Load tlb_mask[mmu_idx] and tlb_table[mmu_idx]. */
|
2023-04-04 01:25:06 +03:00
|
|
|
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, mask_off);
|
|
|
|
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_AREG0, table_off);
|
2014-03-25 23:11:48 +04:00
|
|
|
|
2023-04-23 22:26:05 +03:00
|
|
|
/* Extract the page index, shifted into place for tlb index. */
|
|
|
|
if (TCG_TARGET_REG_BITS == 32) {
|
2023-04-04 01:25:06 +03:00
|
|
|
tcg_out_shri32(s, TCG_REG_R0, addrlo,
|
2023-03-24 07:06:22 +03:00
|
|
|
s->page_bits - CPU_TLB_ENTRY_BITS);
|
2023-04-23 22:26:05 +03:00
|
|
|
} else {
|
2023-04-04 01:25:06 +03:00
|
|
|
tcg_out_shri64(s, TCG_REG_R0, addrlo,
|
2023-03-24 07:06:22 +03:00
|
|
|
s->page_bits - CPU_TLB_ENTRY_BITS);
|
2023-04-23 22:26:05 +03:00
|
|
|
}
|
2023-04-04 01:25:06 +03:00
|
|
|
tcg_out32(s, AND | SAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_R0));
|
2023-04-23 22:26:05 +03:00
|
|
|
|
tcg: Widen CPUTLBEntry comparators to 64-bits
This makes CPUTLBEntry agnostic to the address size of the guest.
When 32-bit addresses are in effect, we can simply read the low
32 bits of the 64-bit field. Similarly when we need to update
the field for setting TLB_NOTDIRTY.
For TCG backends that could in theory be big-endian, but in
practice are not (arm, loongarch, riscv), use QEMU_BUILD_BUG_ON
to document and ensure this is not accidentally missed.
For s390x, which is always big-endian, use HOST_BIG_ENDIAN anyway,
to document the reason for the adjustment.
For sparc64 and ppc64, always perform a 64-bit load, and rely on
the following 32-bit comparison to ignore the high bits.
Rearrange mips and ppc if ladders for clarity.
Reviewed-by: Anton Johansson <anjo@rev.ng>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
2023-03-24 23:02:59 +03:00
|
|
|
/*
|
|
|
|
* Load the (low part) TLB comparator into TMP2.
|
|
|
|
* For 64-bit host, always load the entire 64-bit slot for simplicity.
|
|
|
|
* We will ignore the high bits with tcg_out_cmp(..., addr_type).
|
|
|
|
*/
|
|
|
|
if (TCG_TARGET_REG_BITS == 64) {
|
|
|
|
if (cmp_off == 0) {
|
|
|
|
tcg_out32(s, LDUX | TAB(TCG_REG_TMP2, TCG_REG_TMP1, TCG_REG_TMP2));
|
2023-04-23 22:26:05 +03:00
|
|
|
} else {
|
tcg: Widen CPUTLBEntry comparators to 64-bits
This makes CPUTLBEntry agnostic to the address size of the guest.
When 32-bit addresses are in effect, we can simply read the low
32 bits of the 64-bit field. Similarly when we need to update
the field for setting TLB_NOTDIRTY.
For TCG backends that could in theory be big-endian, but in
practice are not (arm, loongarch, riscv), use QEMU_BUILD_BUG_ON
to document and ensure this is not accidentally missed.
For s390x, which is always big-endian, use HOST_BIG_ENDIAN anyway,
to document the reason for the adjustment.
For sparc64 and ppc64, always perform a 64-bit load, and rely on
the following 32-bit comparison to ignore the high bits.
Rearrange mips and ppc if ladders for clarity.
Reviewed-by: Anton Johansson <anjo@rev.ng>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
2023-03-24 23:02:59 +03:00
|
|
|
tcg_out32(s, ADD | TAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP2));
|
|
|
|
tcg_out_ld(s, TCG_TYPE_I64, TCG_REG_TMP2, TCG_REG_TMP1, cmp_off);
|
2023-04-23 22:26:05 +03:00
|
|
|
}
|
tcg: Widen CPUTLBEntry comparators to 64-bits
This makes CPUTLBEntry agnostic to the address size of the guest.
When 32-bit addresses are in effect, we can simply read the low
32 bits of the 64-bit field. Similarly when we need to update
the field for setting TLB_NOTDIRTY.
For TCG backends that could in theory be big-endian, but in
practice are not (arm, loongarch, riscv), use QEMU_BUILD_BUG_ON
to document and ensure this is not accidentally missed.
For s390x, which is always big-endian, use HOST_BIG_ENDIAN anyway,
to document the reason for the adjustment.
For sparc64 and ppc64, always perform a 64-bit load, and rely on
the following 32-bit comparison to ignore the high bits.
Rearrange mips and ppc if ladders for clarity.
Reviewed-by: Anton Johansson <anjo@rev.ng>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
2023-03-24 23:02:59 +03:00
|
|
|
} else if (cmp_off == 0 && !HOST_BIG_ENDIAN) {
|
|
|
|
tcg_out32(s, LWZUX | TAB(TCG_REG_TMP2, TCG_REG_TMP1, TCG_REG_TMP2));
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, ADD | TAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP2));
|
|
|
|
tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_TMP2, TCG_REG_TMP1,
|
|
|
|
cmp_off + 4 * HOST_BIG_ENDIAN);
|
2023-04-23 22:26:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Load the TLB addend for use on the fast path.
|
|
|
|
* Do this asap to minimize any load use delay.
|
|
|
|
*/
|
2023-04-27 17:45:50 +03:00
|
|
|
if (TCG_TARGET_REG_BITS == 64 || addr_type == TCG_TYPE_I32) {
|
2023-04-04 01:25:06 +03:00
|
|
|
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1,
|
|
|
|
offsetof(CPUTLBEntry, addend));
|
|
|
|
}
|
2023-04-23 22:26:05 +03:00
|
|
|
|
2023-04-04 01:25:06 +03:00
|
|
|
/* Clear the non-page, non-alignment bits from the address in R0. */
|
2023-04-23 22:26:05 +03:00
|
|
|
if (TCG_TARGET_REG_BITS == 32) {
|
|
|
|
/*
|
|
|
|
* We don't support unaligned accesses on 32-bits.
|
|
|
|
* Preserve the bottom bits and thus trigger a comparison
|
|
|
|
* failure on unaligned accesses.
|
|
|
|
*/
|
|
|
|
if (a_bits < s_bits) {
|
|
|
|
a_bits = s_bits;
|
|
|
|
}
|
|
|
|
tcg_out_rlw(s, RLWINM, TCG_REG_R0, addrlo, 0,
|
2023-03-24 07:06:22 +03:00
|
|
|
(32 - a_bits) & 31, 31 - s->page_bits);
|
2023-04-23 22:26:05 +03:00
|
|
|
} else {
|
|
|
|
TCGReg t = addrlo;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the access is unaligned, we need to make sure we fail if we
|
|
|
|
* cross a page boundary. The trick is to add the access size-1
|
|
|
|
* to the address before masking the low bits. That will make the
|
|
|
|
* address overflow to the next page if we cross a page boundary,
|
|
|
|
* which will then force a mismatch of the TLB compare.
|
|
|
|
*/
|
|
|
|
if (a_bits < s_bits) {
|
|
|
|
unsigned a_mask = (1 << a_bits) - 1;
|
|
|
|
unsigned s_mask = (1 << s_bits) - 1;
|
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_R0, t, s_mask - a_mask));
|
|
|
|
t = TCG_REG_R0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mask the address for the requested alignment. */
|
2023-04-27 17:45:50 +03:00
|
|
|
if (addr_type == TCG_TYPE_I32) {
|
2023-04-23 22:26:05 +03:00
|
|
|
tcg_out_rlw(s, RLWINM, TCG_REG_R0, t, 0,
|
2023-03-24 07:06:22 +03:00
|
|
|
(32 - a_bits) & 31, 31 - s->page_bits);
|
2023-04-23 22:26:05 +03:00
|
|
|
} else if (a_bits == 0) {
|
2023-03-24 07:06:22 +03:00
|
|
|
tcg_out_rld(s, RLDICR, TCG_REG_R0, t, 0, 63 - s->page_bits);
|
2023-04-23 22:26:05 +03:00
|
|
|
} else {
|
|
|
|
tcg_out_rld(s, RLDICL, TCG_REG_R0, t,
|
2023-03-24 07:06:22 +03:00
|
|
|
64 - s->page_bits, s->page_bits - a_bits);
|
|
|
|
tcg_out_rld(s, RLDICL, TCG_REG_R0, TCG_REG_R0, s->page_bits, 0);
|
2023-04-23 22:26:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-27 17:45:50 +03:00
|
|
|
if (TCG_TARGET_REG_BITS == 32 && addr_type != TCG_TYPE_I32) {
|
2023-04-04 01:25:06 +03:00
|
|
|
/* Low part comparison into cr7. */
|
|
|
|
tcg_out_cmp(s, TCG_COND_EQ, TCG_REG_R0, TCG_REG_TMP2,
|
2023-04-23 22:26:05 +03:00
|
|
|
0, 7, TCG_TYPE_I32);
|
2023-04-04 01:25:06 +03:00
|
|
|
|
|
|
|
/* Load the high part TLB comparator into TMP2. */
|
|
|
|
tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_TMP2, TCG_REG_TMP1,
|
|
|
|
cmp_off + 4 * !HOST_BIG_ENDIAN);
|
|
|
|
|
|
|
|
/* Load addend, deferred for this case. */
|
|
|
|
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1,
|
|
|
|
offsetof(CPUTLBEntry, addend));
|
|
|
|
|
|
|
|
/* High part comparison into cr6. */
|
|
|
|
tcg_out_cmp(s, TCG_COND_EQ, addrhi, TCG_REG_TMP2, 0, 6, TCG_TYPE_I32);
|
|
|
|
|
|
|
|
/* Combine comparisons into cr7. */
|
2023-04-23 22:26:05 +03:00
|
|
|
tcg_out32(s, CRAND | BT(7, CR_EQ) | BA(6, CR_EQ) | BB(7, CR_EQ));
|
|
|
|
} else {
|
2023-04-04 01:25:06 +03:00
|
|
|
/* Full comparison into cr7. */
|
2023-04-27 17:45:50 +03:00
|
|
|
tcg_out_cmp(s, TCG_COND_EQ, TCG_REG_R0, TCG_REG_TMP2, 0, 7, addr_type);
|
2023-04-23 22:26:05 +03:00
|
|
|
}
|
2014-03-25 02:44:09 +04:00
|
|
|
|
|
|
|
/* Load a pointer into the current opcode w/conditional branch-link. */
|
2023-04-23 22:26:05 +03:00
|
|
|
ldst->label_ptr[0] = s->code_ptr;
|
2018-11-30 01:48:26 +03:00
|
|
|
tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK);
|
2023-04-04 01:25:06 +03:00
|
|
|
|
|
|
|
h->base = TCG_REG_TMP1;
|
2023-04-23 22:26:05 +03:00
|
|
|
#else
|
2021-08-04 01:08:55 +03:00
|
|
|
if (a_bits) {
|
2023-04-23 22:26:05 +03:00
|
|
|
ldst = new_ldst_label(s);
|
|
|
|
ldst->is_ld = is_ld;
|
|
|
|
ldst->oi = oi;
|
|
|
|
ldst->addrlo_reg = addrlo;
|
|
|
|
ldst->addrhi_reg = addrhi;
|
|
|
|
|
|
|
|
/* We are expecting a_bits to max out at 7, much lower than ANDI. */
|
|
|
|
tcg_debug_assert(a_bits < 16);
|
|
|
|
tcg_out32(s, ANDI | SAI(addrlo, TCG_REG_R0, (1 << a_bits) - 1));
|
|
|
|
|
|
|
|
ldst->label_ptr[0] = s->code_ptr;
|
|
|
|
tcg_out32(s, BC | BI(0, CR_EQ) | BO_COND_FALSE | LK);
|
2021-08-04 01:08:55 +03:00
|
|
|
}
|
2023-04-23 22:26:05 +03:00
|
|
|
|
|
|
|
h->base = guest_base ? TCG_GUEST_BASE_REG : 0;
|
2023-04-04 01:25:06 +03:00
|
|
|
#endif
|
|
|
|
|
2023-04-27 17:45:50 +03:00
|
|
|
if (TCG_TARGET_REG_BITS == 64 && addr_type == TCG_TYPE_I32) {
|
2023-04-04 01:25:06 +03:00
|
|
|
/* Zero-extend the guest address for use in the host address. */
|
|
|
|
tcg_out_ext32u(s, TCG_REG_R0, addrlo);
|
|
|
|
h->index = TCG_REG_R0;
|
|
|
|
} else {
|
|
|
|
h->index = addrlo;
|
2014-03-25 02:44:09 +04:00
|
|
|
}
|
|
|
|
|
2023-04-23 22:26:05 +03:00
|
|
|
return ldst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tcg_out_qemu_ld(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
|
|
|
TCGReg addrlo, TCGReg addrhi,
|
|
|
|
MemOpIdx oi, TCGType data_type)
|
|
|
|
{
|
|
|
|
MemOp opc = get_memop(oi);
|
|
|
|
TCGLabelQemuLdst *ldst;
|
|
|
|
HostAddress h;
|
|
|
|
|
|
|
|
ldst = prepare_host_addr(s, &h, addrlo, addrhi, oi, true);
|
|
|
|
|
|
|
|
if (TCG_TARGET_REG_BITS == 32 && (opc & MO_SIZE) == MO_64) {
|
2014-03-25 23:11:48 +04:00
|
|
|
if (opc & MO_BSWAP) {
|
2023-04-23 22:10:00 +03:00
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_R0, h.index, 4));
|
|
|
|
tcg_out32(s, LWBRX | TAB(datalo, h.base, h.index));
|
|
|
|
tcg_out32(s, LWBRX | TAB(datahi, h.base, TCG_REG_R0));
|
|
|
|
} else if (h.base != 0) {
|
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_R0, h.index, 4));
|
|
|
|
tcg_out32(s, LWZX | TAB(datahi, h.base, h.index));
|
|
|
|
tcg_out32(s, LWZX | TAB(datalo, h.base, TCG_REG_R0));
|
|
|
|
} else if (h.index == datahi) {
|
|
|
|
tcg_out32(s, LWZ | TAI(datalo, h.index, 4));
|
|
|
|
tcg_out32(s, LWZ | TAI(datahi, h.index, 0));
|
2014-03-25 23:11:48 +04:00
|
|
|
} else {
|
2023-04-23 22:10:00 +03:00
|
|
|
tcg_out32(s, LWZ | TAI(datahi, h.index, 0));
|
|
|
|
tcg_out32(s, LWZ | TAI(datalo, h.index, 4));
|
2014-03-25 23:11:48 +04:00
|
|
|
}
|
2013-08-31 16:14:53 +04:00
|
|
|
} else {
|
2015-05-29 19:16:51 +03:00
|
|
|
uint32_t insn = qemu_ldx_opc[opc & (MO_BSWAP | MO_SSIZE)];
|
2019-09-30 05:56:34 +03:00
|
|
|
if (!have_isa_2_06 && insn == LDBRX) {
|
2023-04-23 22:10:00 +03:00
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_R0, h.index, 4));
|
|
|
|
tcg_out32(s, LWBRX | TAB(datalo, h.base, h.index));
|
|
|
|
tcg_out32(s, LWBRX | TAB(TCG_REG_R0, h.base, TCG_REG_R0));
|
2014-03-25 23:11:48 +04:00
|
|
|
tcg_out_rld(s, RLDIMI, datalo, TCG_REG_R0, 32, 0);
|
|
|
|
} else if (insn) {
|
2023-04-23 22:10:00 +03:00
|
|
|
tcg_out32(s, insn | TAB(datalo, h.base, h.index));
|
2014-03-25 23:11:48 +04:00
|
|
|
} else {
|
|
|
|
insn = qemu_ldx_opc[opc & (MO_SIZE | MO_BSWAP)];
|
2023-04-23 22:10:00 +03:00
|
|
|
tcg_out32(s, insn | TAB(datalo, h.base, h.index));
|
2023-04-06 07:16:28 +03:00
|
|
|
tcg_out_movext(s, TCG_TYPE_REG, datalo,
|
|
|
|
TCG_TYPE_REG, opc & MO_SSIZE, datalo);
|
2014-03-25 23:11:48 +04:00
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2023-04-23 22:26:05 +03:00
|
|
|
if (ldst) {
|
|
|
|
ldst->type = data_type;
|
|
|
|
ldst->datalo_reg = datalo;
|
|
|
|
ldst->datahi_reg = datahi;
|
|
|
|
ldst->raddr = tcg_splitwx_to_rx(s->code_ptr);
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2023-04-06 22:53:46 +03:00
|
|
|
static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
|
|
|
TCGReg addrlo, TCGReg addrhi,
|
|
|
|
MemOpIdx oi, TCGType data_type)
|
2013-02-02 01:00:05 +04:00
|
|
|
{
|
2023-04-06 22:53:46 +03:00
|
|
|
MemOp opc = get_memop(oi);
|
2023-04-23 22:26:05 +03:00
|
|
|
TCGLabelQemuLdst *ldst;
|
2023-04-23 22:10:00 +03:00
|
|
|
HostAddress h;
|
2023-04-06 22:53:46 +03:00
|
|
|
|
2023-04-23 22:26:05 +03:00
|
|
|
ldst = prepare_host_addr(s, &h, addrlo, addrhi, oi, false);
|
2013-02-02 01:00:05 +04:00
|
|
|
|
2023-04-23 22:26:05 +03:00
|
|
|
if (TCG_TARGET_REG_BITS == 32 && (opc & MO_SIZE) == MO_64) {
|
2014-03-25 23:11:48 +04:00
|
|
|
if (opc & MO_BSWAP) {
|
2023-04-23 22:10:00 +03:00
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_R0, h.index, 4));
|
|
|
|
tcg_out32(s, STWBRX | SAB(datalo, h.base, h.index));
|
|
|
|
tcg_out32(s, STWBRX | SAB(datahi, h.base, TCG_REG_R0));
|
|
|
|
} else if (h.base != 0) {
|
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_R0, h.index, 4));
|
|
|
|
tcg_out32(s, STWX | SAB(datahi, h.base, h.index));
|
|
|
|
tcg_out32(s, STWX | SAB(datalo, h.base, TCG_REG_R0));
|
2014-03-25 23:11:48 +04:00
|
|
|
} else {
|
2023-04-23 22:10:00 +03:00
|
|
|
tcg_out32(s, STW | TAI(datahi, h.index, 0));
|
|
|
|
tcg_out32(s, STW | TAI(datalo, h.index, 4));
|
2014-03-25 23:11:48 +04:00
|
|
|
}
|
2013-02-02 01:00:05 +04:00
|
|
|
} else {
|
2015-05-29 19:16:51 +03:00
|
|
|
uint32_t insn = qemu_stx_opc[opc & (MO_BSWAP | MO_SIZE)];
|
2019-09-30 05:56:34 +03:00
|
|
|
if (!have_isa_2_06 && insn == STDBRX) {
|
2023-04-23 22:10:00 +03:00
|
|
|
tcg_out32(s, STWBRX | SAB(datalo, h.base, h.index));
|
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_TMP1, h.index, 4));
|
2014-03-25 23:11:48 +04:00
|
|
|
tcg_out_shri64(s, TCG_REG_R0, datalo, 32);
|
2023-04-23 22:10:00 +03:00
|
|
|
tcg_out32(s, STWBRX | SAB(TCG_REG_R0, h.base, TCG_REG_TMP1));
|
2014-03-25 23:11:48 +04:00
|
|
|
} else {
|
2023-04-23 22:10:00 +03:00
|
|
|
tcg_out32(s, insn | SAB(datalo, h.base, h.index));
|
2014-03-25 23:11:48 +04:00
|
|
|
}
|
2013-02-02 01:00:05 +04:00
|
|
|
}
|
2014-03-25 02:44:09 +04:00
|
|
|
|
2023-04-23 22:26:05 +03:00
|
|
|
if (ldst) {
|
|
|
|
ldst->type = data_type;
|
|
|
|
ldst->datalo_reg = datalo;
|
|
|
|
ldst->datahi_reg = datahi;
|
|
|
|
ldst->raddr = tcg_splitwx_to_rx(s->code_ptr);
|
|
|
|
}
|
2013-02-02 01:00:05 +04:00
|
|
|
}
|
|
|
|
|
2023-04-19 16:13:22 +03:00
|
|
|
static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
|
|
|
TCGReg addr_reg, MemOpIdx oi, bool is_ld)
|
|
|
|
{
|
|
|
|
TCGLabelQemuLdst *ldst;
|
|
|
|
HostAddress h;
|
|
|
|
bool need_bswap;
|
|
|
|
uint32_t insn;
|
|
|
|
TCGReg index;
|
|
|
|
|
|
|
|
ldst = prepare_host_addr(s, &h, addr_reg, -1, oi, is_ld);
|
|
|
|
|
|
|
|
/* Compose the final address, as LQ/STQ have no indexing. */
|
|
|
|
index = h.index;
|
|
|
|
if (h.base != 0) {
|
|
|
|
index = TCG_REG_TMP1;
|
|
|
|
tcg_out32(s, ADD | TAB(index, h.base, h.index));
|
|
|
|
}
|
|
|
|
need_bswap = get_memop(oi) & MO_BSWAP;
|
|
|
|
|
|
|
|
if (h.aa.atom == MO_128) {
|
|
|
|
tcg_debug_assert(!need_bswap);
|
|
|
|
tcg_debug_assert(datalo & 1);
|
|
|
|
tcg_debug_assert(datahi == datalo - 1);
|
|
|
|
insn = is_ld ? LQ : STQ;
|
|
|
|
tcg_out32(s, insn | TAI(datahi, index, 0));
|
|
|
|
} else {
|
|
|
|
TCGReg d1, d2;
|
|
|
|
|
|
|
|
if (HOST_BIG_ENDIAN ^ need_bswap) {
|
|
|
|
d1 = datahi, d2 = datalo;
|
|
|
|
} else {
|
|
|
|
d1 = datalo, d2 = datahi;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (need_bswap) {
|
|
|
|
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, 8);
|
|
|
|
insn = is_ld ? LDBRX : STDBRX;
|
|
|
|
tcg_out32(s, insn | TAB(d1, 0, index));
|
|
|
|
tcg_out32(s, insn | TAB(d2, index, TCG_REG_R0));
|
|
|
|
} else {
|
|
|
|
insn = is_ld ? LD : STD;
|
|
|
|
tcg_out32(s, insn | TAI(d1, index, 0));
|
|
|
|
tcg_out32(s, insn | TAI(d2, index, 8));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ldst) {
|
|
|
|
ldst->type = TCG_TYPE_I128;
|
|
|
|
ldst->datalo_reg = datalo;
|
|
|
|
ldst->datahi_reg = datahi;
|
|
|
|
ldst->raddr = tcg_splitwx_to_rx(s->code_ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-31 09:03:03 +03:00
|
|
|
static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
p[i] = NOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-25 19:11:53 +04:00
|
|
|
/* Parameters for function call generation, used in tcg.c. */
|
|
|
|
#define TCG_TARGET_STACK_ALIGN 16
|
|
|
|
|
2014-03-25 19:55:12 +04:00
|
|
|
#ifdef _CALL_AIX
|
|
|
|
# define LINK_AREA_SIZE (6 * SZR)
|
|
|
|
# define LR_OFFSET (1 * SZR)
|
|
|
|
# define TCG_TARGET_CALL_STACK_OFFSET (LINK_AREA_SIZE + 8 * SZR)
|
2021-07-13 00:17:37 +03:00
|
|
|
#elif defined(_CALL_DARWIN)
|
2014-06-26 19:37:17 +04:00
|
|
|
# define LINK_AREA_SIZE (6 * SZR)
|
|
|
|
# define LR_OFFSET (2 * SZR)
|
2014-03-25 20:13:38 +04:00
|
|
|
#elif TCG_TARGET_REG_BITS == 64
|
|
|
|
# if defined(_CALL_ELF) && _CALL_ELF == 2
|
|
|
|
# define LINK_AREA_SIZE (4 * SZR)
|
|
|
|
# define LR_OFFSET (1 * SZR)
|
|
|
|
# endif
|
|
|
|
#else /* TCG_TARGET_REG_BITS == 32 */
|
|
|
|
# if defined(_CALL_SYSV)
|
|
|
|
# define LINK_AREA_SIZE (2 * SZR)
|
|
|
|
# define LR_OFFSET (1 * SZR)
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
#ifndef LR_OFFSET
|
|
|
|
# error "Unhandled abi"
|
|
|
|
#endif
|
|
|
|
#ifndef TCG_TARGET_CALL_STACK_OFFSET
|
2014-03-25 19:57:23 +04:00
|
|
|
# define TCG_TARGET_CALL_STACK_OFFSET LINK_AREA_SIZE
|
2014-03-25 19:55:12 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define CPU_TEMP_BUF_SIZE (CPU_TEMP_BUF_NLONGS * (int)sizeof(long))
|
|
|
|
#define REG_SAVE_SIZE ((int)ARRAY_SIZE(tcg_target_callee_save_regs) * SZR)
|
2014-03-25 02:44:09 +04:00
|
|
|
|
2014-03-25 19:55:12 +04:00
|
|
|
#define FRAME_SIZE ((TCG_TARGET_CALL_STACK_OFFSET \
|
|
|
|
+ TCG_STATIC_CALL_ARGS_SIZE \
|
|
|
|
+ CPU_TEMP_BUF_SIZE \
|
|
|
|
+ REG_SAVE_SIZE \
|
|
|
|
+ TCG_TARGET_STACK_ALIGN - 1) \
|
|
|
|
& -TCG_TARGET_STACK_ALIGN)
|
|
|
|
|
|
|
|
#define REG_SAVE_BOT (FRAME_SIZE - REG_SAVE_SIZE)
|
2014-03-25 02:44:09 +04:00
|
|
|
|
|
|
|
static void tcg_target_qemu_prologue(TCGContext *s)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2014-03-25 02:44:09 +04:00
|
|
|
int i;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2014-03-25 19:55:12 +04:00
|
|
|
#ifdef _CALL_AIX
|
2020-11-04 21:17:46 +03:00
|
|
|
const void **desc = (const void **)s->code_ptr;
|
|
|
|
desc[0] = tcg_splitwx_to_rx(desc + 2); /* entry point */
|
|
|
|
desc[1] = 0; /* environment pointer */
|
|
|
|
s->code_ptr = (void *)(desc + 2); /* skip over descriptor */
|
2014-03-25 02:44:09 +04:00
|
|
|
#endif
|
|
|
|
|
2014-03-28 17:53:53 +04:00
|
|
|
tcg_set_frame(s, TCG_REG_CALL_STACK, REG_SAVE_BOT - CPU_TEMP_BUF_SIZE,
|
|
|
|
CPU_TEMP_BUF_SIZE);
|
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
/* Prologue */
|
|
|
|
tcg_out32(s, MFSPR | RT(TCG_REG_R0) | LR);
|
2014-03-25 20:13:38 +04:00
|
|
|
tcg_out32(s, (SZR == 8 ? STDU : STWU)
|
|
|
|
| SAI(TCG_REG_R1, TCG_REG_R1, -FRAME_SIZE));
|
2014-03-25 19:55:12 +04:00
|
|
|
|
2014-03-25 02:44:09 +04:00
|
|
|
for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); ++i) {
|
2014-03-25 03:03:59 +04:00
|
|
|
tcg_out_st(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i],
|
|
|
|
TCG_REG_R1, REG_SAVE_BOT + i * SZR);
|
2014-03-25 02:44:09 +04:00
|
|
|
}
|
2014-03-25 19:55:12 +04:00
|
|
|
tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_R0, TCG_REG_R1, FRAME_SIZE+LR_OFFSET);
|
2014-03-25 02:44:09 +04:00
|
|
|
|
2015-08-24 02:42:07 +03:00
|
|
|
#ifndef CONFIG_SOFTMMU
|
2015-08-24 15:53:54 +03:00
|
|
|
if (guest_base) {
|
2017-07-31 07:16:10 +03:00
|
|
|
tcg_out_movi_int(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base, true);
|
2014-03-25 02:44:09 +04:00
|
|
|
tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
|
|
|
|
tcg_out32(s, MTSPR | RS(tcg_target_call_iarg_regs[1]) | CTR);
|
2017-07-31 07:16:10 +03:00
|
|
|
tcg_out32(s, BCCTR | BO_ALWAYS);
|
2014-03-25 02:44:09 +04:00
|
|
|
|
|
|
|
/* Epilogue */
|
2020-11-06 02:41:38 +03:00
|
|
|
tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr);
|
2014-03-25 02:44:09 +04:00
|
|
|
|
2014-03-25 19:55:12 +04:00
|
|
|
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R0, TCG_REG_R1, FRAME_SIZE+LR_OFFSET);
|
2014-03-25 02:44:09 +04:00
|
|
|
for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); ++i) {
|
2014-03-25 03:03:59 +04:00
|
|
|
tcg_out_ld(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i],
|
|
|
|
TCG_REG_R1, REG_SAVE_BOT + i * SZR);
|
2014-03-25 02:44:09 +04:00
|
|
|
}
|
|
|
|
tcg_out32(s, MTSPR | RS(TCG_REG_R0) | LR);
|
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_R1, TCG_REG_R1, FRAME_SIZE));
|
|
|
|
tcg_out32(s, BCLR | BO_ALWAYS);
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
|
2023-08-15 19:34:59 +03:00
|
|
|
static void tcg_out_tb_start(TCGContext *s)
|
|
|
|
{
|
2023-08-15 19:47:11 +03:00
|
|
|
/* Load TCG_REG_TB. */
|
|
|
|
if (USE_REG_TB) {
|
2023-08-15 20:04:42 +03:00
|
|
|
if (have_isa_3_00) {
|
|
|
|
/* lnia REG_TB */
|
|
|
|
tcg_out_addpcis(s, TCG_REG_TB, 0);
|
|
|
|
} else {
|
|
|
|
/* bcl 20,31,$+4 (preferred form for getting nia) */
|
|
|
|
tcg_out32(s, BC | BO_ALWAYS | BI(7, CR_SO) | 0x4 | LK);
|
|
|
|
tcg_out32(s, MFSPR | RT(TCG_REG_TB) | LR);
|
|
|
|
}
|
2023-08-15 19:47:11 +03:00
|
|
|
}
|
2023-08-15 19:34:59 +03:00
|
|
|
}
|
|
|
|
|
2022-11-26 23:42:06 +03:00
|
|
|
static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
|
|
|
|
{
|
|
|
|
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R3, arg);
|
|
|
|
tcg_out_b(s, 0, tcg_code_gen_epilogue);
|
|
|
|
}
|
|
|
|
|
2022-11-27 04:14:05 +03:00
|
|
|
static void tcg_out_goto_tb(TCGContext *s, int which)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2022-12-06 02:45:02 +03:00
|
|
|
uintptr_t ptr = get_jmp_target_addr(s, which);
|
2023-08-15 20:47:47 +03:00
|
|
|
int16_t lo;
|
2022-12-06 02:45:02 +03:00
|
|
|
|
2023-08-15 19:47:11 +03:00
|
|
|
/* Direct branch will be patched by tb_target_set_jmp_target. */
|
|
|
|
set_jmp_insn_offset(s, which);
|
|
|
|
tcg_out32(s, NOP);
|
|
|
|
|
|
|
|
/* When branch is out of range, fall through to indirect. */
|
2022-12-06 02:45:02 +03:00
|
|
|
if (USE_REG_TB) {
|
2023-08-15 19:58:19 +03:00
|
|
|
ptrdiff_t offset = ppc_tbrel_diff(s, (void *)ptr);
|
2023-08-15 19:47:11 +03:00
|
|
|
tcg_out_mem_long(s, LD, LDX, TCG_REG_TMP1, TCG_REG_TB, offset);
|
2023-08-15 20:47:47 +03:00
|
|
|
} else if (have_isa_3_00) {
|
|
|
|
ptrdiff_t offset = tcg_pcrel_diff(s, (void *)ptr) - 4;
|
|
|
|
lo = offset;
|
|
|
|
tcg_out_addpcis(s, TCG_REG_TMP1, offset - lo);
|
|
|
|
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, lo);
|
2022-11-27 04:14:05 +03:00
|
|
|
} else {
|
2023-08-15 20:47:47 +03:00
|
|
|
lo = ptr;
|
|
|
|
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP1, ptr - lo);
|
|
|
|
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, lo);
|
2022-11-27 04:14:05 +03:00
|
|
|
}
|
2023-08-15 19:47:11 +03:00
|
|
|
|
|
|
|
tcg_out32(s, MTSPR | RS(TCG_REG_TMP1) | CTR);
|
|
|
|
tcg_out32(s, BCCTR | BO_ALWAYS);
|
|
|
|
set_jmp_reset_offset(s, which);
|
2022-11-27 04:14:05 +03:00
|
|
|
}
|
|
|
|
|
2022-12-06 02:45:02 +03:00
|
|
|
void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
|
|
|
|
uintptr_t jmp_rx, uintptr_t jmp_rw)
|
|
|
|
{
|
|
|
|
uintptr_t addr = tb->jmp_target_addr[n];
|
|
|
|
intptr_t diff = addr - jmp_rx;
|
|
|
|
tcg_insn_unit insn;
|
|
|
|
|
|
|
|
if (in_range_b(diff)) {
|
|
|
|
insn = B | (diff & 0x3fffffc);
|
|
|
|
} else {
|
|
|
|
insn = NOP;
|
|
|
|
}
|
|
|
|
|
|
|
|
qatomic_set((uint32_t *)jmp_rw, insn);
|
|
|
|
flush_idcache_range(jmp_rx, jmp_rw, 4);
|
|
|
|
}
|
|
|
|
|
2022-11-27 04:14:05 +03:00
|
|
|
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|
|
|
const TCGArg args[TCG_MAX_OP_ARGS],
|
|
|
|
const int const_args[TCG_MAX_OP_ARGS])
|
|
|
|
{
|
|
|
|
TCGArg a0, a1, a2;
|
|
|
|
|
|
|
|
switch (opc) {
|
2017-04-26 14:50:31 +03:00
|
|
|
case INDEX_op_goto_ptr:
|
|
|
|
tcg_out32(s, MTSPR | RS(args[0]) | CTR);
|
2017-07-31 07:16:10 +03:00
|
|
|
tcg_out32(s, ADDI | TAI(TCG_REG_R3, 0, 0));
|
2017-04-26 14:50:31 +03:00
|
|
|
tcg_out32(s, BCCTR | BO_ALWAYS);
|
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
case INDEX_op_br:
|
|
|
|
{
|
2015-02-14 00:39:54 +03:00
|
|
|
TCGLabel *l = arg_label(args[0]);
|
2018-11-30 01:48:26 +03:00
|
|
|
uint32_t insn = B;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
if (l->has_value) {
|
2020-11-04 21:17:46 +03:00
|
|
|
insn |= reloc_pc24_val(tcg_splitwx_to_rx(s->code_ptr),
|
|
|
|
l->u.value_ptr);
|
2013-08-31 16:14:53 +04:00
|
|
|
} else {
|
2015-02-14 00:39:54 +03:00
|
|
|
tcg_out_reloc(s, s->code_ptr, R_PPC_REL24, l, 0);
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
2018-11-30 01:48:26 +03:00
|
|
|
tcg_out32(s, insn);
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INDEX_op_ld8u_i32:
|
|
|
|
case INDEX_op_ld8u_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_ld8s_i32:
|
|
|
|
case INDEX_op_ld8s_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]);
|
2023-04-05 21:17:01 +03:00
|
|
|
tcg_out_ext8s(s, TCG_TYPE_REG, args[0], args[0]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_ld16u_i32:
|
|
|
|
case INDEX_op_ld16u_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, LHZ, LHZX, args[0], args[1], args[2]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_ld16s_i32:
|
|
|
|
case INDEX_op_ld16s_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, LHA, LHAX, args[0], args[1], args[2]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_ld_i32:
|
|
|
|
case INDEX_op_ld32u_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, LWZ, LWZX, args[0], args[1], args[2]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_ld32s_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, LWA, LWAX, args[0], args[1], args[2]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_ld_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, LD, LDX, args[0], args[1], args[2]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_st8_i32:
|
|
|
|
case INDEX_op_st8_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, STB, STBX, args[0], args[1], args[2]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_st16_i32:
|
|
|
|
case INDEX_op_st16_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, STH, STHX, args[0], args[1], args[2]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_st_i32:
|
|
|
|
case INDEX_op_st32_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, STW, STWX, args[0], args[1], args[2]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_st_i64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case INDEX_op_add_i32:
|
2013-02-02 04:17:17 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
|
|
|
if (const_args[2]) {
|
|
|
|
do_addi_32:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, ADDI, ADD, a0, a1, (int32_t)a2);
|
2013-02-02 04:17:17 +04:00
|
|
|
} else {
|
|
|
|
tcg_out32(s, ADD | TAB(a0, a1, a2));
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_sub_i32:
|
2013-02-02 04:17:17 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
2013-04-04 18:30:20 +04:00
|
|
|
if (const_args[1]) {
|
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out_movi(s, TCG_TYPE_I32, a0, a1 - a2);
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, SUBFIC | TAI(a0, a2, a1));
|
|
|
|
}
|
|
|
|
} else if (const_args[2]) {
|
2013-02-02 04:17:17 +04:00
|
|
|
a2 = -a2;
|
|
|
|
goto do_addi_32;
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, SUBF | TAB(a0, a2, a1));
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case INDEX_op_and_i32:
|
2013-03-05 01:48:38 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
2013-02-02 11:43:42 +04:00
|
|
|
if (const_args[2]) {
|
2013-03-05 01:48:38 +04:00
|
|
|
tcg_out_andi32(s, a0, a1, a2);
|
2013-02-02 11:43:42 +04:00
|
|
|
} else {
|
2013-03-05 01:48:38 +04:00
|
|
|
tcg_out32(s, AND | SAB(a1, a0, a2));
|
2013-02-02 11:43:42 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INDEX_op_and_i64:
|
2013-03-05 01:48:38 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
2008-07-23 23:17:46 +04:00
|
|
|
if (const_args[2]) {
|
2013-03-05 01:48:38 +04:00
|
|
|
tcg_out_andi64(s, a0, a1, a2);
|
2013-02-02 11:58:17 +04:00
|
|
|
} else {
|
2013-03-05 01:48:38 +04:00
|
|
|
tcg_out32(s, AND | SAB(a1, a0, a2));
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
break;
|
2008-07-29 03:46:06 +04:00
|
|
|
case INDEX_op_or_i64:
|
2008-07-23 23:17:46 +04:00
|
|
|
case INDEX_op_or_i32:
|
2013-02-02 08:22:05 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
2008-07-23 23:17:46 +04:00
|
|
|
if (const_args[2]) {
|
2013-02-02 08:22:05 +04:00
|
|
|
tcg_out_ori32(s, a0, a1, a2);
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, OR | SAB(a1, a0, a2));
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
break;
|
2008-07-29 03:46:06 +04:00
|
|
|
case INDEX_op_xor_i64:
|
2008-07-23 23:17:46 +04:00
|
|
|
case INDEX_op_xor_i32:
|
2013-02-02 08:22:05 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
2008-07-23 23:17:46 +04:00
|
|
|
if (const_args[2]) {
|
2013-02-02 08:22:05 +04:00
|
|
|
tcg_out_xori32(s, a0, a1, a2);
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, XOR | SAB(a1, a0, a2));
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
break;
|
2013-01-31 19:49:13 +04:00
|
|
|
case INDEX_op_andc_i32:
|
2013-03-05 01:48:38 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out_andi32(s, a0, a1, ~a2);
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, ANDC | SAB(a1, a0, a2));
|
|
|
|
}
|
|
|
|
break;
|
2013-01-31 19:49:13 +04:00
|
|
|
case INDEX_op_andc_i64:
|
2013-03-05 01:48:38 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out_andi64(s, a0, a1, ~a2);
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, ANDC | SAB(a1, a0, a2));
|
|
|
|
}
|
2013-01-31 19:49:13 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_orc_i32:
|
2013-03-05 01:48:38 +04:00
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out_ori32(s, args[0], args[1], ~args[2]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* FALLTHRU */
|
2013-01-31 19:49:13 +04:00
|
|
|
case INDEX_op_orc_i64:
|
|
|
|
tcg_out32(s, ORC | SAB(args[1], args[0], args[2]));
|
|
|
|
break;
|
|
|
|
case INDEX_op_eqv_i32:
|
2013-03-05 01:48:38 +04:00
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out_xori32(s, args[0], args[1], ~args[2]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* FALLTHRU */
|
2013-01-31 19:49:13 +04:00
|
|
|
case INDEX_op_eqv_i64:
|
|
|
|
tcg_out32(s, EQV | SAB(args[1], args[0], args[2]));
|
|
|
|
break;
|
|
|
|
case INDEX_op_nand_i32:
|
|
|
|
case INDEX_op_nand_i64:
|
|
|
|
tcg_out32(s, NAND | SAB(args[1], args[0], args[2]));
|
|
|
|
break;
|
|
|
|
case INDEX_op_nor_i32:
|
|
|
|
case INDEX_op_nor_i64:
|
|
|
|
tcg_out32(s, NOR | SAB(args[1], args[0], args[2]));
|
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2016-11-16 14:48:55 +03:00
|
|
|
case INDEX_op_clz_i32:
|
|
|
|
tcg_out_cntxz(s, TCG_TYPE_I32, CNTLZW, args[0], args[1],
|
|
|
|
args[2], const_args[2]);
|
|
|
|
break;
|
|
|
|
case INDEX_op_ctz_i32:
|
|
|
|
tcg_out_cntxz(s, TCG_TYPE_I32, CNTTZW, args[0], args[1],
|
|
|
|
args[2], const_args[2]);
|
|
|
|
break;
|
2016-11-22 14:43:12 +03:00
|
|
|
case INDEX_op_ctpop_i32:
|
|
|
|
tcg_out32(s, CNTPOPW | SAB(args[1], args[0], 0));
|
|
|
|
break;
|
2016-11-16 14:48:55 +03:00
|
|
|
|
|
|
|
case INDEX_op_clz_i64:
|
|
|
|
tcg_out_cntxz(s, TCG_TYPE_I64, CNTLZD, args[0], args[1],
|
|
|
|
args[2], const_args[2]);
|
|
|
|
break;
|
|
|
|
case INDEX_op_ctz_i64:
|
|
|
|
tcg_out_cntxz(s, TCG_TYPE_I64, CNTTZD, args[0], args[1],
|
|
|
|
args[2], const_args[2]);
|
|
|
|
break;
|
2016-11-22 14:43:12 +03:00
|
|
|
case INDEX_op_ctpop_i64:
|
|
|
|
tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0));
|
|
|
|
break;
|
2016-11-16 14:48:55 +03:00
|
|
|
|
2008-07-23 23:17:46 +04:00
|
|
|
case INDEX_op_mul_i32:
|
2013-01-31 21:45:11 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
2008-07-23 23:17:46 +04:00
|
|
|
if (const_args[2]) {
|
2013-01-31 21:45:11 +04:00
|
|
|
tcg_out32(s, MULLI | TAI(a0, a1, a2));
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, MULLW | TAB(a0, a1, a2));
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INDEX_op_div_i32:
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out32(s, DIVW | TAB(args[0], args[1], args[2]));
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case INDEX_op_divu_i32:
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out32(s, DIVWU | TAB(args[0], args[1], args[2]));
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
|
2022-06-13 17:43:59 +03:00
|
|
|
case INDEX_op_rem_i32:
|
|
|
|
tcg_out32(s, MODSW | TAB(args[0], args[1], args[2]));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INDEX_op_remu_i32:
|
|
|
|
tcg_out32(s, MODUW | TAB(args[0], args[1], args[2]));
|
|
|
|
break;
|
|
|
|
|
2008-07-23 23:17:46 +04:00
|
|
|
case INDEX_op_shl_i32:
|
|
|
|
if (const_args[2]) {
|
2020-06-08 00:10:59 +03:00
|
|
|
/* Limit immediate shift count lest we create an illegal insn. */
|
|
|
|
tcg_out_shli32(s, args[0], args[1], args[2] & 31);
|
2013-02-02 03:00:45 +04:00
|
|
|
} else {
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out32(s, SLW | SAB(args[1], args[0], args[2]));
|
2013-02-02 03:00:45 +04:00
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_shr_i32:
|
|
|
|
if (const_args[2]) {
|
2020-06-08 00:10:59 +03:00
|
|
|
/* Limit immediate shift count lest we create an illegal insn. */
|
|
|
|
tcg_out_shri32(s, args[0], args[1], args[2] & 31);
|
2013-02-02 03:00:45 +04:00
|
|
|
} else {
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out32(s, SRW | SAB(args[1], args[0], args[2]));
|
2013-02-02 03:00:45 +04:00
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_sar_i32:
|
2013-08-31 16:14:53 +04:00
|
|
|
if (const_args[2]) {
|
2021-06-13 19:04:40 +03:00
|
|
|
tcg_out_sari32(s, args[0], args[1], args[2]);
|
2013-08-31 16:14:53 +04:00
|
|
|
} else {
|
|
|
|
tcg_out32(s, SRAW | SAB(args[1], args[0], args[2]));
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
2013-01-31 07:24:06 +04:00
|
|
|
case INDEX_op_rotl_i32:
|
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out_rlw(s, RLWINM, args[0], args[1], args[2], 0, 31);
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, RLWNM | SAB(args[1], args[0], args[2])
|
|
|
|
| MB(0) | ME(31));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INDEX_op_rotr_i32:
|
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out_rlw(s, RLWINM, args[0], args[1], 32 - args[2], 0, 31);
|
|
|
|
} else {
|
2013-08-31 16:41:45 +04:00
|
|
|
tcg_out32(s, SUBFIC | TAI(TCG_REG_R0, args[2], 32));
|
|
|
|
tcg_out32(s, RLWNM | SAB(args[1], args[0], TCG_REG_R0)
|
2013-01-31 07:24:06 +04:00
|
|
|
| MB(0) | ME(31));
|
|
|
|
}
|
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
case INDEX_op_brcond_i32:
|
2013-04-03 01:58:27 +04:00
|
|
|
tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
|
2015-02-14 00:39:54 +03:00
|
|
|
arg_label(args[3]), TCG_TYPE_I32);
|
2008-07-28 23:42:23 +04:00
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
case INDEX_op_brcond_i64:
|
2013-04-03 01:58:27 +04:00
|
|
|
tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
|
2015-02-14 00:39:54 +03:00
|
|
|
arg_label(args[3]), TCG_TYPE_I64);
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
2014-04-30 22:55:34 +04:00
|
|
|
case INDEX_op_brcond2_i32:
|
|
|
|
tcg_out_brcond2(s, args, const_args);
|
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
case INDEX_op_neg_i32:
|
|
|
|
case INDEX_op_neg_i64:
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out32(s, NEG | RT(args[0]) | RA(args[1]));
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
|
2011-08-22 14:40:00 +04:00
|
|
|
case INDEX_op_not_i32:
|
|
|
|
case INDEX_op_not_i64:
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out32(s, NOR | SAB(args[1], args[0], args[1]));
|
2011-08-22 14:40:00 +04:00
|
|
|
break;
|
|
|
|
|
2008-07-23 23:17:46 +04:00
|
|
|
case INDEX_op_add_i64:
|
2013-02-02 04:17:17 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
|
|
|
if (const_args[2]) {
|
|
|
|
do_addi_64:
|
2013-07-31 22:36:42 +04:00
|
|
|
tcg_out_mem_long(s, ADDI, ADD, a0, a1, a2);
|
2013-02-02 04:17:17 +04:00
|
|
|
} else {
|
|
|
|
tcg_out32(s, ADD | TAB(a0, a1, a2));
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_sub_i64:
|
2013-02-02 04:17:17 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
2013-04-04 18:30:20 +04:00
|
|
|
if (const_args[1]) {
|
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out_movi(s, TCG_TYPE_I64, a0, a1 - a2);
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, SUBFIC | TAI(a0, a2, a1));
|
|
|
|
}
|
|
|
|
} else if (const_args[2]) {
|
2013-02-02 04:17:17 +04:00
|
|
|
a2 = -a2;
|
|
|
|
goto do_addi_64;
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, SUBF | TAB(a0, a2, a1));
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case INDEX_op_shl_i64:
|
2013-08-31 16:14:53 +04:00
|
|
|
if (const_args[2]) {
|
2020-06-08 00:10:59 +03:00
|
|
|
/* Limit immediate shift count lest we create an illegal insn. */
|
|
|
|
tcg_out_shli64(s, args[0], args[1], args[2] & 63);
|
2013-08-31 16:14:53 +04:00
|
|
|
} else {
|
|
|
|
tcg_out32(s, SLD | SAB(args[1], args[0], args[2]));
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_shr_i64:
|
2013-08-31 16:14:53 +04:00
|
|
|
if (const_args[2]) {
|
2020-06-08 00:10:59 +03:00
|
|
|
/* Limit immediate shift count lest we create an illegal insn. */
|
|
|
|
tcg_out_shri64(s, args[0], args[1], args[2] & 63);
|
2013-08-31 16:14:53 +04:00
|
|
|
} else {
|
|
|
|
tcg_out32(s, SRD | SAB(args[1], args[0], args[2]));
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_sar_i64:
|
2008-07-29 03:46:06 +04:00
|
|
|
if (const_args[2]) {
|
2021-06-13 19:04:40 +03:00
|
|
|
tcg_out_sari64(s, args[0], args[1], args[2]);
|
2013-08-31 16:14:53 +04:00
|
|
|
} else {
|
|
|
|
tcg_out32(s, SRAD | SAB(args[1], args[0], args[2]));
|
2008-07-29 03:46:06 +04:00
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
2013-01-31 07:24:06 +04:00
|
|
|
case INDEX_op_rotl_i64:
|
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out_rld(s, RLDICL, args[0], args[1], args[2], 0);
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, RLDCL | SAB(args[1], args[0], args[2]) | MB64(0));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INDEX_op_rotr_i64:
|
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out_rld(s, RLDICL, args[0], args[1], 64 - args[2], 0);
|
|
|
|
} else {
|
2013-08-31 16:41:45 +04:00
|
|
|
tcg_out32(s, SUBFIC | TAI(TCG_REG_R0, args[2], 64));
|
|
|
|
tcg_out32(s, RLDCL | SAB(args[1], args[0], TCG_REG_R0) | MB64(0));
|
2013-01-31 07:24:06 +04:00
|
|
|
}
|
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
|
|
|
case INDEX_op_mul_i64:
|
2013-01-31 21:45:11 +04:00
|
|
|
a0 = args[0], a1 = args[1], a2 = args[2];
|
|
|
|
if (const_args[2]) {
|
|
|
|
tcg_out32(s, MULLI | TAI(a0, a1, a2));
|
|
|
|
} else {
|
|
|
|
tcg_out32(s, MULLD | TAB(a0, a1, a2));
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_div_i64:
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out32(s, DIVD | TAB(args[0], args[1], args[2]));
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_divu_i64:
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out32(s, DIVDU | TAB(args[0], args[1], args[2]));
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
2022-06-13 17:43:59 +03:00
|
|
|
case INDEX_op_rem_i64:
|
|
|
|
tcg_out32(s, MODSD | TAB(args[0], args[1], args[2]));
|
|
|
|
break;
|
|
|
|
case INDEX_op_remu_i64:
|
|
|
|
tcg_out32(s, MODUD | TAB(args[0], args[1], args[2]));
|
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2023-05-17 06:07:20 +03:00
|
|
|
case INDEX_op_qemu_ld_a64_i32:
|
|
|
|
if (TCG_TARGET_REG_BITS == 32) {
|
2023-04-06 22:53:46 +03:00
|
|
|
tcg_out_qemu_ld(s, args[0], -1, args[1], args[2],
|
|
|
|
args[3], TCG_TYPE_I32);
|
2023-05-17 06:07:20 +03:00
|
|
|
break;
|
2023-04-06 22:53:46 +03:00
|
|
|
}
|
2023-05-17 06:07:20 +03:00
|
|
|
/* fall through */
|
|
|
|
case INDEX_op_qemu_ld_a32_i32:
|
|
|
|
tcg_out_qemu_ld(s, args[0], -1, args[1], -1, args[2], TCG_TYPE_I32);
|
2014-03-25 23:11:48 +04:00
|
|
|
break;
|
2023-05-17 06:07:20 +03:00
|
|
|
case INDEX_op_qemu_ld_a32_i64:
|
2023-04-06 22:53:46 +03:00
|
|
|
if (TCG_TARGET_REG_BITS == 64) {
|
|
|
|
tcg_out_qemu_ld(s, args[0], -1, args[1], -1,
|
|
|
|
args[2], TCG_TYPE_I64);
|
2023-05-17 06:07:20 +03:00
|
|
|
} else {
|
2023-04-06 22:53:46 +03:00
|
|
|
tcg_out_qemu_ld(s, args[0], args[1], args[2], -1,
|
|
|
|
args[3], TCG_TYPE_I64);
|
2023-05-17 06:07:20 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INDEX_op_qemu_ld_a64_i64:
|
|
|
|
if (TCG_TARGET_REG_BITS == 64) {
|
|
|
|
tcg_out_qemu_ld(s, args[0], -1, args[1], -1,
|
|
|
|
args[2], TCG_TYPE_I64);
|
2023-04-06 22:53:46 +03:00
|
|
|
} else {
|
|
|
|
tcg_out_qemu_ld(s, args[0], args[1], args[2], args[3],
|
|
|
|
args[4], TCG_TYPE_I64);
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
2023-04-19 16:13:22 +03:00
|
|
|
case INDEX_op_qemu_ld_a32_i128:
|
|
|
|
case INDEX_op_qemu_ld_a64_i128:
|
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
|
|
|
|
tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], true);
|
|
|
|
break;
|
2023-05-17 06:07:20 +03:00
|
|
|
|
|
|
|
case INDEX_op_qemu_st_a64_i32:
|
|
|
|
if (TCG_TARGET_REG_BITS == 32) {
|
2023-04-06 22:53:46 +03:00
|
|
|
tcg_out_qemu_st(s, args[0], -1, args[1], args[2],
|
|
|
|
args[3], TCG_TYPE_I32);
|
2023-05-17 06:07:20 +03:00
|
|
|
break;
|
2023-04-06 22:53:46 +03:00
|
|
|
}
|
2023-05-17 06:07:20 +03:00
|
|
|
/* fall through */
|
|
|
|
case INDEX_op_qemu_st_a32_i32:
|
|
|
|
tcg_out_qemu_st(s, args[0], -1, args[1], -1, args[2], TCG_TYPE_I32);
|
2014-03-25 23:11:48 +04:00
|
|
|
break;
|
2023-05-17 06:07:20 +03:00
|
|
|
case INDEX_op_qemu_st_a32_i64:
|
2023-04-06 22:53:46 +03:00
|
|
|
if (TCG_TARGET_REG_BITS == 64) {
|
|
|
|
tcg_out_qemu_st(s, args[0], -1, args[1], -1,
|
|
|
|
args[2], TCG_TYPE_I64);
|
2023-05-17 06:07:20 +03:00
|
|
|
} else {
|
2023-04-06 22:53:46 +03:00
|
|
|
tcg_out_qemu_st(s, args[0], args[1], args[2], -1,
|
|
|
|
args[3], TCG_TYPE_I64);
|
2023-05-17 06:07:20 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INDEX_op_qemu_st_a64_i64:
|
|
|
|
if (TCG_TARGET_REG_BITS == 64) {
|
|
|
|
tcg_out_qemu_st(s, args[0], -1, args[1], -1,
|
|
|
|
args[2], TCG_TYPE_I64);
|
2023-04-06 22:53:46 +03:00
|
|
|
} else {
|
|
|
|
tcg_out_qemu_st(s, args[0], args[1], args[2], args[3],
|
|
|
|
args[4], TCG_TYPE_I64);
|
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
break;
|
2023-04-19 16:13:22 +03:00
|
|
|
case INDEX_op_qemu_st_a32_i128:
|
|
|
|
case INDEX_op_qemu_st_a64_i128:
|
|
|
|
tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
|
|
|
|
tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false);
|
|
|
|
break;
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2010-02-07 02:48:53 +03:00
|
|
|
case INDEX_op_setcond_i32:
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2],
|
2023-08-05 04:55:23 +03:00
|
|
|
const_args[2], false);
|
2010-02-07 02:48:53 +03:00
|
|
|
break;
|
|
|
|
case INDEX_op_setcond_i64:
|
2013-08-31 16:14:53 +04:00
|
|
|
tcg_out_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2],
|
2023-08-05 04:55:23 +03:00
|
|
|
const_args[2], false);
|
|
|
|
break;
|
|
|
|
case INDEX_op_negsetcond_i32:
|
|
|
|
tcg_out_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2],
|
|
|
|
const_args[2], true);
|
|
|
|
break;
|
|
|
|
case INDEX_op_negsetcond_i64:
|
|
|
|
tcg_out_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2],
|
|
|
|
const_args[2], true);
|
2010-02-07 02:48:53 +03:00
|
|
|
break;
|
2014-04-30 22:55:34 +04:00
|
|
|
case INDEX_op_setcond2_i32:
|
|
|
|
tcg_out_setcond2(s, args, const_args);
|
|
|
|
break;
|
2010-02-07 02:48:53 +03:00
|
|
|
|
2013-01-31 09:16:38 +04:00
|
|
|
case INDEX_op_bswap16_i32:
|
|
|
|
case INDEX_op_bswap16_i64:
|
2021-06-13 19:48:02 +03:00
|
|
|
tcg_out_bswap16(s, args[0], args[1], args[2]);
|
2013-01-31 09:16:38 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_bswap32_i32:
|
2021-06-13 19:48:02 +03:00
|
|
|
tcg_out_bswap32(s, args[0], args[1], 0);
|
|
|
|
break;
|
2013-01-31 09:16:38 +04:00
|
|
|
case INDEX_op_bswap32_i64:
|
2021-06-13 19:48:02 +03:00
|
|
|
tcg_out_bswap32(s, args[0], args[1], args[2]);
|
2013-01-31 09:16:38 +04:00
|
|
|
break;
|
2013-01-31 09:41:54 +04:00
|
|
|
case INDEX_op_bswap64_i64:
|
2021-06-13 19:37:05 +03:00
|
|
|
tcg_out_bswap64(s, args[0], args[1]);
|
2013-01-31 09:41:54 +04:00
|
|
|
break;
|
|
|
|
|
2013-01-31 20:39:30 +04:00
|
|
|
case INDEX_op_deposit_i32:
|
2013-04-04 23:47:22 +04:00
|
|
|
if (const_args[2]) {
|
|
|
|
uint32_t mask = ((2u << (args[4] - 1)) - 1) << args[3];
|
|
|
|
tcg_out_andi32(s, args[0], args[0], ~mask);
|
|
|
|
} else {
|
|
|
|
tcg_out_rlw(s, RLWIMI, args[0], args[2], args[3],
|
|
|
|
32 - args[3] - args[4], 31 - args[3]);
|
|
|
|
}
|
2013-01-31 20:39:30 +04:00
|
|
|
break;
|
|
|
|
case INDEX_op_deposit_i64:
|
2013-04-04 23:47:22 +04:00
|
|
|
if (const_args[2]) {
|
|
|
|
uint64_t mask = ((2ull << (args[4] - 1)) - 1) << args[3];
|
|
|
|
tcg_out_andi64(s, args[0], args[0], ~mask);
|
|
|
|
} else {
|
|
|
|
tcg_out_rld(s, RLDIMI, args[0], args[2], args[3],
|
|
|
|
64 - args[3] - args[4]);
|
|
|
|
}
|
2013-01-31 20:39:30 +04:00
|
|
|
break;
|
|
|
|
|
2016-10-14 22:18:03 +03:00
|
|
|
case INDEX_op_extract_i32:
|
|
|
|
tcg_out_rlw(s, RLWINM, args[0], args[1],
|
|
|
|
32 - args[2], 32 - args[3], 31);
|
|
|
|
break;
|
|
|
|
case INDEX_op_extract_i64:
|
|
|
|
tcg_out_rld(s, RLDICL, args[0], args[1], 64 - args[2], 64 - args[3]);
|
|
|
|
break;
|
|
|
|
|
2013-02-02 01:00:05 +04:00
|
|
|
case INDEX_op_movcond_i32:
|
|
|
|
tcg_out_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], args[2],
|
|
|
|
args[3], args[4], const_args[2]);
|
|
|
|
break;
|
|
|
|
case INDEX_op_movcond_i64:
|
|
|
|
tcg_out_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1], args[2],
|
|
|
|
args[3], args[4], const_args[2]);
|
|
|
|
break;
|
|
|
|
|
2014-04-30 22:39:20 +04:00
|
|
|
#if TCG_TARGET_REG_BITS == 64
|
2013-03-05 02:26:52 +04:00
|
|
|
case INDEX_op_add2_i64:
|
2014-04-30 22:39:20 +04:00
|
|
|
#else
|
|
|
|
case INDEX_op_add2_i32:
|
|
|
|
#endif
|
2013-03-05 02:26:52 +04:00
|
|
|
/* Note that the CA bit is defined based on the word size of the
|
|
|
|
environment. So in 64-bit mode it's always carry-out of bit 63.
|
|
|
|
The fallback code using deposit works just as well for 32-bit. */
|
|
|
|
a0 = args[0], a1 = args[1];
|
2013-06-02 16:29:39 +04:00
|
|
|
if (a0 == args[3] || (!const_args[5] && a0 == args[5])) {
|
2013-03-05 02:26:52 +04:00
|
|
|
a0 = TCG_REG_R0;
|
|
|
|
}
|
2013-06-02 16:29:39 +04:00
|
|
|
if (const_args[4]) {
|
|
|
|
tcg_out32(s, ADDIC | TAI(a0, args[2], args[4]));
|
2013-03-05 02:26:52 +04:00
|
|
|
} else {
|
2013-06-02 16:29:39 +04:00
|
|
|
tcg_out32(s, ADDC | TAB(a0, args[2], args[4]));
|
2013-03-05 02:26:52 +04:00
|
|
|
}
|
|
|
|
if (const_args[5]) {
|
2013-06-02 16:29:39 +04:00
|
|
|
tcg_out32(s, (args[5] ? ADDME : ADDZE) | RT(a1) | RA(args[3]));
|
2013-03-05 02:26:52 +04:00
|
|
|
} else {
|
2013-06-02 16:29:39 +04:00
|
|
|
tcg_out32(s, ADDE | TAB(a1, args[3], args[5]));
|
2013-03-05 02:26:52 +04:00
|
|
|
}
|
|
|
|
if (a0 != args[0]) {
|
2014-03-25 02:22:35 +04:00
|
|
|
tcg_out_mov(s, TCG_TYPE_REG, args[0], a0);
|
2013-03-05 02:26:52 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-04-30 22:39:20 +04:00
|
|
|
#if TCG_TARGET_REG_BITS == 64
|
2013-03-05 02:26:52 +04:00
|
|
|
case INDEX_op_sub2_i64:
|
2014-04-30 22:39:20 +04:00
|
|
|
#else
|
|
|
|
case INDEX_op_sub2_i32:
|
|
|
|
#endif
|
2013-03-05 02:26:52 +04:00
|
|
|
a0 = args[0], a1 = args[1];
|
2014-03-27 05:56:31 +04:00
|
|
|
if (a0 == args[5] || (!const_args[3] && a0 == args[3])) {
|
2013-03-05 02:26:52 +04:00
|
|
|
a0 = TCG_REG_R0;
|
|
|
|
}
|
|
|
|
if (const_args[2]) {
|
2014-03-27 05:56:31 +04:00
|
|
|
tcg_out32(s, SUBFIC | TAI(a0, args[4], args[2]));
|
2013-03-05 02:26:52 +04:00
|
|
|
} else {
|
2014-03-27 05:56:31 +04:00
|
|
|
tcg_out32(s, SUBFC | TAB(a0, args[4], args[2]));
|
2013-03-05 02:26:52 +04:00
|
|
|
}
|
2014-03-27 05:56:31 +04:00
|
|
|
if (const_args[3]) {
|
|
|
|
tcg_out32(s, (args[3] ? SUBFME : SUBFZE) | RT(a1) | RA(args[5]));
|
2013-03-05 02:26:52 +04:00
|
|
|
} else {
|
2014-03-27 05:56:31 +04:00
|
|
|
tcg_out32(s, SUBFE | TAB(a1, args[5], args[3]));
|
2013-03-05 02:26:52 +04:00
|
|
|
}
|
|
|
|
if (a0 != args[0]) {
|
2014-03-25 02:22:35 +04:00
|
|
|
tcg_out_mov(s, TCG_TYPE_REG, args[0], a0);
|
2013-03-05 02:26:52 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-04-30 22:55:34 +04:00
|
|
|
case INDEX_op_muluh_i32:
|
|
|
|
tcg_out32(s, MULHWU | TAB(args[0], args[1], args[2]));
|
|
|
|
break;
|
2014-03-26 22:37:06 +04:00
|
|
|
case INDEX_op_mulsh_i32:
|
|
|
|
tcg_out32(s, MULHW | TAB(args[0], args[1], args[2]));
|
|
|
|
break;
|
2013-08-15 01:46:08 +04:00
|
|
|
case INDEX_op_muluh_i64:
|
|
|
|
tcg_out32(s, MULHDU | TAB(args[0], args[1], args[2]));
|
|
|
|
break;
|
|
|
|
case INDEX_op_mulsh_i64:
|
|
|
|
tcg_out32(s, MULHD | TAB(args[0], args[1], args[2]));
|
2013-03-05 04:20:51 +04:00
|
|
|
break;
|
|
|
|
|
2016-07-14 23:20:19 +03:00
|
|
|
case INDEX_op_mb:
|
|
|
|
tcg_out_mb(s, args[0]);
|
|
|
|
break;
|
|
|
|
|
2014-04-25 23:19:33 +04:00
|
|
|
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
|
|
|
|
case INDEX_op_mov_i64:
|
|
|
|
case INDEX_op_call: /* Always emitted via tcg_out_call. */
|
2022-11-26 23:42:06 +03:00
|
|
|
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
|
2022-11-27 04:14:05 +03:00
|
|
|
case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
|
2023-04-05 21:17:01 +03:00
|
|
|
case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */
|
|
|
|
case INDEX_op_ext8s_i64:
|
2023-04-05 23:26:51 +03:00
|
|
|
case INDEX_op_ext8u_i32:
|
|
|
|
case INDEX_op_ext8u_i64:
|
2023-04-06 00:49:59 +03:00
|
|
|
case INDEX_op_ext16s_i32:
|
|
|
|
case INDEX_op_ext16s_i64:
|
2023-04-06 02:25:22 +03:00
|
|
|
case INDEX_op_ext16u_i32:
|
|
|
|
case INDEX_op_ext16u_i64:
|
2023-04-06 03:50:09 +03:00
|
|
|
case INDEX_op_ext32s_i64:
|
2023-04-06 04:07:05 +03:00
|
|
|
case INDEX_op_ext32u_i64:
|
2023-04-06 04:30:56 +03:00
|
|
|
case INDEX_op_ext_i32_i64:
|
2023-04-06 04:56:28 +03:00
|
|
|
case INDEX_op_extu_i32_i64:
|
2023-04-06 05:58:35 +03:00
|
|
|
case INDEX_op_extrl_i64_i32:
|
2008-07-23 23:17:46 +04:00
|
|
|
default:
|
2023-04-05 22:09:14 +03:00
|
|
|
g_assert_not_reached();
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 20:04:35 +03:00
|
|
|
int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
|
|
|
|
{
|
2019-06-23 20:04:38 +03:00
|
|
|
switch (opc) {
|
|
|
|
case INDEX_op_and_vec:
|
|
|
|
case INDEX_op_or_vec:
|
|
|
|
case INDEX_op_xor_vec:
|
|
|
|
case INDEX_op_andc_vec:
|
|
|
|
case INDEX_op_not_vec:
|
2021-12-18 05:52:59 +03:00
|
|
|
case INDEX_op_nor_vec:
|
|
|
|
case INDEX_op_eqv_vec:
|
|
|
|
case INDEX_op_nand_vec:
|
2019-06-23 20:04:38 +03:00
|
|
|
return 1;
|
2019-09-30 06:39:24 +03:00
|
|
|
case INDEX_op_orc_vec:
|
|
|
|
return have_isa_2_07;
|
2019-06-23 20:04:40 +03:00
|
|
|
case INDEX_op_add_vec:
|
|
|
|
case INDEX_op_sub_vec:
|
tcg/ppc: Add support for vector maximum/minimum
Add support for vector maximum/minimum using Altivec instructions
VMAXSB, VMAXSH, VMAXSW, VMAXUB, VMAXUH, VMAXUW, and
VMINSB, VMINSH, VMINSW, VMINUB, VMINUH, VMINUW.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:39 +03:00
|
|
|
case INDEX_op_smax_vec:
|
|
|
|
case INDEX_op_smin_vec:
|
|
|
|
case INDEX_op_umax_vec:
|
|
|
|
case INDEX_op_umin_vec:
|
2019-09-30 06:39:24 +03:00
|
|
|
case INDEX_op_shlv_vec:
|
|
|
|
case INDEX_op_shrv_vec:
|
|
|
|
case INDEX_op_sarv_vec:
|
2020-04-20 06:46:12 +03:00
|
|
|
case INDEX_op_rotlv_vec:
|
2019-09-30 06:39:24 +03:00
|
|
|
return vece <= MO_32 || have_isa_2_07;
|
tcg/ppc: Add support for vector saturated add/subtract
Add support for vector saturated add/subtract using Altivec
instructions:
VADDSBS, VADDSHS, VADDSWS, VADDUBS, VADDUHS, VADDUWS, and
VSUBSBS, VSUBSHS, VSUBSWS, VSUBUBS, VSUBUHS, VSUBUWS.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:41 +03:00
|
|
|
case INDEX_op_ssadd_vec:
|
|
|
|
case INDEX_op_sssub_vec:
|
|
|
|
case INDEX_op_usadd_vec:
|
|
|
|
case INDEX_op_ussub_vec:
|
tcg/ppc: Add support for vector maximum/minimum
Add support for vector maximum/minimum using Altivec instructions
VMAXSB, VMAXSH, VMAXSW, VMAXUB, VMAXUH, VMAXUW, and
VMINSB, VMINSH, VMINSW, VMINUB, VMINUH, VMINUW.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:39 +03:00
|
|
|
return vece <= MO_32;
|
2019-06-23 20:04:38 +03:00
|
|
|
case INDEX_op_cmp_vec:
|
2019-06-23 20:04:44 +03:00
|
|
|
case INDEX_op_shli_vec:
|
|
|
|
case INDEX_op_shri_vec:
|
|
|
|
case INDEX_op_sari_vec:
|
2020-04-20 06:46:12 +03:00
|
|
|
case INDEX_op_rotli_vec:
|
2019-09-30 06:39:24 +03:00
|
|
|
return vece <= MO_32 || have_isa_2_07 ? -1 : 0;
|
2019-09-30 07:21:22 +03:00
|
|
|
case INDEX_op_neg_vec:
|
|
|
|
return vece >= MO_32 && have_isa_3_00;
|
2019-09-30 06:39:24 +03:00
|
|
|
case INDEX_op_mul_vec:
|
|
|
|
switch (vece) {
|
|
|
|
case MO_8:
|
|
|
|
case MO_16:
|
|
|
|
return -1;
|
|
|
|
case MO_32:
|
|
|
|
return have_isa_2_07 ? 1 : -1;
|
2020-07-24 07:58:41 +03:00
|
|
|
case MO_64:
|
|
|
|
return have_isa_3_10;
|
2019-09-30 06:39:24 +03:00
|
|
|
}
|
|
|
|
return 0;
|
2019-06-23 20:04:47 +03:00
|
|
|
case INDEX_op_bitsel_vec:
|
|
|
|
return have_vsx;
|
2020-04-20 06:46:12 +03:00
|
|
|
case INDEX_op_rotrv_vec:
|
|
|
|
return -1;
|
2019-06-23 20:04:38 +03:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
2019-06-23 20:04:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
|
|
|
|
TCGReg dst, TCGReg src)
|
|
|
|
{
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_debug_assert(dst >= TCG_REG_V0);
|
2019-09-30 07:44:44 +03:00
|
|
|
|
|
|
|
/* Splat from integer reg allowed via constraints for v3.00. */
|
|
|
|
if (src < TCG_REG_V0) {
|
|
|
|
tcg_debug_assert(have_isa_3_00);
|
|
|
|
switch (vece) {
|
|
|
|
case MO_64:
|
|
|
|
tcg_out32(s, MTVSRDD | VRT(dst) | RA(src) | RB(src));
|
|
|
|
return true;
|
|
|
|
case MO_32:
|
|
|
|
tcg_out32(s, MTVSRWS | VRT(dst) | RA(src));
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
/* Fail, so that we fall back on either dupm or mov+dup. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Recall we use (or emulate) VSX integer loads, so the integer is
|
|
|
|
* right justified within the left (zero-index) double-word.
|
|
|
|
*/
|
|
|
|
switch (vece) {
|
|
|
|
case MO_8:
|
|
|
|
tcg_out32(s, VSPLTB | VRT(dst) | VRB(src) | (7 << 16));
|
|
|
|
break;
|
|
|
|
case MO_16:
|
|
|
|
tcg_out32(s, VSPLTH | VRT(dst) | VRB(src) | (3 << 16));
|
|
|
|
break;
|
|
|
|
case MO_32:
|
|
|
|
tcg_out32(s, VSPLTW | VRT(dst) | VRB(src) | (1 << 16));
|
|
|
|
break;
|
|
|
|
case MO_64:
|
2019-06-23 20:04:47 +03:00
|
|
|
if (have_vsx) {
|
|
|
|
tcg_out32(s, XXPERMDI | VRT(dst) | VRA(src) | VRB(src));
|
|
|
|
break;
|
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_out_vsldoi(s, TCG_VEC_TMP1, src, src, 8);
|
|
|
|
tcg_out_vsldoi(s, dst, TCG_VEC_TMP1, src, 8);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
return true;
|
2019-06-23 20:04:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
|
|
|
|
TCGReg out, TCGReg base, intptr_t offset)
|
|
|
|
{
|
2019-06-23 20:04:38 +03:00
|
|
|
int elt;
|
|
|
|
|
|
|
|
tcg_debug_assert(out >= TCG_REG_V0);
|
|
|
|
switch (vece) {
|
|
|
|
case MO_8:
|
2019-09-30 07:36:26 +03:00
|
|
|
if (have_isa_3_00) {
|
|
|
|
tcg_out_mem_long(s, LXV, LVX, out, base, offset & -16);
|
|
|
|
} else {
|
|
|
|
tcg_out_mem_long(s, 0, LVEBX, out, base, offset);
|
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
elt = extract32(offset, 0, 4);
|
2022-03-23 18:57:17 +03:00
|
|
|
#if !HOST_BIG_ENDIAN
|
2019-06-23 20:04:38 +03:00
|
|
|
elt ^= 15;
|
|
|
|
#endif
|
|
|
|
tcg_out32(s, VSPLTB | VRT(out) | VRB(out) | (elt << 16));
|
|
|
|
break;
|
|
|
|
case MO_16:
|
|
|
|
tcg_debug_assert((offset & 1) == 0);
|
2019-09-30 07:36:26 +03:00
|
|
|
if (have_isa_3_00) {
|
|
|
|
tcg_out_mem_long(s, LXV | 8, LVX, out, base, offset & -16);
|
|
|
|
} else {
|
|
|
|
tcg_out_mem_long(s, 0, LVEHX, out, base, offset);
|
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
elt = extract32(offset, 1, 3);
|
2022-03-23 18:57:17 +03:00
|
|
|
#if !HOST_BIG_ENDIAN
|
2019-06-23 20:04:38 +03:00
|
|
|
elt ^= 7;
|
|
|
|
#endif
|
|
|
|
tcg_out32(s, VSPLTH | VRT(out) | VRB(out) | (elt << 16));
|
|
|
|
break;
|
|
|
|
case MO_32:
|
2019-09-30 07:36:26 +03:00
|
|
|
if (have_isa_3_00) {
|
|
|
|
tcg_out_mem_long(s, 0, LXVWSX, out, base, offset);
|
|
|
|
break;
|
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_debug_assert((offset & 3) == 0);
|
|
|
|
tcg_out_mem_long(s, 0, LVEWX, out, base, offset);
|
|
|
|
elt = extract32(offset, 2, 2);
|
2022-03-23 18:57:17 +03:00
|
|
|
#if !HOST_BIG_ENDIAN
|
2019-06-23 20:04:38 +03:00
|
|
|
elt ^= 3;
|
|
|
|
#endif
|
|
|
|
tcg_out32(s, VSPLTW | VRT(out) | VRB(out) | (elt << 16));
|
|
|
|
break;
|
|
|
|
case MO_64:
|
2019-06-23 20:04:47 +03:00
|
|
|
if (have_vsx) {
|
|
|
|
tcg_out_mem_long(s, 0, LXVDSX, out, base, offset);
|
|
|
|
break;
|
|
|
|
}
|
2019-06-23 20:04:38 +03:00
|
|
|
tcg_debug_assert((offset & 7) == 0);
|
|
|
|
tcg_out_mem_long(s, 0, LVX, out, base, offset & -16);
|
|
|
|
tcg_out_vsldoi(s, TCG_VEC_TMP1, out, out, 8);
|
|
|
|
elt = extract32(offset, 3, 1);
|
2022-03-23 18:57:17 +03:00
|
|
|
#if !HOST_BIG_ENDIAN
|
2019-06-23 20:04:38 +03:00
|
|
|
elt = !elt;
|
|
|
|
#endif
|
|
|
|
if (elt) {
|
|
|
|
tcg_out_vsldoi(s, out, out, TCG_VEC_TMP1, 8);
|
|
|
|
} else {
|
|
|
|
tcg_out_vsldoi(s, out, TCG_VEC_TMP1, out, 8);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
return true;
|
2019-06-23 20:04:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
|
|
|
|
unsigned vecl, unsigned vece,
|
2021-03-12 15:14:18 +03:00
|
|
|
const TCGArg args[TCG_MAX_OP_ARGS],
|
|
|
|
const int const_args[TCG_MAX_OP_ARGS])
|
2019-06-23 20:04:35 +03:00
|
|
|
{
|
2019-06-23 20:04:38 +03:00
|
|
|
static const uint32_t
|
2019-09-30 06:39:24 +03:00
|
|
|
add_op[4] = { VADDUBM, VADDUHM, VADDUWM, VADDUDM },
|
|
|
|
sub_op[4] = { VSUBUBM, VSUBUHM, VSUBUWM, VSUBUDM },
|
2020-07-24 07:58:41 +03:00
|
|
|
mul_op[4] = { 0, 0, VMULUWM, VMULLD },
|
2019-09-30 07:21:22 +03:00
|
|
|
neg_op[4] = { 0, 0, VNEGW, VNEGD },
|
2019-09-30 06:39:24 +03:00
|
|
|
eq_op[4] = { VCMPEQUB, VCMPEQUH, VCMPEQUW, VCMPEQUD },
|
2019-09-30 07:21:22 +03:00
|
|
|
ne_op[4] = { VCMPNEB, VCMPNEH, VCMPNEW, 0 },
|
2019-09-30 06:39:24 +03:00
|
|
|
gts_op[4] = { VCMPGTSB, VCMPGTSH, VCMPGTSW, VCMPGTSD },
|
|
|
|
gtu_op[4] = { VCMPGTUB, VCMPGTUH, VCMPGTUW, VCMPGTUD },
|
tcg/ppc: Add support for vector saturated add/subtract
Add support for vector saturated add/subtract using Altivec
instructions:
VADDSBS, VADDSHS, VADDSWS, VADDUBS, VADDUHS, VADDUWS, and
VSUBSBS, VSUBSHS, VSUBSWS, VSUBUBS, VSUBUHS, VSUBUWS.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:41 +03:00
|
|
|
ssadd_op[4] = { VADDSBS, VADDSHS, VADDSWS, 0 },
|
|
|
|
usadd_op[4] = { VADDUBS, VADDUHS, VADDUWS, 0 },
|
|
|
|
sssub_op[4] = { VSUBSBS, VSUBSHS, VSUBSWS, 0 },
|
|
|
|
ussub_op[4] = { VSUBUBS, VSUBUHS, VSUBUWS, 0 },
|
2019-09-30 06:39:24 +03:00
|
|
|
umin_op[4] = { VMINUB, VMINUH, VMINUW, VMINUD },
|
|
|
|
smin_op[4] = { VMINSB, VMINSH, VMINSW, VMINSD },
|
|
|
|
umax_op[4] = { VMAXUB, VMAXUH, VMAXUW, VMAXUD },
|
|
|
|
smax_op[4] = { VMAXSB, VMAXSH, VMAXSW, VMAXSD },
|
|
|
|
shlv_op[4] = { VSLB, VSLH, VSLW, VSLD },
|
|
|
|
shrv_op[4] = { VSRB, VSRH, VSRW, VSRD },
|
|
|
|
sarv_op[4] = { VSRAB, VSRAH, VSRAW, VSRAD },
|
2019-06-23 20:04:42 +03:00
|
|
|
mrgh_op[4] = { VMRGHB, VMRGHH, VMRGHW, 0 },
|
|
|
|
mrgl_op[4] = { VMRGLB, VMRGLH, VMRGLW, 0 },
|
2019-09-30 06:39:24 +03:00
|
|
|
muleu_op[4] = { VMULEUB, VMULEUH, VMULEUW, 0 },
|
|
|
|
mulou_op[4] = { VMULOUB, VMULOUH, VMULOUW, 0 },
|
2019-06-23 20:04:42 +03:00
|
|
|
pkum_op[4] = { VPKUHUM, VPKUWUM, 0, 0 },
|
2019-09-30 06:39:24 +03:00
|
|
|
rotl_op[4] = { VRLB, VRLH, VRLW, VRLD };
|
2019-06-23 20:04:38 +03:00
|
|
|
|
|
|
|
TCGType type = vecl + TCG_TYPE_V64;
|
|
|
|
TCGArg a0 = args[0], a1 = args[1], a2 = args[2];
|
|
|
|
uint32_t insn;
|
|
|
|
|
|
|
|
switch (opc) {
|
|
|
|
case INDEX_op_ld_vec:
|
|
|
|
tcg_out_ld(s, type, a0, a1, a2);
|
|
|
|
return;
|
|
|
|
case INDEX_op_st_vec:
|
|
|
|
tcg_out_st(s, type, a0, a1, a2);
|
|
|
|
return;
|
|
|
|
case INDEX_op_dupm_vec:
|
|
|
|
tcg_out_dupm_vec(s, type, vece, a0, a1, a2);
|
|
|
|
return;
|
|
|
|
|
2019-06-23 20:04:40 +03:00
|
|
|
case INDEX_op_add_vec:
|
|
|
|
insn = add_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_sub_vec:
|
|
|
|
insn = sub_op[vece];
|
|
|
|
break;
|
2019-09-30 07:21:22 +03:00
|
|
|
case INDEX_op_neg_vec:
|
|
|
|
insn = neg_op[vece];
|
|
|
|
a2 = a1;
|
|
|
|
a1 = 0;
|
|
|
|
break;
|
2019-09-30 06:39:24 +03:00
|
|
|
case INDEX_op_mul_vec:
|
2020-07-24 07:58:41 +03:00
|
|
|
insn = mul_op[vece];
|
2019-09-30 06:39:24 +03:00
|
|
|
break;
|
tcg/ppc: Add support for vector saturated add/subtract
Add support for vector saturated add/subtract using Altivec
instructions:
VADDSBS, VADDSHS, VADDSWS, VADDUBS, VADDUHS, VADDUWS, and
VSUBSBS, VSUBSHS, VSUBSWS, VSUBUBS, VSUBUHS, VSUBUWS.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:41 +03:00
|
|
|
case INDEX_op_ssadd_vec:
|
|
|
|
insn = ssadd_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_sssub_vec:
|
|
|
|
insn = sssub_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_usadd_vec:
|
|
|
|
insn = usadd_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_ussub_vec:
|
|
|
|
insn = ussub_op[vece];
|
|
|
|
break;
|
tcg/ppc: Add support for vector maximum/minimum
Add support for vector maximum/minimum using Altivec instructions
VMAXSB, VMAXSH, VMAXSW, VMAXUB, VMAXUH, VMAXUW, and
VMINSB, VMINSH, VMINSW, VMINUB, VMINUH, VMINUW.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:39 +03:00
|
|
|
case INDEX_op_smin_vec:
|
|
|
|
insn = smin_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_umin_vec:
|
|
|
|
insn = umin_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_smax_vec:
|
|
|
|
insn = smax_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_umax_vec:
|
|
|
|
insn = umax_op[vece];
|
|
|
|
break;
|
2019-06-23 20:04:44 +03:00
|
|
|
case INDEX_op_shlv_vec:
|
|
|
|
insn = shlv_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_shrv_vec:
|
|
|
|
insn = shrv_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_sarv_vec:
|
|
|
|
insn = sarv_op[vece];
|
|
|
|
break;
|
2019-06-23 20:04:38 +03:00
|
|
|
case INDEX_op_and_vec:
|
|
|
|
insn = VAND;
|
|
|
|
break;
|
|
|
|
case INDEX_op_or_vec:
|
|
|
|
insn = VOR;
|
|
|
|
break;
|
|
|
|
case INDEX_op_xor_vec:
|
|
|
|
insn = VXOR;
|
|
|
|
break;
|
|
|
|
case INDEX_op_andc_vec:
|
|
|
|
insn = VANDC;
|
|
|
|
break;
|
|
|
|
case INDEX_op_not_vec:
|
|
|
|
insn = VNOR;
|
|
|
|
a2 = a1;
|
|
|
|
break;
|
2019-09-30 06:39:24 +03:00
|
|
|
case INDEX_op_orc_vec:
|
|
|
|
insn = VORC;
|
|
|
|
break;
|
2021-12-18 05:52:59 +03:00
|
|
|
case INDEX_op_nand_vec:
|
|
|
|
insn = VNAND;
|
|
|
|
break;
|
|
|
|
case INDEX_op_nor_vec:
|
|
|
|
insn = VNOR;
|
|
|
|
break;
|
|
|
|
case INDEX_op_eqv_vec:
|
|
|
|
insn = VEQV;
|
|
|
|
break;
|
2019-06-23 20:04:38 +03:00
|
|
|
|
|
|
|
case INDEX_op_cmp_vec:
|
|
|
|
switch (args[3]) {
|
|
|
|
case TCG_COND_EQ:
|
|
|
|
insn = eq_op[vece];
|
|
|
|
break;
|
2019-09-30 07:21:22 +03:00
|
|
|
case TCG_COND_NE:
|
|
|
|
insn = ne_op[vece];
|
|
|
|
break;
|
2019-06-23 20:04:38 +03:00
|
|
|
case TCG_COND_GT:
|
|
|
|
insn = gts_op[vece];
|
|
|
|
break;
|
|
|
|
case TCG_COND_GTU:
|
|
|
|
insn = gtu_op[vece];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2019-06-23 20:04:47 +03:00
|
|
|
case INDEX_op_bitsel_vec:
|
|
|
|
tcg_out32(s, XXSEL | VRT(a0) | VRC(a1) | VRB(a2) | VRA(args[3]));
|
|
|
|
return;
|
|
|
|
|
2019-06-23 20:04:46 +03:00
|
|
|
case INDEX_op_dup2_vec:
|
|
|
|
assert(TCG_TARGET_REG_BITS == 32);
|
|
|
|
/* With inputs a1 = xLxx, a2 = xHxx */
|
|
|
|
tcg_out32(s, VMRGHW | VRT(a0) | VRA(a2) | VRB(a1)); /* a0 = xxHL */
|
|
|
|
tcg_out_vsldoi(s, TCG_VEC_TMP1, a0, a0, 8); /* tmp = HLxx */
|
|
|
|
tcg_out_vsldoi(s, a0, a0, TCG_VEC_TMP1, 8); /* a0 = HLHL */
|
|
|
|
return;
|
|
|
|
|
2019-06-23 20:04:42 +03:00
|
|
|
case INDEX_op_ppc_mrgh_vec:
|
|
|
|
insn = mrgh_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_ppc_mrgl_vec:
|
|
|
|
insn = mrgl_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_ppc_muleu_vec:
|
|
|
|
insn = muleu_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_ppc_mulou_vec:
|
|
|
|
insn = mulou_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_ppc_pkum_vec:
|
|
|
|
insn = pkum_op[vece];
|
|
|
|
break;
|
2020-04-20 06:46:12 +03:00
|
|
|
case INDEX_op_rotlv_vec:
|
2019-06-23 20:04:42 +03:00
|
|
|
insn = rotl_op[vece];
|
|
|
|
break;
|
|
|
|
case INDEX_op_ppc_msum_vec:
|
|
|
|
tcg_debug_assert(vece == MO_16);
|
|
|
|
tcg_out32(s, VMSUMUHM | VRT(a0) | VRA(a1) | VRB(a2) | VRC(args[3]));
|
|
|
|
return;
|
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
case INDEX_op_mov_vec: /* Always emitted via tcg_out_mov. */
|
|
|
|
case INDEX_op_dup_vec: /* Always emitted via tcg_out_dup_vec. */
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
|
|
|
tcg_debug_assert(insn != 0);
|
|
|
|
tcg_out32(s, insn | VRT(a0) | VRA(a1) | VRB(a2));
|
|
|
|
}
|
|
|
|
|
2019-06-23 20:04:44 +03:00
|
|
|
static void expand_vec_shi(TCGType type, unsigned vece, TCGv_vec v0,
|
|
|
|
TCGv_vec v1, TCGArg imm, TCGOpcode opci)
|
|
|
|
{
|
2020-09-08 02:46:21 +03:00
|
|
|
TCGv_vec t1;
|
|
|
|
|
|
|
|
if (vece == MO_32) {
|
|
|
|
/*
|
|
|
|
* Only 5 bits are significant, and VSPLTISB can represent -16..15.
|
|
|
|
* So using negative numbers gets us the 4th bit easily.
|
|
|
|
*/
|
|
|
|
imm = sextract32(imm, 0, 5);
|
|
|
|
} else {
|
|
|
|
imm &= (8 << vece) - 1;
|
|
|
|
}
|
2019-06-23 20:04:44 +03:00
|
|
|
|
2020-09-08 02:46:21 +03:00
|
|
|
/* Splat w/bytes for xxspltib when 2.07 allows MO_64. */
|
|
|
|
t1 = tcg_constant_vec(type, MO_8, imm);
|
2019-06-23 20:04:44 +03:00
|
|
|
vec_gen_3(opci, type, vece, tcgv_vec_arg(v0),
|
|
|
|
tcgv_vec_arg(v1), tcgv_vec_arg(t1));
|
|
|
|
}
|
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
static void expand_vec_cmp(TCGType type, unsigned vece, TCGv_vec v0,
|
|
|
|
TCGv_vec v1, TCGv_vec v2, TCGCond cond)
|
|
|
|
{
|
|
|
|
bool need_swap = false, need_inv = false;
|
|
|
|
|
2019-09-30 06:39:24 +03:00
|
|
|
tcg_debug_assert(vece <= MO_32 || have_isa_2_07);
|
2019-06-23 20:04:38 +03:00
|
|
|
|
|
|
|
switch (cond) {
|
|
|
|
case TCG_COND_EQ:
|
|
|
|
case TCG_COND_GT:
|
|
|
|
case TCG_COND_GTU:
|
|
|
|
break;
|
|
|
|
case TCG_COND_NE:
|
2019-09-30 07:21:22 +03:00
|
|
|
if (have_isa_3_00 && vece <= MO_32) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall through */
|
2019-06-23 20:04:38 +03:00
|
|
|
case TCG_COND_LE:
|
|
|
|
case TCG_COND_LEU:
|
|
|
|
need_inv = true;
|
|
|
|
break;
|
|
|
|
case TCG_COND_LT:
|
|
|
|
case TCG_COND_LTU:
|
|
|
|
need_swap = true;
|
|
|
|
break;
|
|
|
|
case TCG_COND_GE:
|
|
|
|
case TCG_COND_GEU:
|
|
|
|
need_swap = need_inv = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (need_inv) {
|
|
|
|
cond = tcg_invert_cond(cond);
|
|
|
|
}
|
|
|
|
if (need_swap) {
|
|
|
|
TCGv_vec t1;
|
|
|
|
t1 = v1, v1 = v2, v2 = t1;
|
|
|
|
cond = tcg_swap_cond(cond);
|
|
|
|
}
|
|
|
|
|
|
|
|
vec_gen_4(INDEX_op_cmp_vec, type, vece, tcgv_vec_arg(v0),
|
|
|
|
tcgv_vec_arg(v1), tcgv_vec_arg(v2), cond);
|
|
|
|
|
|
|
|
if (need_inv) {
|
|
|
|
tcg_gen_not_vec(vece, v0, v0);
|
|
|
|
}
|
2019-06-23 20:04:35 +03:00
|
|
|
}
|
|
|
|
|
2019-06-23 20:04:42 +03:00
|
|
|
static void expand_vec_mul(TCGType type, unsigned vece, TCGv_vec v0,
|
|
|
|
TCGv_vec v1, TCGv_vec v2)
|
|
|
|
{
|
|
|
|
TCGv_vec t1 = tcg_temp_new_vec(type);
|
|
|
|
TCGv_vec t2 = tcg_temp_new_vec(type);
|
2020-09-08 02:46:21 +03:00
|
|
|
TCGv_vec c0, c16;
|
2019-06-23 20:04:42 +03:00
|
|
|
|
|
|
|
switch (vece) {
|
|
|
|
case MO_8:
|
|
|
|
case MO_16:
|
|
|
|
vec_gen_3(INDEX_op_ppc_muleu_vec, type, vece, tcgv_vec_arg(t1),
|
|
|
|
tcgv_vec_arg(v1), tcgv_vec_arg(v2));
|
|
|
|
vec_gen_3(INDEX_op_ppc_mulou_vec, type, vece, tcgv_vec_arg(t2),
|
|
|
|
tcgv_vec_arg(v1), tcgv_vec_arg(v2));
|
|
|
|
vec_gen_3(INDEX_op_ppc_mrgh_vec, type, vece + 1, tcgv_vec_arg(v0),
|
|
|
|
tcgv_vec_arg(t1), tcgv_vec_arg(t2));
|
|
|
|
vec_gen_3(INDEX_op_ppc_mrgl_vec, type, vece + 1, tcgv_vec_arg(t1),
|
|
|
|
tcgv_vec_arg(t1), tcgv_vec_arg(t2));
|
|
|
|
vec_gen_3(INDEX_op_ppc_pkum_vec, type, vece, tcgv_vec_arg(v0),
|
|
|
|
tcgv_vec_arg(v0), tcgv_vec_arg(t1));
|
2023-08-04 23:35:53 +03:00
|
|
|
break;
|
2019-06-23 20:04:42 +03:00
|
|
|
|
|
|
|
case MO_32:
|
2019-09-30 06:39:24 +03:00
|
|
|
tcg_debug_assert(!have_isa_2_07);
|
2020-09-08 02:46:21 +03:00
|
|
|
/*
|
|
|
|
* Only 5 bits are significant, and VSPLTISB can represent -16..15.
|
|
|
|
* So using -16 is a quick way to represent 16.
|
|
|
|
*/
|
|
|
|
c16 = tcg_constant_vec(type, MO_8, -16);
|
|
|
|
c0 = tcg_constant_vec(type, MO_8, 0);
|
|
|
|
|
2020-04-20 06:46:12 +03:00
|
|
|
vec_gen_3(INDEX_op_rotlv_vec, type, MO_32, tcgv_vec_arg(t1),
|
2020-09-08 02:46:21 +03:00
|
|
|
tcgv_vec_arg(v2), tcgv_vec_arg(c16));
|
2019-06-23 20:04:42 +03:00
|
|
|
vec_gen_3(INDEX_op_ppc_mulou_vec, type, MO_16, tcgv_vec_arg(t2),
|
|
|
|
tcgv_vec_arg(v1), tcgv_vec_arg(v2));
|
2020-09-08 02:46:21 +03:00
|
|
|
vec_gen_4(INDEX_op_ppc_msum_vec, type, MO_16, tcgv_vec_arg(t1),
|
|
|
|
tcgv_vec_arg(v1), tcgv_vec_arg(t1), tcgv_vec_arg(c0));
|
|
|
|
vec_gen_3(INDEX_op_shlv_vec, type, MO_32, tcgv_vec_arg(t1),
|
|
|
|
tcgv_vec_arg(t1), tcgv_vec_arg(c16));
|
|
|
|
tcg_gen_add_vec(MO_32, v0, t1, t2);
|
2019-06-23 20:04:42 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
tcg_temp_free_vec(t1);
|
|
|
|
tcg_temp_free_vec(t2);
|
|
|
|
}
|
|
|
|
|
2019-06-23 20:04:35 +03:00
|
|
|
void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
|
|
|
|
TCGArg a0, ...)
|
|
|
|
{
|
2019-06-23 20:04:38 +03:00
|
|
|
va_list va;
|
2020-04-20 06:46:12 +03:00
|
|
|
TCGv_vec v0, v1, v2, t0;
|
2019-06-23 20:04:44 +03:00
|
|
|
TCGArg a2;
|
2019-06-23 20:04:38 +03:00
|
|
|
|
|
|
|
va_start(va, a0);
|
|
|
|
v0 = temp_tcgv_vec(arg_temp(a0));
|
|
|
|
v1 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg)));
|
2019-06-23 20:04:44 +03:00
|
|
|
a2 = va_arg(va, TCGArg);
|
2019-06-23 20:04:38 +03:00
|
|
|
|
|
|
|
switch (opc) {
|
2019-06-23 20:04:44 +03:00
|
|
|
case INDEX_op_shli_vec:
|
|
|
|
expand_vec_shi(type, vece, v0, v1, a2, INDEX_op_shlv_vec);
|
|
|
|
break;
|
|
|
|
case INDEX_op_shri_vec:
|
|
|
|
expand_vec_shi(type, vece, v0, v1, a2, INDEX_op_shrv_vec);
|
|
|
|
break;
|
|
|
|
case INDEX_op_sari_vec:
|
|
|
|
expand_vec_shi(type, vece, v0, v1, a2, INDEX_op_sarv_vec);
|
|
|
|
break;
|
2020-04-20 06:46:12 +03:00
|
|
|
case INDEX_op_rotli_vec:
|
|
|
|
expand_vec_shi(type, vece, v0, v1, a2, INDEX_op_rotlv_vec);
|
|
|
|
break;
|
2019-06-23 20:04:38 +03:00
|
|
|
case INDEX_op_cmp_vec:
|
2019-06-23 20:04:44 +03:00
|
|
|
v2 = temp_tcgv_vec(arg_temp(a2));
|
2019-06-23 20:04:38 +03:00
|
|
|
expand_vec_cmp(type, vece, v0, v1, v2, va_arg(va, TCGArg));
|
|
|
|
break;
|
2019-06-23 20:04:42 +03:00
|
|
|
case INDEX_op_mul_vec:
|
|
|
|
v2 = temp_tcgv_vec(arg_temp(a2));
|
|
|
|
expand_vec_mul(type, vece, v0, v1, v2);
|
|
|
|
break;
|
2020-04-20 06:46:12 +03:00
|
|
|
case INDEX_op_rotlv_vec:
|
|
|
|
v2 = temp_tcgv_vec(arg_temp(a2));
|
|
|
|
t0 = tcg_temp_new_vec(type);
|
|
|
|
tcg_gen_neg_vec(vece, t0, v2);
|
|
|
|
tcg_gen_rotlv_vec(vece, v0, v1, t0);
|
|
|
|
tcg_temp_free_vec(t0);
|
|
|
|
break;
|
2019-06-23 20:04:38 +03:00
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
va_end(va);
|
2019-06-23 20:04:35 +03:00
|
|
|
}
|
|
|
|
|
2020-10-17 19:35:21 +03:00
|
|
|
static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
|
|
|
|
{
|
2017-09-14 05:29:32 +03:00
|
|
|
switch (op) {
|
|
|
|
case INDEX_op_goto_ptr:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O0_I1(r);
|
2014-04-30 22:39:20 +04:00
|
|
|
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_ld8u_i32:
|
|
|
|
case INDEX_op_ld8s_i32:
|
|
|
|
case INDEX_op_ld16u_i32:
|
|
|
|
case INDEX_op_ld16s_i32:
|
|
|
|
case INDEX_op_ld_i32:
|
|
|
|
case INDEX_op_ctpop_i32:
|
|
|
|
case INDEX_op_neg_i32:
|
|
|
|
case INDEX_op_not_i32:
|
|
|
|
case INDEX_op_ext8s_i32:
|
|
|
|
case INDEX_op_ext16s_i32:
|
|
|
|
case INDEX_op_bswap16_i32:
|
|
|
|
case INDEX_op_bswap32_i32:
|
|
|
|
case INDEX_op_extract_i32:
|
|
|
|
case INDEX_op_ld8u_i64:
|
|
|
|
case INDEX_op_ld8s_i64:
|
|
|
|
case INDEX_op_ld16u_i64:
|
|
|
|
case INDEX_op_ld16s_i64:
|
|
|
|
case INDEX_op_ld32u_i64:
|
|
|
|
case INDEX_op_ld32s_i64:
|
|
|
|
case INDEX_op_ld_i64:
|
|
|
|
case INDEX_op_ctpop_i64:
|
|
|
|
case INDEX_op_neg_i64:
|
|
|
|
case INDEX_op_not_i64:
|
|
|
|
case INDEX_op_ext8s_i64:
|
|
|
|
case INDEX_op_ext16s_i64:
|
|
|
|
case INDEX_op_ext32s_i64:
|
|
|
|
case INDEX_op_ext_i32_i64:
|
|
|
|
case INDEX_op_extu_i32_i64:
|
|
|
|
case INDEX_op_bswap16_i64:
|
|
|
|
case INDEX_op_bswap32_i64:
|
|
|
|
case INDEX_op_bswap64_i64:
|
|
|
|
case INDEX_op_extract_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I1(r, r);
|
|
|
|
|
|
|
|
case INDEX_op_st8_i32:
|
|
|
|
case INDEX_op_st16_i32:
|
|
|
|
case INDEX_op_st_i32:
|
|
|
|
case INDEX_op_st8_i64:
|
|
|
|
case INDEX_op_st16_i64:
|
|
|
|
case INDEX_op_st32_i64:
|
|
|
|
case INDEX_op_st_i64:
|
|
|
|
return C_O0_I2(r, r);
|
2014-04-30 22:55:34 +04:00
|
|
|
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_add_i32:
|
|
|
|
case INDEX_op_and_i32:
|
|
|
|
case INDEX_op_or_i32:
|
|
|
|
case INDEX_op_xor_i32:
|
|
|
|
case INDEX_op_andc_i32:
|
|
|
|
case INDEX_op_orc_i32:
|
|
|
|
case INDEX_op_eqv_i32:
|
|
|
|
case INDEX_op_shl_i32:
|
|
|
|
case INDEX_op_shr_i32:
|
|
|
|
case INDEX_op_sar_i32:
|
|
|
|
case INDEX_op_rotl_i32:
|
|
|
|
case INDEX_op_rotr_i32:
|
|
|
|
case INDEX_op_setcond_i32:
|
2023-08-05 04:55:23 +03:00
|
|
|
case INDEX_op_negsetcond_i32:
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_and_i64:
|
|
|
|
case INDEX_op_andc_i64:
|
|
|
|
case INDEX_op_shl_i64:
|
|
|
|
case INDEX_op_shr_i64:
|
|
|
|
case INDEX_op_sar_i64:
|
|
|
|
case INDEX_op_rotl_i64:
|
|
|
|
case INDEX_op_rotr_i64:
|
|
|
|
case INDEX_op_setcond_i64:
|
2023-08-05 04:55:23 +03:00
|
|
|
case INDEX_op_negsetcond_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I2(r, r, ri);
|
|
|
|
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_mul_i32:
|
|
|
|
case INDEX_op_mul_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I2(r, r, rI);
|
|
|
|
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_div_i32:
|
|
|
|
case INDEX_op_divu_i32:
|
2022-06-13 17:43:59 +03:00
|
|
|
case INDEX_op_rem_i32:
|
|
|
|
case INDEX_op_remu_i32:
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_nand_i32:
|
|
|
|
case INDEX_op_nor_i32:
|
|
|
|
case INDEX_op_muluh_i32:
|
|
|
|
case INDEX_op_mulsh_i32:
|
|
|
|
case INDEX_op_orc_i64:
|
|
|
|
case INDEX_op_eqv_i64:
|
|
|
|
case INDEX_op_nand_i64:
|
|
|
|
case INDEX_op_nor_i64:
|
|
|
|
case INDEX_op_div_i64:
|
|
|
|
case INDEX_op_divu_i64:
|
2022-06-13 17:43:59 +03:00
|
|
|
case INDEX_op_rem_i64:
|
|
|
|
case INDEX_op_remu_i64:
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_mulsh_i64:
|
|
|
|
case INDEX_op_muluh_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I2(r, r, r);
|
|
|
|
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_sub_i32:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I2(r, rI, ri);
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_add_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I2(r, r, rT);
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_or_i64:
|
|
|
|
case INDEX_op_xor_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I2(r, r, rU);
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_sub_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I2(r, rI, rT);
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_clz_i32:
|
|
|
|
case INDEX_op_ctz_i32:
|
|
|
|
case INDEX_op_clz_i64:
|
|
|
|
case INDEX_op_ctz_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I2(r, r, rZW);
|
2014-04-30 22:39:20 +04:00
|
|
|
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_brcond_i32:
|
|
|
|
case INDEX_op_brcond_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O0_I2(r, ri);
|
2013-03-05 02:26:52 +04:00
|
|
|
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_movcond_i32:
|
|
|
|
case INDEX_op_movcond_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I4(r, r, ri, rZ, rZ);
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_deposit_i32:
|
|
|
|
case INDEX_op_deposit_i64:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I2(r, 0, rZ);
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_brcond2_i32:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O0_I4(r, r, ri, ri);
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_setcond2_i32:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I4(r, r, r, ri, ri);
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_add2_i64:
|
|
|
|
case INDEX_op_add2_i32:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O2_I4(r, r, r, r, rI, rZM);
|
2017-09-14 05:29:32 +03:00
|
|
|
case INDEX_op_sub2_i64:
|
|
|
|
case INDEX_op_sub2_i32:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O2_I4(r, r, rI, rZM, r, r);
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2023-05-17 06:07:20 +03:00
|
|
|
case INDEX_op_qemu_ld_a32_i32:
|
|
|
|
return C_O1_I1(r, r);
|
|
|
|
case INDEX_op_qemu_ld_a64_i32:
|
|
|
|
return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) : C_O1_I2(r, r, r);
|
|
|
|
case INDEX_op_qemu_ld_a32_i64:
|
|
|
|
return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) : C_O2_I1(r, r, r);
|
|
|
|
case INDEX_op_qemu_ld_a64_i64:
|
|
|
|
return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) : C_O2_I2(r, r, r, r);
|
|
|
|
|
|
|
|
case INDEX_op_qemu_st_a32_i32:
|
|
|
|
return C_O0_I2(r, r);
|
|
|
|
case INDEX_op_qemu_st_a64_i32:
|
|
|
|
return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r) : C_O0_I3(r, r, r);
|
|
|
|
case INDEX_op_qemu_st_a32_i64:
|
|
|
|
return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r) : C_O0_I3(r, r, r);
|
|
|
|
case INDEX_op_qemu_st_a64_i64:
|
|
|
|
return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r) : C_O0_I4(r, r, r, r);
|
2016-11-18 11:31:40 +03:00
|
|
|
|
2023-04-19 16:13:22 +03:00
|
|
|
case INDEX_op_qemu_ld_a32_i128:
|
|
|
|
case INDEX_op_qemu_ld_a64_i128:
|
|
|
|
return C_O2_I1(o, m, r);
|
|
|
|
case INDEX_op_qemu_st_a32_i128:
|
|
|
|
case INDEX_op_qemu_st_a64_i128:
|
|
|
|
return C_O0_I3(o, m, r);
|
|
|
|
|
2019-06-23 20:04:40 +03:00
|
|
|
case INDEX_op_add_vec:
|
|
|
|
case INDEX_op_sub_vec:
|
2019-06-23 20:04:42 +03:00
|
|
|
case INDEX_op_mul_vec:
|
2019-06-23 20:04:38 +03:00
|
|
|
case INDEX_op_and_vec:
|
|
|
|
case INDEX_op_or_vec:
|
|
|
|
case INDEX_op_xor_vec:
|
|
|
|
case INDEX_op_andc_vec:
|
|
|
|
case INDEX_op_orc_vec:
|
2021-12-18 05:52:59 +03:00
|
|
|
case INDEX_op_nor_vec:
|
|
|
|
case INDEX_op_eqv_vec:
|
|
|
|
case INDEX_op_nand_vec:
|
2019-06-23 20:04:38 +03:00
|
|
|
case INDEX_op_cmp_vec:
|
tcg/ppc: Add support for vector saturated add/subtract
Add support for vector saturated add/subtract using Altivec
instructions:
VADDSBS, VADDSHS, VADDSWS, VADDUBS, VADDUHS, VADDUWS, and
VSUBSBS, VSUBSHS, VSUBSWS, VSUBUBS, VSUBUHS, VSUBUWS.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:41 +03:00
|
|
|
case INDEX_op_ssadd_vec:
|
|
|
|
case INDEX_op_sssub_vec:
|
|
|
|
case INDEX_op_usadd_vec:
|
|
|
|
case INDEX_op_ussub_vec:
|
tcg/ppc: Add support for vector maximum/minimum
Add support for vector maximum/minimum using Altivec instructions
VMAXSB, VMAXSH, VMAXSW, VMAXUB, VMAXUH, VMAXUW, and
VMINSB, VMINSH, VMINSW, VMINUB, VMINUH, VMINUW.
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Aleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
2019-06-23 20:04:39 +03:00
|
|
|
case INDEX_op_smax_vec:
|
|
|
|
case INDEX_op_smin_vec:
|
|
|
|
case INDEX_op_umax_vec:
|
|
|
|
case INDEX_op_umin_vec:
|
2019-06-23 20:04:44 +03:00
|
|
|
case INDEX_op_shlv_vec:
|
|
|
|
case INDEX_op_shrv_vec:
|
|
|
|
case INDEX_op_sarv_vec:
|
2020-04-20 06:46:12 +03:00
|
|
|
case INDEX_op_rotlv_vec:
|
|
|
|
case INDEX_op_rotrv_vec:
|
2019-06-23 20:04:42 +03:00
|
|
|
case INDEX_op_ppc_mrgh_vec:
|
|
|
|
case INDEX_op_ppc_mrgl_vec:
|
|
|
|
case INDEX_op_ppc_muleu_vec:
|
|
|
|
case INDEX_op_ppc_mulou_vec:
|
|
|
|
case INDEX_op_ppc_pkum_vec:
|
2019-06-23 20:04:46 +03:00
|
|
|
case INDEX_op_dup2_vec:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I2(v, v, v);
|
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
case INDEX_op_not_vec:
|
2019-09-30 07:21:22 +03:00
|
|
|
case INDEX_op_neg_vec:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I1(v, v);
|
|
|
|
|
2019-09-30 07:44:44 +03:00
|
|
|
case INDEX_op_dup_vec:
|
2020-10-17 19:35:21 +03:00
|
|
|
return have_isa_3_00 ? C_O1_I1(v, vr) : C_O1_I1(v, v);
|
|
|
|
|
2019-06-23 20:04:38 +03:00
|
|
|
case INDEX_op_ld_vec:
|
|
|
|
case INDEX_op_dupm_vec:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I1(v, r);
|
|
|
|
|
|
|
|
case INDEX_op_st_vec:
|
|
|
|
return C_O0_I2(v, r);
|
|
|
|
|
2019-06-23 20:04:47 +03:00
|
|
|
case INDEX_op_bitsel_vec:
|
2019-06-23 20:04:42 +03:00
|
|
|
case INDEX_op_ppc_msum_vec:
|
2020-10-17 19:35:21 +03:00
|
|
|
return C_O1_I3(v, v, v, v);
|
2019-06-23 20:04:38 +03:00
|
|
|
|
2017-09-14 05:29:32 +03:00
|
|
|
default:
|
2020-10-17 19:35:21 +03:00
|
|
|
g_assert_not_reached();
|
2016-11-18 11:31:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-31 16:14:53 +04:00
|
|
|
static void tcg_target_init(TCGContext *s)
|
2008-07-23 23:17:46 +04:00
|
|
|
{
|
2017-09-11 22:44:30 +03:00
|
|
|
tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffff;
|
|
|
|
tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffff;
|
2019-06-23 20:04:35 +03:00
|
|
|
if (have_altivec) {
|
|
|
|
tcg_target_available_regs[TCG_TYPE_V64] = 0xffffffff00000000ull;
|
|
|
|
tcg_target_available_regs[TCG_TYPE_V128] = 0xffffffff00000000ull;
|
|
|
|
}
|
2017-09-11 22:44:30 +03:00
|
|
|
|
|
|
|
tcg_target_call_clobber_regs = 0;
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R0);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R2);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R3);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R4);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R5);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R6);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R7);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R8);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R9);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R10);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R11);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R12);
|
2008-07-23 23:17:46 +04:00
|
|
|
|
2019-06-23 20:04:34 +03:00
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V0);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V1);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V2);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V3);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V4);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V5);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V6);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V7);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V8);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V9);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V10);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V11);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V12);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V13);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V14);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V15);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V16);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V17);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V18);
|
|
|
|
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_V19);
|
|
|
|
|
2017-09-11 21:25:55 +03:00
|
|
|
s->reserved_regs = 0;
|
2013-07-31 21:18:49 +04:00
|
|
|
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); /* tcg temp */
|
|
|
|
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); /* stack pointer */
|
2014-04-30 23:12:16 +04:00
|
|
|
#if defined(_CALL_SYSV)
|
|
|
|
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2); /* toc pointer */
|
2009-12-06 16:00:24 +03:00
|
|
|
#endif
|
2014-04-30 23:12:16 +04:00
|
|
|
#if defined(_CALL_SYSV) || TCG_TARGET_REG_BITS == 64
|
2013-07-31 21:18:49 +04:00
|
|
|
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13); /* thread pointer */
|
2014-04-30 23:12:16 +04:00
|
|
|
#endif
|
2023-04-04 01:25:06 +03:00
|
|
|
tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP1);
|
|
|
|
tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP2);
|
2019-06-23 20:04:34 +03:00
|
|
|
tcg_regset_set_reg(s->reserved_regs, TCG_VEC_TMP1);
|
|
|
|
tcg_regset_set_reg(s->reserved_regs, TCG_VEC_TMP2);
|
2017-07-31 07:16:10 +03:00
|
|
|
if (USE_REG_TB) {
|
|
|
|
tcg_regset_set_reg(s->reserved_regs, TCG_REG_TB); /* tb->tc_ptr */
|
2014-03-28 17:53:53 +04:00
|
|
|
}
|
2008-07-23 23:17:46 +04:00
|
|
|
}
|
2013-08-31 15:44:21 +04:00
|
|
|
|
2014-03-25 20:13:38 +04:00
|
|
|
#ifdef __ELF__
|
2013-08-31 15:44:21 +04:00
|
|
|
typedef struct {
|
|
|
|
DebugFrameCIE cie;
|
|
|
|
DebugFrameFDEHeader fde;
|
|
|
|
uint8_t fde_def_cfa[4];
|
|
|
|
uint8_t fde_reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2 + 3];
|
|
|
|
} DebugFrame;
|
|
|
|
|
|
|
|
/* We're expecting a 2 byte uleb128 encoded value. */
|
|
|
|
QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14));
|
|
|
|
|
2014-03-25 20:13:38 +04:00
|
|
|
#if TCG_TARGET_REG_BITS == 64
|
|
|
|
# define ELF_HOST_MACHINE EM_PPC64
|
|
|
|
#else
|
|
|
|
# define ELF_HOST_MACHINE EM_PPC
|
|
|
|
#endif
|
2013-08-31 15:44:21 +04:00
|
|
|
|
|
|
|
static DebugFrame debug_frame = {
|
|
|
|
.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
|
|
|
|
.cie.id = -1,
|
|
|
|
.cie.version = 1,
|
|
|
|
.cie.code_align = 1,
|
2014-03-25 19:55:12 +04:00
|
|
|
.cie.data_align = (-SZR & 0x7f), /* sleb128 -SZR */
|
2013-08-31 15:44:21 +04:00
|
|
|
.cie.return_column = 65,
|
|
|
|
|
|
|
|
/* Total FDE size does not include the "len" member. */
|
|
|
|
.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset),
|
|
|
|
|
|
|
|
.fde_def_cfa = {
|
2014-03-25 19:55:12 +04:00
|
|
|
12, TCG_REG_R1, /* DW_CFA_def_cfa r1, ... */
|
2013-08-31 15:44:21 +04:00
|
|
|
(FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */
|
|
|
|
(FRAME_SIZE >> 7)
|
|
|
|
},
|
|
|
|
.fde_reg_ofs = {
|
2014-03-25 19:55:12 +04:00
|
|
|
/* DW_CFA_offset_extended_sf, lr, LR_OFFSET */
|
|
|
|
0x11, 65, (LR_OFFSET / -SZR) & 0x7f,
|
2013-08-31 15:44:21 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-10-29 19:17:30 +03:00
|
|
|
void tcg_register_jit(const void *buf, size_t buf_size)
|
2013-08-31 15:44:21 +04:00
|
|
|
{
|
|
|
|
uint8_t *p = &debug_frame.fde_reg_ofs[3];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); ++i, p += 2) {
|
|
|
|
p[0] = 0x80 + tcg_target_callee_save_regs[i];
|
2014-03-25 19:55:12 +04:00
|
|
|
p[1] = (FRAME_SIZE - (REG_SAVE_BOT + i * SZR)) / SZR;
|
2013-08-31 15:44:21 +04:00
|
|
|
}
|
|
|
|
|
2014-03-25 19:55:12 +04:00
|
|
|
debug_frame.fde.func_start = (uintptr_t)buf;
|
2013-08-31 15:44:21 +04:00
|
|
|
debug_frame.fde.func_len = buf_size;
|
|
|
|
|
|
|
|
tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
|
|
|
|
}
|
2014-03-25 20:13:38 +04:00
|
|
|
#endif /* __ELF__ */
|
target/ppc: moved vector even and odd multiplication to decodetree
Moved the instructions vmulesb, vmulosb, vmuleub, vmuloub,
vmulesh, vmulosh, vmuleuh, vmulouh, vmulesw, vmulosw,
muleuw and vmulouw from legacy to decodetree. Implemented
the instructions vmulesd, vmulosd, vmuleud, vmuloud.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Lucas Mateus Castro (alqotel) <lucas.araujo@eldorado.org.br>
Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
Message-Id: <20220225210936.1749575-3-matheus.ferst@eldorado.org.br>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
2022-03-02 08:51:36 +03:00
|
|
|
#undef VMULEUB
|
|
|
|
#undef VMULEUH
|
|
|
|
#undef VMULEUW
|
|
|
|
#undef VMULOUB
|
|
|
|
#undef VMULOUH
|
|
|
|
#undef VMULOUW
|
2022-05-17 15:39:28 +03:00
|
|
|
#undef VMSUMUHM
|