Import QEMU upstream snapshot d2e570c
Upstream: https://gitlab.com/qemu-project/qemu.git Upstream-Commit: d2e570cc0f97b936902a5b1b86b73c0f5998b475
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Define AArch64 target-specific constraint sets.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs.
|
||||
* Each operand should be a sequence of constraint letters as defined by
|
||||
* tcg-target-con-str.h; the constraint combination is inclusive or.
|
||||
*/
|
||||
C_O0_I1(r)
|
||||
C_O0_I2(r, rC)
|
||||
C_O0_I2(rz, r)
|
||||
C_O0_I2(w, r)
|
||||
C_O0_I3(rz, rz, r)
|
||||
C_O1_I1(r, r)
|
||||
C_O1_I1(w, r)
|
||||
C_O1_I1(w, w)
|
||||
C_O1_I1(w, wr)
|
||||
C_O1_I2(r, r, r)
|
||||
C_O1_I2(r, r, rA)
|
||||
C_O1_I2(r, r, rAL)
|
||||
C_O1_I2(r, r, rC)
|
||||
C_O1_I2(r, r, ri)
|
||||
C_O1_I2(r, r, rL)
|
||||
C_O1_I2(r, r, rS)
|
||||
C_O1_I2(r, r, rU)
|
||||
C_O1_I2(r, rZ, rA)
|
||||
C_O1_I2(r, rz, rMZ)
|
||||
C_O1_I2(r, rz, rz)
|
||||
C_O1_I2(r, rZ, rZ)
|
||||
C_O1_I2(w, 0, w)
|
||||
C_O1_I2(w, w, w)
|
||||
C_O1_I2(w, w, wN)
|
||||
C_O1_I2(w, w, wO)
|
||||
C_O1_I2(w, w, wZ)
|
||||
C_O1_I3(w, w, w, w)
|
||||
C_O1_I4(r, r, rC, rz, rz)
|
||||
C_O2_I1(r, r, r)
|
||||
@@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Define AArch64 target-specific operand constraints.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define constraint letters for register sets:
|
||||
* REGS(letter, register_mask)
|
||||
*/
|
||||
REGS('r', ALL_GENERAL_REGS)
|
||||
REGS('w', ALL_VECTOR_REGS)
|
||||
|
||||
/*
|
||||
* Define constraint letters for constants:
|
||||
* CONST(letter, TCG_CT_CONST_* bit set)
|
||||
*/
|
||||
CONST('A', TCG_CT_CONST_AIMM)
|
||||
CONST('C', TCG_CT_CONST_CMP)
|
||||
CONST('L', TCG_CT_CONST_LIMM)
|
||||
CONST('M', TCG_CT_CONST_MONE)
|
||||
CONST('O', TCG_CT_CONST_ORRI)
|
||||
CONST('N', TCG_CT_CONST_ANDI)
|
||||
CONST('S', TCG_CT_CONST_S8)
|
||||
CONST('U', TCG_CT_CONST_U8)
|
||||
CONST('Z', TCG_CT_CONST_ZERO)
|
||||
@@ -0,0 +1,60 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Define target-specific opcode support
|
||||
* Copyright (c) 2013 Huawei Technologies Duesseldorf GmbH
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_HAS_H
|
||||
#define TCG_TARGET_HAS_H
|
||||
|
||||
#include "host/cpuinfo.h"
|
||||
|
||||
#define have_lse (cpuinfo & CPUINFO_LSE)
|
||||
#define have_lse2 (cpuinfo & CPUINFO_LSE2)
|
||||
|
||||
/* optional instructions */
|
||||
#define TCG_TARGET_HAS_extr_i64_i32 0
|
||||
|
||||
/*
|
||||
* Without FEAT_LSE2, we must use LDXP+STXP to implement atomic 128-bit load,
|
||||
* which requires writable pages. We must defer to the helper for user-only,
|
||||
* but in system mode all ram is writable for the host.
|
||||
*/
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 have_lse2
|
||||
#else
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 1
|
||||
#endif
|
||||
|
||||
#define TCG_TARGET_HAS_tst 1
|
||||
|
||||
#define TCG_TARGET_HAS_v64 1
|
||||
#define TCG_TARGET_HAS_v128 1
|
||||
#define TCG_TARGET_HAS_v256 0
|
||||
|
||||
#define TCG_TARGET_HAS_andc_vec 1
|
||||
#define TCG_TARGET_HAS_orc_vec 1
|
||||
#define TCG_TARGET_HAS_nand_vec 0
|
||||
#define TCG_TARGET_HAS_nor_vec 0
|
||||
#define TCG_TARGET_HAS_eqv_vec 0
|
||||
#define TCG_TARGET_HAS_not_vec 1
|
||||
#define TCG_TARGET_HAS_neg_vec 1
|
||||
#define TCG_TARGET_HAS_abs_vec 1
|
||||
#define TCG_TARGET_HAS_roti_vec 0
|
||||
#define TCG_TARGET_HAS_rots_vec 0
|
||||
#define TCG_TARGET_HAS_rotv_vec 0
|
||||
#define TCG_TARGET_HAS_shi_vec 1
|
||||
#define TCG_TARGET_HAS_shs_vec 0
|
||||
#define TCG_TARGET_HAS_shv_vec 1
|
||||
#define TCG_TARGET_HAS_mul_vec 1
|
||||
#define TCG_TARGET_HAS_sat_vec 1
|
||||
#define TCG_TARGET_HAS_minmax_vec 1
|
||||
#define TCG_TARGET_HAS_bitsel_vec 1
|
||||
#define TCG_TARGET_HAS_cmpsel_vec 0
|
||||
#define TCG_TARGET_HAS_tst_vec 1
|
||||
|
||||
#define TCG_TARGET_extract_valid(type, ofs, len) 1
|
||||
#define TCG_TARGET_sextract_valid(type, ofs, len) 1
|
||||
#define TCG_TARGET_deposit_valid(type, ofs, len) 1
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Define target-specific memory model
|
||||
* Copyright (c) 2013 Huawei Technologies Duesseldorf GmbH
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_MO_H
|
||||
#define TCG_TARGET_MO_H
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Linaro
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* See the COPYING file in the top-level directory for details.
|
||||
*
|
||||
* Target-specific opcodes for host vector expansion. These will be
|
||||
* emitted by tcg_expand_vec_op. For those familiar with GCC internals,
|
||||
* consider these to be UNSPEC with names.
|
||||
*/
|
||||
|
||||
DEF(aa64_sshl_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
DEF(aa64_sli_vec, 1, 2, 1, TCG_OPF_VECTOR)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Initial TCG Implementation for aarch64
|
||||
*
|
||||
* Copyright (c) 2013 Huawei Technologies Duesseldorf GmbH
|
||||
* Written by Claudio Fontana
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* See the COPYING file in the top-level directory for details.
|
||||
*/
|
||||
|
||||
#ifndef AARCH64_TCG_TARGET_H
|
||||
#define AARCH64_TCG_TARGET_H
|
||||
|
||||
#define TCG_TARGET_INSN_UNIT_SIZE 4
|
||||
#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
|
||||
|
||||
typedef enum {
|
||||
TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3,
|
||||
TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7,
|
||||
TCG_REG_X8, TCG_REG_X9, TCG_REG_X10, TCG_REG_X11,
|
||||
TCG_REG_X12, TCG_REG_X13, TCG_REG_X14, TCG_REG_X15,
|
||||
TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19,
|
||||
TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23,
|
||||
TCG_REG_X24, TCG_REG_X25, TCG_REG_X26, TCG_REG_X27,
|
||||
TCG_REG_X28, TCG_REG_X29, TCG_REG_X30,
|
||||
|
||||
/* X31 is either the stack pointer or zero, depending on context. */
|
||||
TCG_REG_SP = 31,
|
||||
TCG_REG_XZR = 31,
|
||||
|
||||
TCG_REG_V0 = 32, TCG_REG_V1, TCG_REG_V2, 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,
|
||||
TCG_REG_V20, TCG_REG_V21, TCG_REG_V22, TCG_REG_V23,
|
||||
TCG_REG_V24, TCG_REG_V25, TCG_REG_V26, TCG_REG_V27,
|
||||
TCG_REG_V28, TCG_REG_V29, TCG_REG_V30, TCG_REG_V31,
|
||||
|
||||
/* Aliases. */
|
||||
TCG_REG_FP = TCG_REG_X29,
|
||||
TCG_REG_LR = TCG_REG_X30,
|
||||
TCG_AREG0 = TCG_REG_X19,
|
||||
} TCGReg;
|
||||
|
||||
#define TCG_REG_ZERO TCG_REG_XZR
|
||||
|
||||
#define TCG_TARGET_NB_REGS 64
|
||||
|
||||
#endif /* AARCH64_TCG_TARGET_H */
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Debug information support.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/lockable.h"
|
||||
#include "tcg/debuginfo.h"
|
||||
|
||||
#include <elfutils/libdwfl.h>
|
||||
|
||||
static QemuMutex lock;
|
||||
static Dwfl *dwfl;
|
||||
static const Dwfl_Callbacks dwfl_callbacks = {
|
||||
.find_elf = NULL,
|
||||
.find_debuginfo = dwfl_standard_find_debuginfo,
|
||||
.section_address = NULL,
|
||||
.debuginfo_path = NULL,
|
||||
};
|
||||
|
||||
__attribute__((constructor))
|
||||
static void debuginfo_init(void)
|
||||
{
|
||||
qemu_mutex_init(&lock);
|
||||
}
|
||||
|
||||
void debuginfo_report_elf(const char *name, int fd, uint64_t bias)
|
||||
{
|
||||
QEMU_LOCK_GUARD(&lock);
|
||||
|
||||
if (dwfl) {
|
||||
dwfl_report_begin_add(dwfl);
|
||||
} else {
|
||||
dwfl = dwfl_begin(&dwfl_callbacks);
|
||||
}
|
||||
|
||||
if (dwfl) {
|
||||
dwfl_report_elf(dwfl, name, name, fd, bias, true);
|
||||
dwfl_report_end(dwfl, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void debuginfo_lock(void)
|
||||
{
|
||||
qemu_mutex_lock(&lock);
|
||||
}
|
||||
|
||||
void debuginfo_query(struct debuginfo_query *q, size_t n)
|
||||
{
|
||||
const char *symbol, *file;
|
||||
Dwfl_Module *dwfl_module;
|
||||
Dwfl_Line *dwfl_line;
|
||||
GElf_Off dwfl_offset;
|
||||
GElf_Sym dwfl_sym;
|
||||
size_t i;
|
||||
int line;
|
||||
|
||||
if (!dwfl) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
dwfl_module = dwfl_addrmodule(dwfl, q[i].address);
|
||||
if (!dwfl_module) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (q[i].flags & DEBUGINFO_SYMBOL) {
|
||||
symbol = dwfl_module_addrinfo(dwfl_module, q[i].address,
|
||||
&dwfl_offset, &dwfl_sym,
|
||||
NULL, NULL, NULL);
|
||||
if (symbol) {
|
||||
q[i].symbol = symbol;
|
||||
q[i].offset = dwfl_offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (q[i].flags & DEBUGINFO_LINE) {
|
||||
dwfl_line = dwfl_module_getsrc(dwfl_module, q[i].address);
|
||||
if (dwfl_line) {
|
||||
file = dwfl_lineinfo(dwfl_line, NULL, &line, 0, NULL, NULL);
|
||||
if (file) {
|
||||
q[i].file = file;
|
||||
q[i].line = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debuginfo_unlock(void)
|
||||
{
|
||||
qemu_mutex_unlock(&lock);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define LoongArch target-specific constraint sets.
|
||||
*
|
||||
* Copyright (c) 2021 WANG Xuerui <[email protected]>
|
||||
*
|
||||
* Based on tcg/riscv/tcg-target-con-set.h
|
||||
*
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs.
|
||||
* Each operand should be a sequence of constraint letters as defined by
|
||||
* tcg-target-con-str.h; the constraint combination is inclusive or.
|
||||
*/
|
||||
C_O0_I1(r)
|
||||
C_O0_I2(rz, r)
|
||||
C_O0_I2(r, rz)
|
||||
C_O0_I2(w, r)
|
||||
C_O0_I3(r, r, r)
|
||||
C_O1_I1(r, r)
|
||||
C_O1_I1(w, r)
|
||||
C_O1_I1(w, w)
|
||||
C_O1_I2(r, r, r)
|
||||
C_O1_I2(r, r, ri)
|
||||
C_O1_I2(r, r, rI)
|
||||
C_O1_I2(r, r, rJ)
|
||||
C_O1_I2(r, r, rU)
|
||||
C_O1_I2(r, r, rW)
|
||||
C_O1_I2(r, 0, rz)
|
||||
C_O1_I2(w, w, w)
|
||||
C_O1_I2(w, w, wM)
|
||||
C_O1_I2(w, w, wA)
|
||||
C_O1_I3(w, w, w, w)
|
||||
C_O1_I4(r, r, rJ, rz, rz)
|
||||
C_N2_I1(r, r, r)
|
||||
@@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define LoongArch target-specific operand constraints.
|
||||
*
|
||||
* Copyright (c) 2021 WANG Xuerui <[email protected]>
|
||||
*
|
||||
* Based on tcg/riscv/tcg-target-con-str.h
|
||||
*
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define constraint letters for register sets:
|
||||
* REGS(letter, register_mask)
|
||||
*/
|
||||
REGS('r', ALL_GENERAL_REGS)
|
||||
REGS('w', ALL_VECTOR_REGS)
|
||||
|
||||
/*
|
||||
* Define constraint letters for constants:
|
||||
* CONST(letter, TCG_CT_CONST_* bit set)
|
||||
*/
|
||||
CONST('I', TCG_CT_CONST_S12)
|
||||
CONST('J', TCG_CT_CONST_S32)
|
||||
CONST('U', TCG_CT_CONST_U12)
|
||||
CONST('W', TCG_CT_CONST_WSZ)
|
||||
CONST('M', TCG_CT_CONST_VCMP)
|
||||
CONST('A', TCG_CT_CONST_VADD)
|
||||
@@ -0,0 +1,57 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific opcode support
|
||||
* Copyright (c) 2021 WANG Xuerui <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_HAS_H
|
||||
#define TCG_TARGET_HAS_H
|
||||
|
||||
#include "host/cpuinfo.h"
|
||||
|
||||
/* 64-bit operations */
|
||||
#define TCG_TARGET_HAS_extr_i64_i32 1
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 (cpuinfo & CPUINFO_LSX)
|
||||
|
||||
#define TCG_TARGET_HAS_tst 0
|
||||
|
||||
#define TCG_TARGET_HAS_v64 (cpuinfo & CPUINFO_LSX)
|
||||
#define TCG_TARGET_HAS_v128 (cpuinfo & CPUINFO_LSX)
|
||||
#define TCG_TARGET_HAS_v256 (cpuinfo & CPUINFO_LASX)
|
||||
|
||||
#define TCG_TARGET_HAS_not_vec 1
|
||||
#define TCG_TARGET_HAS_neg_vec 1
|
||||
#define TCG_TARGET_HAS_abs_vec 0
|
||||
#define TCG_TARGET_HAS_andc_vec 1
|
||||
#define TCG_TARGET_HAS_orc_vec 1
|
||||
#define TCG_TARGET_HAS_nand_vec 0
|
||||
#define TCG_TARGET_HAS_nor_vec 1
|
||||
#define TCG_TARGET_HAS_eqv_vec 0
|
||||
#define TCG_TARGET_HAS_mul_vec 1
|
||||
#define TCG_TARGET_HAS_shi_vec 1
|
||||
#define TCG_TARGET_HAS_shs_vec 0
|
||||
#define TCG_TARGET_HAS_shv_vec 1
|
||||
#define TCG_TARGET_HAS_roti_vec 1
|
||||
#define TCG_TARGET_HAS_rots_vec 0
|
||||
#define TCG_TARGET_HAS_rotv_vec 1
|
||||
#define TCG_TARGET_HAS_sat_vec 1
|
||||
#define TCG_TARGET_HAS_minmax_vec 1
|
||||
#define TCG_TARGET_HAS_bitsel_vec 1
|
||||
#define TCG_TARGET_HAS_cmpsel_vec 0
|
||||
#define TCG_TARGET_HAS_tst_vec 0
|
||||
|
||||
#define TCG_TARGET_extract_valid(type, ofs, len) 1
|
||||
#define TCG_TARGET_deposit_valid(type, ofs, len) 1
|
||||
|
||||
static inline bool
|
||||
tcg_target_sextract_valid(TCGType type, unsigned ofs, unsigned len)
|
||||
{
|
||||
if (type == TCG_TYPE_I64 && ofs + len == 32) {
|
||||
return true;
|
||||
}
|
||||
return ofs == 0 && (len == 8 || len == 16);
|
||||
}
|
||||
#define TCG_TARGET_sextract_valid tcg_target_sextract_valid
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific memory model
|
||||
* Copyright (c) 2021 WANG Xuerui <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_MO_H
|
||||
#define TCG_TARGET_MO_H
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Jiajie Chen
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* See the COPYING file in the top-level directory for details.
|
||||
*
|
||||
* Target-specific opcodes for host vector expansion. These will be
|
||||
* emitted by tcg_expand_vec_op. For those familiar with GCC internals,
|
||||
* consider these to be UNSPEC with names.
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2021 WANG Xuerui <[email protected]>
|
||||
*
|
||||
* Based on tcg/riscv/tcg-target.h
|
||||
*
|
||||
* Copyright (c) 2018 SiFive, Inc
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef LOONGARCH_TCG_TARGET_H
|
||||
#define LOONGARCH_TCG_TARGET_H
|
||||
|
||||
#define TCG_TARGET_INSN_UNIT_SIZE 4
|
||||
#define TCG_TARGET_NB_REGS 64
|
||||
|
||||
#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
|
||||
|
||||
typedef enum {
|
||||
TCG_REG_ZERO,
|
||||
TCG_REG_RA,
|
||||
TCG_REG_TP,
|
||||
TCG_REG_SP,
|
||||
TCG_REG_A0,
|
||||
TCG_REG_A1,
|
||||
TCG_REG_A2,
|
||||
TCG_REG_A3,
|
||||
TCG_REG_A4,
|
||||
TCG_REG_A5,
|
||||
TCG_REG_A6,
|
||||
TCG_REG_A7,
|
||||
TCG_REG_T0,
|
||||
TCG_REG_T1,
|
||||
TCG_REG_T2,
|
||||
TCG_REG_T3,
|
||||
TCG_REG_T4,
|
||||
TCG_REG_T5,
|
||||
TCG_REG_T6,
|
||||
TCG_REG_T7,
|
||||
TCG_REG_T8,
|
||||
TCG_REG_RESERVED,
|
||||
TCG_REG_S9,
|
||||
TCG_REG_S0,
|
||||
TCG_REG_S1,
|
||||
TCG_REG_S2,
|
||||
TCG_REG_S3,
|
||||
TCG_REG_S4,
|
||||
TCG_REG_S5,
|
||||
TCG_REG_S6,
|
||||
TCG_REG_S7,
|
||||
TCG_REG_S8,
|
||||
|
||||
TCG_REG_V0 = 32, TCG_REG_V1, TCG_REG_V2, 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,
|
||||
TCG_REG_V20, TCG_REG_V21, TCG_REG_V22, TCG_REG_V23,
|
||||
TCG_REG_V24, TCG_REG_V25, TCG_REG_V26, TCG_REG_V27,
|
||||
TCG_REG_V28, TCG_REG_V29, TCG_REG_V30, TCG_REG_V31,
|
||||
|
||||
/* aliases */
|
||||
TCG_AREG0 = TCG_REG_S0,
|
||||
TCG_REG_TMP0 = TCG_REG_T8,
|
||||
TCG_REG_TMP1 = TCG_REG_T7,
|
||||
TCG_REG_TMP2 = TCG_REG_T6,
|
||||
TCG_VEC_TMP0 = TCG_REG_V23,
|
||||
} TCGReg;
|
||||
|
||||
#define TCG_REG_ZERO TCG_REG_ZERO
|
||||
|
||||
#endif /* LOONGARCH_TCG_TARGET_H */
|
||||
@@ -0,0 +1,31 @@
|
||||
if not have_tcg
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
tcg_ss = ss.source_set()
|
||||
|
||||
tcg_ss.add(files(
|
||||
'optimize.c',
|
||||
'region.c',
|
||||
'tcg.c',
|
||||
'tcg-common.c',
|
||||
'tcg-op.c',
|
||||
'tcg-op-ldst.c',
|
||||
'tcg-op-gvec.c',
|
||||
'tcg-op-vec.c',
|
||||
))
|
||||
|
||||
if get_option('tcg_interpreter')
|
||||
libffi = dependency('libffi', version: '>=3.0', required: true,
|
||||
method: 'pkg-config')
|
||||
tcg_ss.add(libffi)
|
||||
tcg_ss.add(files('tci.c'))
|
||||
endif
|
||||
|
||||
tcg_ss.add(when: libdw, if_true: files('debuginfo.c'))
|
||||
if host_os == 'linux'
|
||||
tcg_ss.add(files('perf.c'))
|
||||
endif
|
||||
|
||||
user_ss.add_all(tcg_ss)
|
||||
system_ss.add_all(tcg_ss)
|
||||
+3346
File diff suppressed because it is too large
Load Diff
+381
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* Linux perf perf-<pid>.map and jit-<pid>.dump integration.
|
||||
*
|
||||
* The jitdump spec can be found at [1].
|
||||
*
|
||||
* [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/tools/perf/Documentation/jitdump-specification.txt
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "elf.h"
|
||||
#include "exec/target_page.h"
|
||||
#include "exec/translation-block.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "tcg/debuginfo.h"
|
||||
#include "tcg/perf.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
||||
static FILE *safe_fopen_w(const char *path)
|
||||
{
|
||||
int saved_errno;
|
||||
FILE *f;
|
||||
int fd;
|
||||
|
||||
/* Delete the old file, if any. */
|
||||
unlink(path);
|
||||
|
||||
/* Avoid symlink attacks by using O_CREAT | O_EXCL. */
|
||||
fd = open(path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
if (fd == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Convert fd to FILE*. */
|
||||
f = fdopen(fd, "w");
|
||||
if (f == NULL) {
|
||||
saved_errno = errno;
|
||||
close(fd);
|
||||
errno = saved_errno;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static FILE *perfmap;
|
||||
|
||||
void perf_enable_perfmap(void)
|
||||
{
|
||||
char map_file[32];
|
||||
|
||||
snprintf(map_file, sizeof(map_file), "/tmp/perf-%d.map", getpid());
|
||||
perfmap = safe_fopen_w(map_file);
|
||||
if (perfmap == NULL) {
|
||||
warn_report("Could not open %s: %s, proceeding without perfmap",
|
||||
map_file, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/* Get PC and size of code JITed for guest instruction #INSN. */
|
||||
static void get_host_pc_size(uintptr_t *host_pc, uint16_t *host_size,
|
||||
const void *start, size_t insn)
|
||||
{
|
||||
uint16_t start_off = insn ? tcg_ctx->gen_insn_end_off[insn - 1] : 0;
|
||||
|
||||
if (host_pc) {
|
||||
*host_pc = (uintptr_t)start + start_off;
|
||||
}
|
||||
if (host_size) {
|
||||
*host_size = tcg_ctx->gen_insn_end_off[insn] - start_off;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *pretty_symbol(const struct debuginfo_query *q, size_t *len)
|
||||
{
|
||||
static __thread char buf[64];
|
||||
int tmp;
|
||||
|
||||
if (!q->symbol) {
|
||||
tmp = snprintf(buf, sizeof(buf), "guest-0x%"PRIx64, q->address);
|
||||
if (len) {
|
||||
*len = MIN(tmp + 1, sizeof(buf));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (!q->offset) {
|
||||
if (len) {
|
||||
*len = strlen(q->symbol) + 1;
|
||||
}
|
||||
return q->symbol;
|
||||
}
|
||||
|
||||
tmp = snprintf(buf, sizeof(buf), "%s+0x%"PRIx64, q->symbol, q->offset);
|
||||
if (len) {
|
||||
*len = MIN(tmp + 1, sizeof(buf));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void write_perfmap_entry(const void *start, size_t insn,
|
||||
const struct debuginfo_query *q)
|
||||
{
|
||||
uint16_t host_size;
|
||||
uintptr_t host_pc;
|
||||
|
||||
get_host_pc_size(&host_pc, &host_size, start, insn);
|
||||
fprintf(perfmap, "%"PRIxPTR" %"PRIx16" %s\n",
|
||||
host_pc, host_size, pretty_symbol(q, NULL));
|
||||
}
|
||||
|
||||
static FILE *jitdump;
|
||||
static size_t perf_marker_size;
|
||||
static void *perf_marker = MAP_FAILED;
|
||||
|
||||
#define JITHEADER_MAGIC 0x4A695444
|
||||
#define JITHEADER_VERSION 1
|
||||
|
||||
struct jitheader {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t total_size;
|
||||
uint32_t elf_mach;
|
||||
uint32_t pad1;
|
||||
uint32_t pid;
|
||||
uint64_t timestamp;
|
||||
uint64_t flags;
|
||||
};
|
||||
|
||||
enum jit_record_type {
|
||||
JIT_CODE_LOAD = 0,
|
||||
JIT_CODE_DEBUG_INFO = 2,
|
||||
};
|
||||
|
||||
struct jr_prefix {
|
||||
uint32_t id;
|
||||
uint32_t total_size;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
struct jr_code_load {
|
||||
struct jr_prefix p;
|
||||
|
||||
uint32_t pid;
|
||||
uint32_t tid;
|
||||
uint64_t vma;
|
||||
uint64_t code_addr;
|
||||
uint64_t code_size;
|
||||
uint64_t code_index;
|
||||
};
|
||||
|
||||
struct debug_entry {
|
||||
uint64_t addr;
|
||||
int lineno;
|
||||
int discrim;
|
||||
const char name[];
|
||||
};
|
||||
|
||||
struct jr_code_debug_info {
|
||||
struct jr_prefix p;
|
||||
|
||||
uint64_t code_addr;
|
||||
uint64_t nr_entry;
|
||||
struct debug_entry entries[];
|
||||
};
|
||||
|
||||
static uint32_t get_e_machine(void)
|
||||
{
|
||||
Elf64_Ehdr elf_header;
|
||||
FILE *exe;
|
||||
size_t n;
|
||||
|
||||
QEMU_BUILD_BUG_ON(offsetof(Elf32_Ehdr, e_machine) !=
|
||||
offsetof(Elf64_Ehdr, e_machine));
|
||||
|
||||
exe = fopen("/proc/self/exe", "r");
|
||||
if (exe == NULL) {
|
||||
return EM_NONE;
|
||||
}
|
||||
|
||||
n = fread(&elf_header, sizeof(elf_header), 1, exe);
|
||||
fclose(exe);
|
||||
if (n != 1) {
|
||||
return EM_NONE;
|
||||
}
|
||||
|
||||
return elf_header.e_machine;
|
||||
}
|
||||
|
||||
void perf_enable_jitdump(void)
|
||||
{
|
||||
struct jitheader header;
|
||||
char jitdump_file[32];
|
||||
|
||||
if (!use_rt_clock) {
|
||||
warn_report("CLOCK_MONOTONIC is not available, proceeding without jitdump");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(jitdump_file, sizeof(jitdump_file), "jit-%d.dump", getpid());
|
||||
jitdump = safe_fopen_w(jitdump_file);
|
||||
if (jitdump == NULL) {
|
||||
warn_report("Could not open %s: %s, proceeding without jitdump",
|
||||
jitdump_file, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* `perf inject` will see that the mapped file name in the corresponding
|
||||
* PERF_RECORD_MMAP or PERF_RECORD_MMAP2 event is of the form jit-%d.dump
|
||||
* and will process it as a jitdump file.
|
||||
*/
|
||||
perf_marker_size = qemu_real_host_page_size();
|
||||
perf_marker = mmap(NULL, perf_marker_size, PROT_READ | PROT_EXEC,
|
||||
MAP_PRIVATE, fileno(jitdump), 0);
|
||||
if (perf_marker == MAP_FAILED) {
|
||||
warn_report("Could not map %s: %s, proceeding without jitdump",
|
||||
jitdump_file, strerror(errno));
|
||||
fclose(jitdump);
|
||||
jitdump = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
header.magic = JITHEADER_MAGIC;
|
||||
header.version = JITHEADER_VERSION;
|
||||
header.total_size = sizeof(header);
|
||||
header.elf_mach = get_e_machine();
|
||||
header.pad1 = 0;
|
||||
header.pid = getpid();
|
||||
header.timestamp = get_clock();
|
||||
header.flags = 0;
|
||||
fwrite(&header, sizeof(header), 1, jitdump);
|
||||
}
|
||||
|
||||
void perf_report_prologue(const void *start, size_t size)
|
||||
{
|
||||
if (perfmap) {
|
||||
fprintf(perfmap, "%"PRIxPTR" %zx tcg-prologue-buffer\n",
|
||||
(uintptr_t)start, size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a JIT_CODE_DEBUG_INFO jitdump entry. */
|
||||
static void write_jr_code_debug_info(const void *start,
|
||||
const struct debuginfo_query *q,
|
||||
size_t icount)
|
||||
{
|
||||
struct jr_code_debug_info rec;
|
||||
struct debug_entry ent;
|
||||
uintptr_t host_pc;
|
||||
int insn;
|
||||
|
||||
/* Write the header. */
|
||||
rec.p.id = JIT_CODE_DEBUG_INFO;
|
||||
rec.p.total_size = sizeof(rec) + sizeof(ent) + 1;
|
||||
rec.p.timestamp = get_clock();
|
||||
rec.code_addr = (uintptr_t)start;
|
||||
rec.nr_entry = 1;
|
||||
for (insn = 0; insn < icount; insn++) {
|
||||
if (q[insn].file) {
|
||||
rec.p.total_size += sizeof(ent) + strlen(q[insn].file) + 1;
|
||||
rec.nr_entry++;
|
||||
}
|
||||
}
|
||||
fwrite(&rec, sizeof(rec), 1, jitdump);
|
||||
|
||||
/* Write the main debug entries. */
|
||||
for (insn = 0; insn < icount; insn++) {
|
||||
if (q[insn].file) {
|
||||
get_host_pc_size(&host_pc, NULL, start, insn);
|
||||
ent.addr = host_pc;
|
||||
ent.lineno = q[insn].line;
|
||||
ent.discrim = 0;
|
||||
fwrite(&ent, sizeof(ent), 1, jitdump);
|
||||
fwrite(q[insn].file, strlen(q[insn].file) + 1, 1, jitdump);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the trailing debug_entry. */
|
||||
ent.addr = (uintptr_t)start + tcg_ctx->gen_insn_end_off[icount - 1];
|
||||
ent.lineno = 0;
|
||||
ent.discrim = 0;
|
||||
fwrite(&ent, sizeof(ent), 1, jitdump);
|
||||
fwrite("", 1, 1, jitdump);
|
||||
}
|
||||
|
||||
/* Write a JIT_CODE_LOAD jitdump entry. */
|
||||
static void write_jr_code_load(const void *start, uint16_t host_size,
|
||||
const struct debuginfo_query *q)
|
||||
{
|
||||
static uint64_t code_index;
|
||||
struct jr_code_load rec;
|
||||
const char *symbol;
|
||||
size_t symbol_size;
|
||||
|
||||
symbol = pretty_symbol(q, &symbol_size);
|
||||
rec.p.id = JIT_CODE_LOAD;
|
||||
rec.p.total_size = sizeof(rec) + symbol_size + host_size;
|
||||
rec.p.timestamp = get_clock();
|
||||
rec.pid = getpid();
|
||||
rec.tid = qemu_get_thread_id();
|
||||
rec.vma = (uintptr_t)start;
|
||||
rec.code_addr = (uintptr_t)start;
|
||||
rec.code_size = host_size;
|
||||
rec.code_index = code_index++;
|
||||
fwrite(&rec, sizeof(rec), 1, jitdump);
|
||||
fwrite(symbol, symbol_size, 1, jitdump);
|
||||
fwrite(start, host_size, 1, jitdump);
|
||||
}
|
||||
|
||||
void perf_report_code(uint64_t guest_pc, TranslationBlock *tb,
|
||||
const void *start)
|
||||
{
|
||||
struct debuginfo_query *q;
|
||||
size_t insn;
|
||||
uint64_t *gen_insn_data;
|
||||
|
||||
if (!perfmap && !jitdump) {
|
||||
return;
|
||||
}
|
||||
|
||||
q = g_try_malloc0_n(tb->icount, sizeof(*q));
|
||||
if (!q) {
|
||||
return;
|
||||
}
|
||||
|
||||
debuginfo_lock();
|
||||
|
||||
/* Query debuginfo for each guest instruction. */
|
||||
gen_insn_data = tcg_ctx->gen_insn_data;
|
||||
|
||||
for (insn = 0; insn < tb->icount; insn++) {
|
||||
/* FIXME: This replicates the restore_state_to_opc() logic. */
|
||||
q[insn].address = gen_insn_data[insn * INSN_START_WORDS + 0];
|
||||
if (tb_cflags(tb) & CF_PCREL) {
|
||||
q[insn].address |= guest_pc & TARGET_PAGE_MASK;
|
||||
}
|
||||
q[insn].flags = DEBUGINFO_SYMBOL | (jitdump ? DEBUGINFO_LINE : 0);
|
||||
}
|
||||
debuginfo_query(q, tb->icount);
|
||||
|
||||
/* Emit perfmap entries if needed. */
|
||||
if (perfmap) {
|
||||
flockfile(perfmap);
|
||||
for (insn = 0; insn < tb->icount; insn++) {
|
||||
write_perfmap_entry(start, insn, &q[insn]);
|
||||
}
|
||||
funlockfile(perfmap);
|
||||
}
|
||||
|
||||
/* Emit jitdump entries if needed. */
|
||||
if (jitdump) {
|
||||
flockfile(jitdump);
|
||||
write_jr_code_debug_info(start, q, tb->icount);
|
||||
write_jr_code_load(start, tcg_ctx->gen_insn_end_off[tb->icount - 1],
|
||||
q);
|
||||
funlockfile(jitdump);
|
||||
}
|
||||
|
||||
debuginfo_unlock();
|
||||
g_free(q);
|
||||
}
|
||||
|
||||
void perf_exit(void)
|
||||
{
|
||||
if (perfmap) {
|
||||
fclose(perfmap);
|
||||
perfmap = NULL;
|
||||
}
|
||||
|
||||
if (perf_marker != MAP_FAILED) {
|
||||
munmap(perf_marker, perf_marker_size);
|
||||
perf_marker = MAP_FAILED;
|
||||
}
|
||||
|
||||
if (jitdump) {
|
||||
fclose(jitdump);
|
||||
jitdump = NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define PowerPC target-specific constraint sets.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs.
|
||||
* Each operand should be a sequence of constraint letters as defined by
|
||||
* tcg-target-con-str.h; the constraint combination is inclusive or.
|
||||
*/
|
||||
C_O0_I1(r)
|
||||
C_O0_I2(r, r)
|
||||
C_O0_I2(r, rC)
|
||||
C_O0_I2(v, r)
|
||||
C_O0_I3(r, r, r)
|
||||
C_O0_I3(o, m, r)
|
||||
C_O0_I4(r, r, rU, rC)
|
||||
C_O0_I4(r, r, r, r)
|
||||
C_O1_I1(r, r)
|
||||
C_O1_I1(v, r)
|
||||
C_O1_I1(v, v)
|
||||
C_O1_I1(v, vr)
|
||||
C_O1_I2(r, 0, rZ)
|
||||
C_O1_I2(r, rI, r)
|
||||
C_O1_I2(r, r, r)
|
||||
C_O1_I2(r, r, ri)
|
||||
C_O1_I2(r, r, rC)
|
||||
C_O1_I2(r, r, rI)
|
||||
C_O1_I2(r, r, rT)
|
||||
C_O1_I2(r, r, rU)
|
||||
C_O1_I2(r, r, rZM)
|
||||
C_O1_I2(r, r, rZW)
|
||||
C_O1_I2(r, rI, rN)
|
||||
C_O1_I2(r, rZM, rZM)
|
||||
C_O1_I2(v, v, v)
|
||||
C_O1_I3(v, v, v, v)
|
||||
C_O1_I4(v, v, v, vZM, v)
|
||||
C_O1_I4(r, r, rC, rZ, rZ)
|
||||
C_O1_I4(r, r, r, rU, rC)
|
||||
C_O2_I1(r, r, r)
|
||||
C_N1O1_I1(o, m, r)
|
||||
C_O2_I2(r, r, r, r)
|
||||
@@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define PowerPC target-specific operand constraints.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define constraint letters for register sets:
|
||||
* REGS(letter, register_mask)
|
||||
*/
|
||||
REGS('r', ALL_GENERAL_REGS)
|
||||
REGS('o', ALL_GENERAL_REGS & 0xAAAAAAAAu) /* odd registers */
|
||||
REGS('v', ALL_VECTOR_REGS)
|
||||
|
||||
/*
|
||||
* Define constraint letters for constants:
|
||||
* CONST(letter, TCG_CT_CONST_* bit set)
|
||||
*/
|
||||
CONST('C', TCG_CT_CONST_CMP)
|
||||
CONST('I', TCG_CT_CONST_S16)
|
||||
CONST('M', TCG_CT_CONST_MONE)
|
||||
CONST('N', TCG_CT_CONST_N16)
|
||||
CONST('T', TCG_CT_CONST_S32)
|
||||
CONST('U', TCG_CT_CONST_U32)
|
||||
CONST('W', TCG_CT_CONST_WSZ)
|
||||
CONST('Z', TCG_CT_CONST_ZERO)
|
||||
@@ -0,0 +1,69 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific opcode support
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_HAS_H
|
||||
#define TCG_TARGET_HAS_H
|
||||
|
||||
#include "host/cpuinfo.h"
|
||||
|
||||
#define have_isa_2_06 (cpuinfo & CPUINFO_V2_06)
|
||||
#define have_isa_2_07 (cpuinfo & CPUINFO_V2_07)
|
||||
#define have_isa_3_00 (cpuinfo & CPUINFO_V3_0)
|
||||
#define have_isa_3_10 (cpuinfo & CPUINFO_V3_1)
|
||||
#define have_altivec (cpuinfo & CPUINFO_ALTIVEC)
|
||||
#define have_vsx (cpuinfo & CPUINFO_VSX)
|
||||
|
||||
/* optional instructions */
|
||||
#define TCG_TARGET_HAS_extr_i64_i32 0
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 have_isa_2_07
|
||||
|
||||
#define TCG_TARGET_HAS_tst 1
|
||||
|
||||
/*
|
||||
* While technically Altivec could support V64, it has no 64-bit store
|
||||
* instruction and substituting two 32-bit stores makes the generated
|
||||
* code quite large.
|
||||
*/
|
||||
#define TCG_TARGET_HAS_v64 have_vsx
|
||||
#define TCG_TARGET_HAS_v128 have_altivec
|
||||
#define TCG_TARGET_HAS_v256 0
|
||||
|
||||
#define TCG_TARGET_HAS_andc_vec 1
|
||||
#define TCG_TARGET_HAS_orc_vec have_isa_2_07
|
||||
#define TCG_TARGET_HAS_nand_vec have_isa_2_07
|
||||
#define TCG_TARGET_HAS_nor_vec 1
|
||||
#define TCG_TARGET_HAS_eqv_vec have_isa_2_07
|
||||
#define TCG_TARGET_HAS_not_vec 1
|
||||
#define TCG_TARGET_HAS_neg_vec have_isa_3_00
|
||||
#define TCG_TARGET_HAS_abs_vec 0
|
||||
#define TCG_TARGET_HAS_roti_vec 0
|
||||
#define TCG_TARGET_HAS_rots_vec 0
|
||||
#define TCG_TARGET_HAS_rotv_vec 1
|
||||
#define TCG_TARGET_HAS_shi_vec 0
|
||||
#define TCG_TARGET_HAS_shs_vec 0
|
||||
#define TCG_TARGET_HAS_shv_vec 1
|
||||
#define TCG_TARGET_HAS_mul_vec 1
|
||||
#define TCG_TARGET_HAS_sat_vec 1
|
||||
#define TCG_TARGET_HAS_minmax_vec 1
|
||||
#define TCG_TARGET_HAS_bitsel_vec have_vsx
|
||||
#define TCG_TARGET_HAS_cmpsel_vec 1
|
||||
#define TCG_TARGET_HAS_tst_vec 0
|
||||
|
||||
#define TCG_TARGET_extract_valid(type, ofs, len) 1
|
||||
#define TCG_TARGET_deposit_valid(type, ofs, len) 1
|
||||
|
||||
static inline bool
|
||||
tcg_target_sextract_valid(TCGType type, unsigned ofs, unsigned len)
|
||||
{
|
||||
if (type == TCG_TYPE_I64 && ofs + len == 32) {
|
||||
return true;
|
||||
}
|
||||
return ofs == 0 && (len == 8 || len == 16);
|
||||
}
|
||||
#define TCG_TARGET_sextract_valid tcg_target_sextract_valid
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific memory model
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_MO_H
|
||||
#define TCG_TARGET_MO_H
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Linaro Limited
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Target-specific opcodes for host vector expansion. These will be
|
||||
* emitted by tcg_expand_vec_op. For those familiar with GCC internals,
|
||||
* consider these to be UNSPEC with names.
|
||||
*/
|
||||
|
||||
DEF(ppc_mrgh_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
DEF(ppc_mrgl_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
DEF(ppc_msum_vec, 1, 3, 0, TCG_OPF_VECTOR)
|
||||
DEF(ppc_muleu_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
DEF(ppc_mulou_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
DEF(ppc_pkum_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PPC_TCG_TARGET_H
|
||||
#define PPC_TCG_TARGET_H
|
||||
|
||||
#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
|
||||
|
||||
#define TCG_TARGET_NB_REGS 64
|
||||
#define TCG_TARGET_INSN_UNIT_SIZE 4
|
||||
|
||||
typedef enum {
|
||||
TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3,
|
||||
TCG_REG_R4, TCG_REG_R5, TCG_REG_R6, TCG_REG_R7,
|
||||
TCG_REG_R8, TCG_REG_R9, TCG_REG_R10, TCG_REG_R11,
|
||||
TCG_REG_R12, TCG_REG_R13, 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,
|
||||
TCG_REG_R24, TCG_REG_R25, TCG_REG_R26, TCG_REG_R27,
|
||||
TCG_REG_R28, TCG_REG_R29, TCG_REG_R30, TCG_REG_R31,
|
||||
|
||||
TCG_REG_V0, TCG_REG_V1, TCG_REG_V2, 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,
|
||||
TCG_REG_V20, TCG_REG_V21, TCG_REG_V22, TCG_REG_V23,
|
||||
TCG_REG_V24, TCG_REG_V25, TCG_REG_V26, TCG_REG_V27,
|
||||
TCG_REG_V28, TCG_REG_V29, TCG_REG_V30, TCG_REG_V31,
|
||||
|
||||
TCG_REG_CALL_STACK = TCG_REG_R1,
|
||||
TCG_AREG0 = TCG_REG_R27
|
||||
} TCGReg;
|
||||
|
||||
#endif
|
||||
+929
@@ -0,0 +1,929 @@
|
||||
/*
|
||||
* Memory region management for 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.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/madvise.h"
|
||||
#include "qemu/mprotect.h"
|
||||
#include "qemu/memalign.h"
|
||||
#include "qemu/cacheinfo.h"
|
||||
#include "qemu/qtree.h"
|
||||
#include "qapi/error.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "exec/translation-block.h"
|
||||
#include "tcg-internal.h"
|
||||
#include "host/cpuinfo.h"
|
||||
|
||||
|
||||
/*
|
||||
* Local source-level compatibility with Unix.
|
||||
* Used by tcg_region_init below.
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define PROT_EXEC 4
|
||||
#endif
|
||||
|
||||
struct tcg_region_tree {
|
||||
QemuMutex lock;
|
||||
QTree *tree;
|
||||
/* padding to avoid false sharing is computed at run-time */
|
||||
};
|
||||
|
||||
/*
|
||||
* We divide code_gen_buffer into equally-sized "regions" that TCG threads
|
||||
* dynamically allocate from as demand dictates. Given appropriate region
|
||||
* sizing, this minimizes flushes even when some TCG threads generate a lot
|
||||
* more code than others.
|
||||
*/
|
||||
struct tcg_region_state {
|
||||
QemuMutex lock;
|
||||
|
||||
/* fields set at init time */
|
||||
void *start_aligned;
|
||||
void *after_prologue;
|
||||
size_t n;
|
||||
size_t size; /* size of one region */
|
||||
size_t stride; /* .size + guard size */
|
||||
size_t total_size; /* size of entire buffer, >= n * stride */
|
||||
|
||||
/* fields protected by the lock */
|
||||
size_t current; /* current region index */
|
||||
size_t agg_size_full; /* aggregate size of full regions */
|
||||
};
|
||||
|
||||
static struct tcg_region_state region;
|
||||
|
||||
/*
|
||||
* This is an array of struct tcg_region_tree's, with padding.
|
||||
* We use void * to simplify the computation of region_trees[i]; each
|
||||
* struct is found every tree_size bytes.
|
||||
*/
|
||||
static void *region_trees;
|
||||
static size_t tree_size;
|
||||
|
||||
bool in_code_gen_buffer(const void *p)
|
||||
{
|
||||
/*
|
||||
* Much like it is valid to have a pointer to the byte past the
|
||||
* end of an array (so long as you don't dereference it), allow
|
||||
* a pointer to the byte past the end of the code gen buffer.
|
||||
*/
|
||||
return (size_t)(p - region.start_aligned) <= region.total_size;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
static int host_prot_read_exec(void)
|
||||
{
|
||||
#if defined(CONFIG_LINUX) && defined(HOST_AARCH64) && defined(PROT_BTI)
|
||||
if (cpuinfo & CPUINFO_BTI) {
|
||||
return PROT_READ | PROT_EXEC | PROT_BTI;
|
||||
}
|
||||
#endif
|
||||
return PROT_READ | PROT_EXEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_TCG
|
||||
const void *tcg_splitwx_to_rx(void *rw)
|
||||
{
|
||||
/* Pass NULL pointers unchanged. */
|
||||
if (rw) {
|
||||
g_assert(in_code_gen_buffer(rw));
|
||||
rw += tcg_splitwx_diff;
|
||||
}
|
||||
return rw;
|
||||
}
|
||||
|
||||
void *tcg_splitwx_to_rw(const void *rx)
|
||||
{
|
||||
/* Pass NULL pointers unchanged. */
|
||||
if (rx) {
|
||||
rx -= tcg_splitwx_diff;
|
||||
/* Assert that we end with a pointer in the rw region. */
|
||||
g_assert(in_code_gen_buffer(rx));
|
||||
}
|
||||
return (void *)rx;
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_TCG */
|
||||
|
||||
/* compare a pointer @ptr and a tb_tc @s */
|
||||
static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
|
||||
{
|
||||
if (ptr >= s->ptr + s->size) {
|
||||
return 1;
|
||||
} else if (ptr < s->ptr) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp, gpointer userdata)
|
||||
{
|
||||
const struct tb_tc *a = ap;
|
||||
const struct tb_tc *b = bp;
|
||||
|
||||
/*
|
||||
* When both sizes are set, we know this isn't a lookup.
|
||||
* This is the most likely case: every TB must be inserted; lookups
|
||||
* are a lot less frequent.
|
||||
*/
|
||||
if (likely(a->size && b->size)) {
|
||||
if (a->ptr > b->ptr) {
|
||||
return 1;
|
||||
} else if (a->ptr < b->ptr) {
|
||||
return -1;
|
||||
}
|
||||
/* a->ptr == b->ptr should happen only on deletions */
|
||||
g_assert(a->size == b->size);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* All lookups have either .size field set to 0.
|
||||
* From the glib sources we see that @ap is always the lookup key. However
|
||||
* the docs provide no guarantee, so we just mark this case as likely.
|
||||
*/
|
||||
if (likely(a->size == 0)) {
|
||||
return ptr_cmp_tb_tc(a->ptr, b);
|
||||
}
|
||||
return ptr_cmp_tb_tc(b->ptr, a);
|
||||
}
|
||||
|
||||
static void tb_destroy(gpointer value)
|
||||
{
|
||||
TranslationBlock *tb = value;
|
||||
qemu_spin_destroy(&tb->jmp_lock);
|
||||
}
|
||||
|
||||
static void tcg_region_trees_init(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
|
||||
region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
|
||||
for (i = 0; i < region.n; i++) {
|
||||
struct tcg_region_tree *rt = region_trees + i * tree_size;
|
||||
|
||||
qemu_mutex_init(&rt->lock);
|
||||
rt->tree = q_tree_new_full(tb_tc_cmp, NULL, NULL, tb_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
static struct tcg_region_tree *tc_ptr_to_region_tree(const void *p)
|
||||
{
|
||||
size_t region_idx;
|
||||
|
||||
/*
|
||||
* Like tcg_splitwx_to_rw, with no assert. The pc may come from
|
||||
* a signal handler over which the caller has no control.
|
||||
*/
|
||||
if (!in_code_gen_buffer(p)) {
|
||||
p -= tcg_splitwx_diff;
|
||||
if (!in_code_gen_buffer(p)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (p < region.start_aligned) {
|
||||
region_idx = 0;
|
||||
} else {
|
||||
ptrdiff_t offset = p - region.start_aligned;
|
||||
|
||||
if (offset > region.stride * (region.n - 1)) {
|
||||
region_idx = region.n - 1;
|
||||
} else {
|
||||
region_idx = offset / region.stride;
|
||||
}
|
||||
}
|
||||
return region_trees + region_idx * tree_size;
|
||||
}
|
||||
|
||||
void tcg_tb_insert(TranslationBlock *tb)
|
||||
{
|
||||
struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
|
||||
|
||||
g_assert(rt != NULL);
|
||||
qemu_mutex_lock(&rt->lock);
|
||||
q_tree_insert(rt->tree, &tb->tc, tb);
|
||||
qemu_mutex_unlock(&rt->lock);
|
||||
}
|
||||
|
||||
void tcg_tb_remove(TranslationBlock *tb)
|
||||
{
|
||||
struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
|
||||
|
||||
g_assert(rt != NULL);
|
||||
qemu_mutex_lock(&rt->lock);
|
||||
q_tree_remove(rt->tree, &tb->tc);
|
||||
qemu_mutex_unlock(&rt->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the TB 'tb' such that
|
||||
* tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
|
||||
* Return NULL if not found.
|
||||
*/
|
||||
TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
|
||||
{
|
||||
struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
|
||||
TranslationBlock *tb;
|
||||
struct tb_tc s = { .ptr = (void *)tc_ptr };
|
||||
|
||||
if (rt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qemu_mutex_lock(&rt->lock);
|
||||
tb = q_tree_lookup(rt->tree, &s);
|
||||
qemu_mutex_unlock(&rt->lock);
|
||||
return tb;
|
||||
}
|
||||
|
||||
static void tcg_region_tree_lock_all(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < region.n; i++) {
|
||||
struct tcg_region_tree *rt = region_trees + i * tree_size;
|
||||
|
||||
qemu_mutex_lock(&rt->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_region_tree_unlock_all(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < region.n; i++) {
|
||||
struct tcg_region_tree *rt = region_trees + i * tree_size;
|
||||
|
||||
qemu_mutex_unlock(&rt->lock);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
tcg_region_tree_lock_all();
|
||||
for (i = 0; i < region.n; i++) {
|
||||
struct tcg_region_tree *rt = region_trees + i * tree_size;
|
||||
|
||||
q_tree_foreach(rt->tree, func, user_data);
|
||||
}
|
||||
tcg_region_tree_unlock_all();
|
||||
}
|
||||
|
||||
size_t tcg_nb_tbs(void)
|
||||
{
|
||||
size_t nb_tbs = 0;
|
||||
size_t i;
|
||||
|
||||
tcg_region_tree_lock_all();
|
||||
for (i = 0; i < region.n; i++) {
|
||||
struct tcg_region_tree *rt = region_trees + i * tree_size;
|
||||
|
||||
nb_tbs += q_tree_nnodes(rt->tree);
|
||||
}
|
||||
tcg_region_tree_unlock_all();
|
||||
return nb_tbs;
|
||||
}
|
||||
|
||||
static void tcg_region_tree_reset_all(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
tcg_region_tree_lock_all();
|
||||
for (i = 0; i < region.n; i++) {
|
||||
struct tcg_region_tree *rt = region_trees + i * tree_size;
|
||||
|
||||
/* Increment the refcount first so that destroy acts as a reset */
|
||||
q_tree_ref(rt->tree);
|
||||
q_tree_destroy(rt->tree);
|
||||
}
|
||||
tcg_region_tree_unlock_all();
|
||||
}
|
||||
|
||||
static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
|
||||
{
|
||||
void *start, *end;
|
||||
|
||||
start = region.start_aligned + curr_region * region.stride;
|
||||
end = start + region.size;
|
||||
|
||||
if (curr_region == 0) {
|
||||
start = region.after_prologue;
|
||||
}
|
||||
/* The final region may have a few extra pages due to earlier rounding. */
|
||||
if (curr_region == region.n - 1) {
|
||||
end = region.start_aligned + region.total_size;
|
||||
}
|
||||
|
||||
*pstart = start;
|
||||
*pend = end;
|
||||
}
|
||||
|
||||
static void tcg_region_assign(TCGContext *s, size_t curr_region)
|
||||
{
|
||||
void *start, *end;
|
||||
|
||||
tcg_region_bounds(curr_region, &start, &end);
|
||||
|
||||
s->code_gen_buffer = start;
|
||||
s->code_gen_ptr = start;
|
||||
s->code_gen_buffer_size = end - start;
|
||||
s->code_gen_highwater = end - TCG_HIGHWATER;
|
||||
}
|
||||
|
||||
static bool tcg_region_alloc__locked(TCGContext *s)
|
||||
{
|
||||
if (region.current == region.n) {
|
||||
return false;
|
||||
}
|
||||
tcg_region_assign(s, region.current);
|
||||
region.current++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request a new region once the one in use has filled up.
|
||||
* Returns true on success.
|
||||
*/
|
||||
bool tcg_region_alloc(TCGContext *s)
|
||||
{
|
||||
bool ok;
|
||||
/* read the region size now; alloc__locked will overwrite it on success */
|
||||
size_t size_full = s->code_gen_buffer_size;
|
||||
|
||||
qemu_mutex_lock(®ion.lock);
|
||||
ok = tcg_region_alloc__locked(s);
|
||||
if (ok) {
|
||||
region.agg_size_full += size_full - TCG_HIGHWATER;
|
||||
}
|
||||
qemu_mutex_unlock(®ion.lock);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a context's first region allocation.
|
||||
* This function does _not_ increment region.agg_size_full.
|
||||
*/
|
||||
static void tcg_region_initial_alloc__locked(TCGContext *s)
|
||||
{
|
||||
bool ok = tcg_region_alloc__locked(s);
|
||||
g_assert(ok);
|
||||
}
|
||||
|
||||
void tcg_region_thread_initial_alloc(TCGContext *s)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
qemu_mutex_lock(®ion.lock);
|
||||
ok = tcg_region_alloc__locked(s);
|
||||
qemu_mutex_unlock(®ion.lock);
|
||||
|
||||
/*
|
||||
* A vCPU hotplug may happen at any time. When the new thread is
|
||||
* started, the region pool may be exhausted. At this point in
|
||||
* the new thread call stack, we are not in a position to fix this.
|
||||
* Leave code_gen_ptr NULL, so that this thread's first call to
|
||||
* tcg_tb_alloc() returns NULL, so that the translator performs
|
||||
* a tb_flush() and retry.
|
||||
*
|
||||
* During the tb_flush(), tcg_region_reset_all() will assign a
|
||||
* new region to all contexts, including this one.
|
||||
*/
|
||||
if (!ok) {
|
||||
s->code_gen_buffer = NULL;
|
||||
s->code_gen_ptr = NULL;
|
||||
s->code_gen_buffer_size = 0;
|
||||
s->code_gen_highwater = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call from a safe-work context */
|
||||
void tcg_region_reset_all(void)
|
||||
{
|
||||
unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
|
||||
unsigned int i;
|
||||
|
||||
qemu_mutex_lock(®ion.lock);
|
||||
region.current = 0;
|
||||
region.agg_size_full = 0;
|
||||
|
||||
for (i = 0; i < n_ctxs; i++) {
|
||||
TCGContext *s = qatomic_read(&tcg_ctxs[i]);
|
||||
tcg_region_initial_alloc__locked(s);
|
||||
}
|
||||
qemu_mutex_unlock(®ion.lock);
|
||||
|
||||
tcg_region_tree_reset_all();
|
||||
}
|
||||
|
||||
static size_t tcg_n_regions(size_t tb_size, unsigned max_threads)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
return 1;
|
||||
#else
|
||||
size_t n_regions;
|
||||
|
||||
/*
|
||||
* It is likely that some vCPUs will translate more code than others,
|
||||
* so we first try to set more regions than threads, with those regions
|
||||
* being of reasonable size. If that's not possible we make do by evenly
|
||||
* dividing the code_gen_buffer among the vCPUs.
|
||||
*
|
||||
* Use a single region if all we have is one vCPU thread.
|
||||
*/
|
||||
if (max_threads == 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to have more regions than threads, with each region being >= 2 MB.
|
||||
* If we can't, then just allocate one region per vCPU thread.
|
||||
*/
|
||||
n_regions = tb_size / (2 * MiB);
|
||||
if (n_regions <= max_threads) {
|
||||
return max_threads;
|
||||
}
|
||||
return MIN(n_regions, max_threads * 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Minimum size of the code gen buffer. This number is randomly chosen,
|
||||
* but not so small that we can't have a fair number of TB's live.
|
||||
*
|
||||
* Maximum size, MAX_CODE_GEN_BUFFER_SIZE, is defined in tcg-target.h.
|
||||
* Unless otherwise indicated, this is constrained by the range of
|
||||
* direct branches on the host cpu, as used by the TCG implementation
|
||||
* of goto_tb.
|
||||
*/
|
||||
#define MIN_CODE_GEN_BUFFER_SIZE (1 * MiB)
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* As user-mode emulation typically means running multiple instances
|
||||
* of the translator don't go too nuts with our default code gen
|
||||
* buffer lest we make things too hard for the OS.
|
||||
*/
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (128 * MiB)
|
||||
#else
|
||||
/*
|
||||
* We expect most system emulation to run one or two guests per host.
|
||||
* Users running large scale system emulation may want to tweak their
|
||||
* runtime setup via the tb-size control on the command line.
|
||||
*/
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (1 * GiB)
|
||||
#endif
|
||||
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE \
|
||||
(DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \
|
||||
? DEFAULT_CODE_GEN_BUFFER_SIZE_1 : MAX_CODE_GEN_BUFFER_SIZE)
|
||||
|
||||
#ifdef USE_STATIC_CODE_GEN_BUFFER
|
||||
static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
|
||||
__attribute__((aligned(CODE_GEN_ALIGN)));
|
||||
|
||||
static int alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
|
||||
{
|
||||
void *buf, *end;
|
||||
size_t size;
|
||||
|
||||
if (splitwx > 0) {
|
||||
error_setg(errp, "jit split-wx not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* page-align the beginning and end of the buffer */
|
||||
buf = static_code_gen_buffer;
|
||||
end = static_code_gen_buffer + sizeof(static_code_gen_buffer);
|
||||
buf = QEMU_ALIGN_PTR_UP(buf, qemu_real_host_page_size());
|
||||
end = QEMU_ALIGN_PTR_DOWN(end, qemu_real_host_page_size());
|
||||
|
||||
size = end - buf;
|
||||
|
||||
/* Honor a command-line option limiting the size of the buffer. */
|
||||
if (size > tb_size) {
|
||||
size = QEMU_ALIGN_DOWN(tb_size, qemu_real_host_page_size());
|
||||
}
|
||||
|
||||
region.start_aligned = buf;
|
||||
region.total_size = size;
|
||||
|
||||
return PROT_READ | PROT_WRITE;
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
|
||||
{
|
||||
void *buf;
|
||||
|
||||
if (splitwx > 0) {
|
||||
error_setg(errp, "jit split-wx not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
if (buf == NULL) {
|
||||
error_setg_win32(errp, GetLastError(),
|
||||
"allocate %zu bytes for jit buffer", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
region.start_aligned = buf;
|
||||
region.total_size = size;
|
||||
|
||||
return PROT_READ | PROT_WRITE | PROT_EXEC;
|
||||
}
|
||||
#else
|
||||
static int alloc_code_gen_buffer_anon(size_t size, int prot,
|
||||
int flags, Error **errp)
|
||||
{
|
||||
void *buf;
|
||||
|
||||
buf = mmap(NULL, size, prot, flags, -1, 0);
|
||||
if (buf == MAP_FAILED) {
|
||||
error_setg_errno(errp, errno,
|
||||
"allocate %zu bytes for jit buffer", size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
region.start_aligned = buf;
|
||||
region.total_size = size;
|
||||
return prot;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
#ifdef CONFIG_POSIX
|
||||
#include "qemu/memfd.h"
|
||||
|
||||
static int alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
|
||||
{
|
||||
void *buf_rw = NULL, *buf_rx = MAP_FAILED;
|
||||
int fd = -1;
|
||||
|
||||
buf_rw = qemu_memfd_alloc("tcg-jit", size, 0, &fd, errp);
|
||||
if (buf_rw == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
buf_rx = mmap(NULL, size, host_prot_read_exec(), MAP_SHARED, fd, 0);
|
||||
if (buf_rx == MAP_FAILED) {
|
||||
error_setg_errno(errp, errno,
|
||||
"failed to map shared memory for execute");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
region.start_aligned = buf_rw;
|
||||
region.total_size = size;
|
||||
tcg_splitwx_diff = buf_rx - buf_rw;
|
||||
|
||||
return PROT_READ | PROT_WRITE;
|
||||
|
||||
fail:
|
||||
/* buf_rx is always equal to MAP_FAILED here and does not require cleanup */
|
||||
if (buf_rw) {
|
||||
munmap(buf_rw, size);
|
||||
}
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_POSIX */
|
||||
|
||||
#ifdef CONFIG_DARWIN
|
||||
#include <mach/mach.h>
|
||||
|
||||
extern kern_return_t mach_vm_remap(vm_map_t target_task,
|
||||
mach_vm_address_t *target_address,
|
||||
mach_vm_size_t size,
|
||||
mach_vm_offset_t mask,
|
||||
int flags,
|
||||
vm_map_t src_task,
|
||||
mach_vm_address_t src_address,
|
||||
boolean_t copy,
|
||||
vm_prot_t *cur_protection,
|
||||
vm_prot_t *max_protection,
|
||||
vm_inherit_t inheritance);
|
||||
|
||||
static int alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
|
||||
{
|
||||
kern_return_t ret;
|
||||
mach_vm_address_t buf_rw, buf_rx;
|
||||
vm_prot_t cur_prot, max_prot;
|
||||
|
||||
/* Map the read-write portion via normal anon memory. */
|
||||
if (!alloc_code_gen_buffer_anon(size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, errp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf_rw = (mach_vm_address_t)region.start_aligned;
|
||||
buf_rx = 0;
|
||||
ret = mach_vm_remap(mach_task_self(),
|
||||
&buf_rx,
|
||||
size,
|
||||
0,
|
||||
VM_FLAGS_ANYWHERE,
|
||||
mach_task_self(),
|
||||
buf_rw,
|
||||
false,
|
||||
&cur_prot,
|
||||
&max_prot,
|
||||
VM_INHERIT_NONE);
|
||||
if (ret != KERN_SUCCESS) {
|
||||
/* TODO: Convert "ret" to a human readable error message. */
|
||||
error_setg(errp, "vm_remap for jit splitwx failed");
|
||||
munmap((void *)buf_rw, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mprotect((void *)buf_rx, size, host_prot_read_exec()) != 0) {
|
||||
error_setg_errno(errp, errno, "mprotect for jit splitwx");
|
||||
munmap((void *)buf_rx, size);
|
||||
munmap((void *)buf_rw, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tcg_splitwx_diff = buf_rx - buf_rw;
|
||||
return PROT_READ | PROT_WRITE;
|
||||
}
|
||||
#endif /* CONFIG_DARWIN */
|
||||
#endif /* CONFIG_TCG_INTERPRETER */
|
||||
|
||||
static int alloc_code_gen_buffer_splitwx(size_t size, Error **errp)
|
||||
{
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
# ifdef CONFIG_DARWIN
|
||||
return alloc_code_gen_buffer_splitwx_vmremap(size, errp);
|
||||
# endif
|
||||
# ifdef CONFIG_POSIX
|
||||
return alloc_code_gen_buffer_splitwx_memfd(size, errp);
|
||||
# endif
|
||||
#endif
|
||||
error_setg(errp, "jit split-wx not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
int prot, flags;
|
||||
|
||||
if (splitwx) {
|
||||
prot = alloc_code_gen_buffer_splitwx(size, errp);
|
||||
if (prot >= 0) {
|
||||
return prot;
|
||||
}
|
||||
/*
|
||||
* If splitwx force-on (1), fail;
|
||||
* if splitwx default-on (-1), fall through to splitwx off.
|
||||
*/
|
||||
if (splitwx > 0) {
|
||||
return -1;
|
||||
}
|
||||
error_free_or_abort(errp);
|
||||
}
|
||||
|
||||
/*
|
||||
* macOS 11.2 has a bug (Apple Feedback FB8994773) in which mprotect
|
||||
* rejects a permission change from RWX -> NONE when reserving the
|
||||
* guard pages later. We can go the other way with the same number
|
||||
* of syscalls, so always begin with PROT_NONE.
|
||||
*/
|
||||
prot = PROT_NONE;
|
||||
flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
#ifdef CONFIG_DARWIN
|
||||
/* Applicable to both iOS and macOS (Apple Silicon). */
|
||||
if (!splitwx) {
|
||||
flags |= MAP_JIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
return alloc_code_gen_buffer_anon(size, prot, flags, errp);
|
||||
}
|
||||
#endif /* USE_STATIC_CODE_GEN_BUFFER, WIN32, POSIX */
|
||||
|
||||
/*
|
||||
* Initializes region partitioning.
|
||||
*
|
||||
* Called at init time from the parent thread (i.e. the one calling
|
||||
* tcg_context_init), after the target's TCG globals have been set.
|
||||
*
|
||||
* Region partitioning works by splitting code_gen_buffer into separate regions,
|
||||
* and then assigning regions to TCG threads so that the threads can translate
|
||||
* code in parallel without synchronization.
|
||||
*
|
||||
* In system-mode the number of TCG threads is bounded by max_threads,
|
||||
*
|
||||
* In user-mode we use a single region. Having multiple regions in user-mode
|
||||
* is not supported, because the number of vCPU threads (recall that each thread
|
||||
* spawned by the guest corresponds to a vCPU thread) is only bounded by the
|
||||
* OS, and usually this number is huge (tens of thousands is not uncommon).
|
||||
* Thus, given this large bound on the number of vCPU threads and the fact
|
||||
* that code_gen_buffer is allocated at compile-time, we cannot guarantee
|
||||
* that the availability of at least one region per vCPU thread.
|
||||
*
|
||||
* However, this user-mode limitation is unlikely to be a significant problem
|
||||
* in practice. Multi-threaded guests share most if not all of their translated
|
||||
* code, which makes parallel code generation less appealing than in system-mode
|
||||
*/
|
||||
void tcg_region_init(size_t tb_size, int splitwx, unsigned max_threads)
|
||||
{
|
||||
const size_t page_size = qemu_real_host_page_size();
|
||||
size_t region_size;
|
||||
int have_prot, need_prot;
|
||||
|
||||
/* Size the buffer. */
|
||||
if (tb_size == 0) {
|
||||
size_t phys_mem = qemu_get_host_physmem();
|
||||
if (phys_mem == 0) {
|
||||
tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
|
||||
} else {
|
||||
tb_size = QEMU_ALIGN_DOWN(phys_mem / 8, page_size);
|
||||
tb_size = MIN(DEFAULT_CODE_GEN_BUFFER_SIZE, tb_size);
|
||||
}
|
||||
}
|
||||
if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) {
|
||||
tb_size = MIN_CODE_GEN_BUFFER_SIZE;
|
||||
}
|
||||
if (tb_size > MAX_CODE_GEN_BUFFER_SIZE) {
|
||||
tb_size = MAX_CODE_GEN_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
have_prot = alloc_code_gen_buffer(tb_size, splitwx, &error_fatal);
|
||||
assert(have_prot >= 0);
|
||||
|
||||
/* Request large pages for the buffer and the splitwx. */
|
||||
qemu_madvise(region.start_aligned, region.total_size, QEMU_MADV_HUGEPAGE);
|
||||
if (tcg_splitwx_diff) {
|
||||
qemu_madvise(region.start_aligned + tcg_splitwx_diff,
|
||||
region.total_size, QEMU_MADV_HUGEPAGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make region_size a multiple of page_size, using aligned as the start.
|
||||
* As a result of this we might end up with a few extra pages at the end of
|
||||
* the buffer; we will assign those to the last region.
|
||||
*/
|
||||
region.n = tcg_n_regions(tb_size, max_threads);
|
||||
region_size = tb_size / region.n;
|
||||
region_size = QEMU_ALIGN_DOWN(region_size, page_size);
|
||||
|
||||
/* A region must have at least 2 pages; one code, one guard */
|
||||
g_assert(region_size >= 2 * page_size);
|
||||
region.stride = region_size;
|
||||
|
||||
/* Reserve space for guard pages. */
|
||||
region.size = region_size - page_size;
|
||||
region.total_size -= page_size;
|
||||
|
||||
/*
|
||||
* The first region will be smaller than the others, via the prologue,
|
||||
* which has yet to be allocated. For now, the first region begins at
|
||||
* the page boundary.
|
||||
*/
|
||||
region.after_prologue = region.start_aligned;
|
||||
|
||||
/* init the region struct */
|
||||
qemu_mutex_init(®ion.lock);
|
||||
|
||||
/*
|
||||
* Set guard pages in the rw buffer, as that's the one into which
|
||||
* buffer overruns could occur. Do not set guard pages in the rx
|
||||
* buffer -- let that one use hugepages throughout.
|
||||
* Work with the page protections set up with the initial mapping.
|
||||
*/
|
||||
need_prot = PROT_READ | PROT_WRITE;
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
if (tcg_splitwx_diff == 0) {
|
||||
need_prot |= host_prot_read_exec();
|
||||
}
|
||||
#endif
|
||||
for (size_t i = 0, n = region.n; i < n; i++) {
|
||||
void *start, *end;
|
||||
|
||||
tcg_region_bounds(i, &start, &end);
|
||||
if (have_prot != need_prot) {
|
||||
int rc;
|
||||
|
||||
if (need_prot == (PROT_READ | PROT_WRITE | PROT_EXEC)) {
|
||||
rc = qemu_mprotect_rwx(start, end - start);
|
||||
} else if (need_prot == (PROT_READ | PROT_WRITE)) {
|
||||
rc = qemu_mprotect_rw(start, end - start);
|
||||
} else {
|
||||
#ifdef CONFIG_POSIX
|
||||
rc = mprotect(start, end - start, need_prot);
|
||||
if (rc) {
|
||||
error_report("mprotect of jit buffer: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
#else
|
||||
g_assert_not_reached();
|
||||
#endif
|
||||
}
|
||||
if (rc) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (have_prot != 0) {
|
||||
/* Guard pages are nice for bug detection but are not essential. */
|
||||
(void)qemu_mprotect_none(end, page_size);
|
||||
}
|
||||
}
|
||||
|
||||
tcg_region_trees_init();
|
||||
|
||||
/*
|
||||
* Leave the initial context initialized to the first region.
|
||||
* This will be the context into which we generate the prologue.
|
||||
* It is also the only context for CONFIG_USER_ONLY.
|
||||
*/
|
||||
tcg_region_initial_alloc__locked(&tcg_init_ctx);
|
||||
}
|
||||
|
||||
void tcg_region_prologue_set(TCGContext *s)
|
||||
{
|
||||
/* Deduct the prologue from the first region. */
|
||||
g_assert(region.start_aligned == s->code_gen_buffer);
|
||||
region.after_prologue = s->code_ptr;
|
||||
|
||||
/* Recompute boundaries of the first region. */
|
||||
tcg_region_assign(s, 0);
|
||||
|
||||
/* Register the balance of the buffer with gdb. */
|
||||
tcg_register_jit(tcg_splitwx_to_rx(region.after_prologue),
|
||||
region.start_aligned + region.total_size -
|
||||
region.after_prologue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the size (in bytes) of all translated code (i.e. from all regions)
|
||||
* currently in the cache.
|
||||
* See also: tcg_code_capacity()
|
||||
* Do not confuse with tcg_current_code_size(); that one applies to a single
|
||||
* TCG context.
|
||||
*/
|
||||
size_t tcg_code_size(void)
|
||||
{
|
||||
unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
|
||||
unsigned int i;
|
||||
size_t total;
|
||||
|
||||
qemu_mutex_lock(®ion.lock);
|
||||
total = region.agg_size_full;
|
||||
for (i = 0; i < n_ctxs; i++) {
|
||||
const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
|
||||
size_t size;
|
||||
|
||||
size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
|
||||
g_assert(size <= s->code_gen_buffer_size);
|
||||
total += size;
|
||||
}
|
||||
qemu_mutex_unlock(®ion.lock);
|
||||
return total;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the code capacity (in bytes) of the entire cache, i.e. including all
|
||||
* regions.
|
||||
* See also: tcg_code_size()
|
||||
*/
|
||||
size_t tcg_code_capacity(void)
|
||||
{
|
||||
size_t guard_size, capacity;
|
||||
|
||||
/* no need for synchronization; these variables are set at init time */
|
||||
guard_size = region.stride - region.size;
|
||||
capacity = region.total_size;
|
||||
capacity -= (region.n - 1) * guard_size;
|
||||
capacity -= region.n * TCG_HIGHWATER;
|
||||
|
||||
return capacity;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define RISC-V target-specific constraint sets.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs.
|
||||
* Each operand should be a sequence of constraint letters as defined by
|
||||
* tcg-target-con-str.h; the constraint combination is inclusive or.
|
||||
*/
|
||||
C_O0_I1(r)
|
||||
C_O0_I2(rz, r)
|
||||
C_O0_I2(r, rz)
|
||||
C_O1_I1(r, r)
|
||||
C_O1_I2(r, r, r)
|
||||
C_O1_I2(r, r, ri)
|
||||
C_O1_I2(r, r, rI)
|
||||
C_N1_I2(r, r, rM)
|
||||
C_O1_I4(r, r, rI, rM, rM)
|
||||
C_O0_I2(v, r)
|
||||
C_O1_I1(v, r)
|
||||
C_O1_I1(v, v)
|
||||
C_O1_I2(v, v, r)
|
||||
C_O1_I2(v, v, v)
|
||||
C_O1_I2(v, vK, v)
|
||||
C_O1_I2(v, v, vK)
|
||||
C_O1_I2(v, v, vL)
|
||||
C_O1_I4(v, v, vL, vK, vK)
|
||||
@@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define RISC-V target-specific operand constraints.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define constraint letters for register sets:
|
||||
* REGS(letter, register_mask)
|
||||
*/
|
||||
REGS('r', ALL_GENERAL_REGS)
|
||||
REGS('v', ALL_VECTOR_REGS)
|
||||
|
||||
/*
|
||||
* Define constraint letters for constants:
|
||||
* CONST(letter, TCG_CT_CONST_* bit set)
|
||||
*/
|
||||
CONST('I', TCG_CT_CONST_S12)
|
||||
CONST('K', TCG_CT_CONST_S5)
|
||||
CONST('L', TCG_CT_CONST_CMP_VI)
|
||||
CONST('M', TCG_CT_CONST_M12)
|
||||
@@ -0,0 +1,72 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific opcode support
|
||||
* Copyright (c) 2018 SiFive, Inc
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_HAS_H
|
||||
#define TCG_TARGET_HAS_H
|
||||
|
||||
#include "host/cpuinfo.h"
|
||||
|
||||
/* optional instructions */
|
||||
#define TCG_TARGET_HAS_extr_i64_i32 1
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
#define TCG_TARGET_HAS_tst 0
|
||||
|
||||
/* vector instructions */
|
||||
#define TCG_TARGET_HAS_v64 (cpuinfo & CPUINFO_ZVE64X)
|
||||
#define TCG_TARGET_HAS_v128 (cpuinfo & CPUINFO_ZVE64X)
|
||||
#define TCG_TARGET_HAS_v256 (cpuinfo & CPUINFO_ZVE64X)
|
||||
#define TCG_TARGET_HAS_andc_vec 0
|
||||
#define TCG_TARGET_HAS_orc_vec 0
|
||||
#define TCG_TARGET_HAS_nand_vec 0
|
||||
#define TCG_TARGET_HAS_nor_vec 0
|
||||
#define TCG_TARGET_HAS_eqv_vec 0
|
||||
#define TCG_TARGET_HAS_not_vec 1
|
||||
#define TCG_TARGET_HAS_neg_vec 1
|
||||
#define TCG_TARGET_HAS_abs_vec 0
|
||||
#define TCG_TARGET_HAS_roti_vec 1
|
||||
#define TCG_TARGET_HAS_rots_vec 1
|
||||
#define TCG_TARGET_HAS_rotv_vec 1
|
||||
#define TCG_TARGET_HAS_shi_vec 1
|
||||
#define TCG_TARGET_HAS_shs_vec 1
|
||||
#define TCG_TARGET_HAS_shv_vec 1
|
||||
#define TCG_TARGET_HAS_mul_vec 1
|
||||
#define TCG_TARGET_HAS_sat_vec 1
|
||||
#define TCG_TARGET_HAS_minmax_vec 1
|
||||
#define TCG_TARGET_HAS_bitsel_vec 0
|
||||
#define TCG_TARGET_HAS_cmpsel_vec 1
|
||||
|
||||
#define TCG_TARGET_HAS_tst_vec 0
|
||||
|
||||
static inline bool
|
||||
tcg_target_extract_valid(TCGType type, unsigned ofs, unsigned len)
|
||||
{
|
||||
if (type == TCG_TYPE_I64 && ofs + len == 32) {
|
||||
/* ofs > 0 uses SRLIW; ofs == 0 uses add.uw. */
|
||||
return ofs || (cpuinfo & CPUINFO_ZBA);
|
||||
}
|
||||
switch (len) {
|
||||
case 1:
|
||||
return (cpuinfo & CPUINFO_ZBS) && ofs != 0;
|
||||
case 16:
|
||||
return (cpuinfo & CPUINFO_ZBB) && ofs == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#define TCG_TARGET_extract_valid tcg_target_extract_valid
|
||||
|
||||
static inline bool
|
||||
tcg_target_sextract_valid(TCGType type, unsigned ofs, unsigned len)
|
||||
{
|
||||
if (type == TCG_TYPE_I64 && ofs + len == 32) {
|
||||
return true;
|
||||
}
|
||||
return (cpuinfo & CPUINFO_ZBB) && ofs == 0 && (len == 8 || len == 16);
|
||||
}
|
||||
#define TCG_TARGET_sextract_valid tcg_target_sextract_valid
|
||||
|
||||
#define TCG_TARGET_deposit_valid(type, ofs, len) 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific memory model
|
||||
* Copyright (c) 2018 SiFive, Inc
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_MO_H
|
||||
#define TCG_TARGET_MO_H
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) C-SKY Microsystems Co., Ltd.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* See the COPYING file in the top-level directory for details.
|
||||
*
|
||||
* Target-specific opcodes for host vector expansion. These will be
|
||||
* emitted by tcg_expand_vec_op. For those familiar with GCC internals,
|
||||
* consider these to be UNSPEC with names.
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2018 SiFive, Inc
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RISCV_TCG_TARGET_H
|
||||
#define RISCV_TCG_TARGET_H
|
||||
|
||||
#define TCG_TARGET_INSN_UNIT_SIZE 4
|
||||
#define TCG_TARGET_NB_REGS 64
|
||||
#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
|
||||
|
||||
typedef enum {
|
||||
TCG_REG_ZERO, TCG_REG_RA, TCG_REG_SP, TCG_REG_GP,
|
||||
TCG_REG_TP, TCG_REG_T0, TCG_REG_T1, TCG_REG_T2,
|
||||
TCG_REG_S0, TCG_REG_S1, TCG_REG_A0, TCG_REG_A1,
|
||||
TCG_REG_A2, TCG_REG_A3, TCG_REG_A4, TCG_REG_A5,
|
||||
TCG_REG_A6, TCG_REG_A7, TCG_REG_S2, TCG_REG_S3,
|
||||
TCG_REG_S4, TCG_REG_S5, TCG_REG_S6, TCG_REG_S7,
|
||||
TCG_REG_S8, TCG_REG_S9, TCG_REG_S10, TCG_REG_S11,
|
||||
TCG_REG_T3, TCG_REG_T4, TCG_REG_T5, TCG_REG_T6,
|
||||
|
||||
/* RISC-V V Extension registers */
|
||||
TCG_REG_V0, TCG_REG_V1, TCG_REG_V2, 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,
|
||||
TCG_REG_V20, TCG_REG_V21, TCG_REG_V22, TCG_REG_V23,
|
||||
TCG_REG_V24, TCG_REG_V25, TCG_REG_V26, TCG_REG_V27,
|
||||
TCG_REG_V28, TCG_REG_V29, TCG_REG_V30, TCG_REG_V31,
|
||||
|
||||
/* aliases */
|
||||
TCG_AREG0 = TCG_REG_S0,
|
||||
TCG_GUEST_BASE_REG = TCG_REG_S1,
|
||||
TCG_REG_TMP0 = TCG_REG_T6,
|
||||
TCG_REG_TMP1 = TCG_REG_T5,
|
||||
TCG_REG_TMP2 = TCG_REG_T4,
|
||||
} TCGReg;
|
||||
|
||||
#define TCG_REG_ZERO TCG_REG_ZERO
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define S390 target-specific constraint sets.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs.
|
||||
* Each operand should be a sequence of constraint letters as defined by
|
||||
* tcg-target-con-str.h; the constraint combination is inclusive or.
|
||||
*
|
||||
* C_Nn_Om_Ik(...) defines a constraint set with <n + m> outputs and <k>
|
||||
* inputs, except that the first <n> outputs must use new registers.
|
||||
*/
|
||||
C_O0_I1(r)
|
||||
C_O0_I2(r, r)
|
||||
C_O0_I2(r, ri)
|
||||
C_O0_I2(r, rC)
|
||||
C_O0_I2(v, r)
|
||||
C_O0_I3(o, m, r)
|
||||
C_O1_I1(r, r)
|
||||
C_O1_I1(v, r)
|
||||
C_O1_I1(v, v)
|
||||
C_O1_I1(v, vr)
|
||||
C_O1_I2(r, 0, r)
|
||||
C_O1_I2(r, 0, ri)
|
||||
C_O1_I2(r, 0, rI)
|
||||
C_O1_I2(r, 0, rJ)
|
||||
C_O1_I2(r, r, r)
|
||||
C_O1_I2(r, r, ri)
|
||||
C_O1_I2(r, r, rC)
|
||||
C_O1_I2(r, r, rI)
|
||||
C_O1_I2(r, r, rJ)
|
||||
C_O1_I2(r, r, rK)
|
||||
C_O1_I2(r, r, rNKR)
|
||||
C_O1_I2(r, r, rUV)
|
||||
C_O1_I2(r, rZ, r)
|
||||
C_O1_I2(v, v, r)
|
||||
C_O1_I2(v, v, v)
|
||||
C_O1_I3(v, v, v, v)
|
||||
C_O1_I4(v, v, v, vZ, v)
|
||||
C_O1_I4(v, v, v, vZM, v)
|
||||
C_O1_I4(r, r, rC, rI, r)
|
||||
C_O2_I1(o, m, r)
|
||||
C_O2_I2(o, m, 0, r)
|
||||
C_O2_I2(o, m, r, r)
|
||||
C_O2_I3(o, m, 0, 1, r)
|
||||
@@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define S390 target-specific operand constraints.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define constraint letters for register sets:
|
||||
* REGS(letter, register_mask)
|
||||
*/
|
||||
REGS('r', ALL_GENERAL_REGS)
|
||||
REGS('v', ALL_VECTOR_REGS)
|
||||
REGS('o', 0xaaaa) /* odd numbered general regs */
|
||||
|
||||
/*
|
||||
* Define constraint letters for constants:
|
||||
* CONST(letter, TCG_CT_CONST_* bit set)
|
||||
*/
|
||||
CONST('C', TCG_CT_CONST_CMP)
|
||||
CONST('I', TCG_CT_CONST_S16)
|
||||
CONST('J', TCG_CT_CONST_S32)
|
||||
CONST('K', TCG_CT_CONST_P32)
|
||||
CONST('M', TCG_CT_CONST_M1)
|
||||
CONST('N', TCG_CT_CONST_INV)
|
||||
CONST('R', TCG_CT_CONST_INVRISBG)
|
||||
CONST('U', TCG_CT_CONST_U32)
|
||||
CONST('V', TCG_CT_CONST_N32)
|
||||
CONST('Z', TCG_CT_CONST_ZERO)
|
||||
@@ -0,0 +1,80 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific opcode support
|
||||
* Copyright (c) 2009 Ulrich Hecht <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_HAS_H
|
||||
#define TCG_TARGET_HAS_H
|
||||
|
||||
/* Facilities required for proper operation; checked at startup. */
|
||||
|
||||
#define FACILITY_ZARCH_ACTIVE 2
|
||||
#define FACILITY_LONG_DISP 18
|
||||
#define FACILITY_EXT_IMM 21
|
||||
#define FACILITY_GEN_INST_EXT 34
|
||||
#define FACILITY_45 45
|
||||
|
||||
/* Facilities that are checked at runtime. */
|
||||
|
||||
#define FACILITY_LOAD_ON_COND2 53
|
||||
#define FACILITY_MISC_INSN_EXT2 58
|
||||
#define FACILITY_MISC_INSN_EXT3 61
|
||||
#define FACILITY_VECTOR 129
|
||||
#define FACILITY_VECTOR_ENH1 135
|
||||
|
||||
extern uint64_t s390_facilities[3];
|
||||
|
||||
#define HAVE_FACILITY(X) \
|
||||
((s390_facilities[FACILITY_##X / 64] >> (63 - FACILITY_##X % 64)) & 1)
|
||||
|
||||
/* optional instructions */
|
||||
#define TCG_TARGET_HAS_extr_i64_i32 0
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 1
|
||||
#define TCG_TARGET_HAS_tst 1
|
||||
|
||||
#define TCG_TARGET_HAS_v64 HAVE_FACILITY(VECTOR)
|
||||
#define TCG_TARGET_HAS_v128 HAVE_FACILITY(VECTOR)
|
||||
#define TCG_TARGET_HAS_v256 0
|
||||
|
||||
#define TCG_TARGET_HAS_andc_vec 1
|
||||
#define TCG_TARGET_HAS_orc_vec HAVE_FACILITY(VECTOR_ENH1)
|
||||
#define TCG_TARGET_HAS_nand_vec HAVE_FACILITY(VECTOR_ENH1)
|
||||
#define TCG_TARGET_HAS_nor_vec 1
|
||||
#define TCG_TARGET_HAS_eqv_vec HAVE_FACILITY(VECTOR_ENH1)
|
||||
#define TCG_TARGET_HAS_not_vec 1
|
||||
#define TCG_TARGET_HAS_neg_vec 1
|
||||
#define TCG_TARGET_HAS_abs_vec 1
|
||||
#define TCG_TARGET_HAS_roti_vec 1
|
||||
#define TCG_TARGET_HAS_rots_vec 1
|
||||
#define TCG_TARGET_HAS_rotv_vec 1
|
||||
#define TCG_TARGET_HAS_shi_vec 1
|
||||
#define TCG_TARGET_HAS_shs_vec 1
|
||||
#define TCG_TARGET_HAS_shv_vec 1
|
||||
#define TCG_TARGET_HAS_mul_vec 1
|
||||
#define TCG_TARGET_HAS_sat_vec 0
|
||||
#define TCG_TARGET_HAS_minmax_vec 1
|
||||
#define TCG_TARGET_HAS_bitsel_vec 1
|
||||
#define TCG_TARGET_HAS_cmpsel_vec 1
|
||||
#define TCG_TARGET_HAS_tst_vec 0
|
||||
|
||||
#define TCG_TARGET_extract_valid(type, ofs, len) 1
|
||||
#define TCG_TARGET_deposit_valid(type, ofs, len) 1
|
||||
|
||||
static inline bool
|
||||
tcg_target_sextract_valid(TCGType type, unsigned ofs, unsigned len)
|
||||
{
|
||||
if (ofs == 0) {
|
||||
switch (len) {
|
||||
case 8:
|
||||
case 16:
|
||||
return true;
|
||||
case 32:
|
||||
return type == TCG_TYPE_I64;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#define TCG_TARGET_sextract_valid tcg_target_sextract_valid
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific memory model
|
||||
* Copyright (c) 2009 Ulrich Hecht <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_MO_H
|
||||
#define TCG_TARGET_MO_H
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Linaro
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* See the COPYING file in the top-level directory for details.
|
||||
*
|
||||
* Target-specific opcodes for host vector expansion. These will be
|
||||
* emitted by tcg_expand_vec_op. For those familiar with GCC internals,
|
||||
* consider these to be UNSPEC with names.
|
||||
*/
|
||||
DEF(s390_vuph_vec, 1, 1, 0, TCG_OPF_VECTOR)
|
||||
DEF(s390_vupl_vec, 1, 1, 0, TCG_OPF_VECTOR)
|
||||
DEF(s390_vpks_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2009 Ulrich Hecht <[email protected]>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef S390_TCG_TARGET_H
|
||||
#define S390_TCG_TARGET_H
|
||||
|
||||
#define TCG_TARGET_INSN_UNIT_SIZE 2
|
||||
|
||||
/* We have a +- 4GB range on the branches; leave some slop. */
|
||||
#define MAX_CODE_GEN_BUFFER_SIZE (3 * GiB)
|
||||
|
||||
typedef enum TCGReg {
|
||||
TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3,
|
||||
TCG_REG_R4, TCG_REG_R5, TCG_REG_R6, TCG_REG_R7,
|
||||
TCG_REG_R8, TCG_REG_R9, TCG_REG_R10, TCG_REG_R11,
|
||||
TCG_REG_R12, TCG_REG_R13, TCG_REG_R14, TCG_REG_R15,
|
||||
|
||||
TCG_REG_V0 = 32, TCG_REG_V1, TCG_REG_V2, 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,
|
||||
TCG_REG_V20, TCG_REG_V21, TCG_REG_V22, TCG_REG_V23,
|
||||
TCG_REG_V24, TCG_REG_V25, TCG_REG_V26, TCG_REG_V27,
|
||||
TCG_REG_V28, TCG_REG_V29, TCG_REG_V30, TCG_REG_V31,
|
||||
|
||||
TCG_AREG0 = TCG_REG_R10,
|
||||
TCG_REG_CALL_STACK = TCG_REG_R15
|
||||
} TCGReg;
|
||||
|
||||
#define TCG_TARGET_NB_REGS 64
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define Sparc target-specific constraint sets.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs.
|
||||
* Each operand should be a sequence of constraint letters as defined by
|
||||
* tcg-target-con-str.h; the constraint combination is inclusive or.
|
||||
*/
|
||||
C_O0_I1(r)
|
||||
C_O0_I2(rz, r)
|
||||
C_O0_I2(r, rJ)
|
||||
C_O1_I1(r, r)
|
||||
C_O1_I2(r, r, r)
|
||||
C_O1_I2(r, r, rJ)
|
||||
C_O1_I2(r, rz, rJ)
|
||||
C_O1_I2(r, rz, rz)
|
||||
C_O1_I4(r, r, rJ, rI, 0)
|
||||
C_O2_I2(r, r, r, r)
|
||||
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define Sparc target-specific operand constraints.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define constraint letters for register sets:
|
||||
* REGS(letter, register_mask)
|
||||
*/
|
||||
REGS('r', ALL_GENERAL_REGS)
|
||||
|
||||
/*
|
||||
* Define constraint letters for constants:
|
||||
* CONST(letter, TCG_CT_CONST_* bit set)
|
||||
*/
|
||||
CONST('I', TCG_CT_CONST_S11)
|
||||
CONST('J', TCG_CT_CONST_S13)
|
||||
@@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific opcode support
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_HAS_H
|
||||
#define TCG_TARGET_HAS_H
|
||||
|
||||
/* optional instructions */
|
||||
#define TCG_TARGET_HAS_extr_i64_i32 0
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
#define TCG_TARGET_HAS_tst 1
|
||||
|
||||
#define TCG_TARGET_extract_valid(type, ofs, len) \
|
||||
((type) == TCG_TYPE_I64 && (ofs) + (len) == 32)
|
||||
|
||||
#define TCG_TARGET_sextract_valid TCG_TARGET_extract_valid
|
||||
|
||||
#define TCG_TARGET_deposit_valid(type, ofs, len) 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific memory model
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_MO_H
|
||||
#define TCG_TARGET_MO_H
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
/* No target specific opcodes. */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SPARC_TCG_TARGET_H
|
||||
#define SPARC_TCG_TARGET_H
|
||||
|
||||
#define TCG_TARGET_INSN_UNIT_SIZE 4
|
||||
#define TCG_TARGET_NB_REGS 32
|
||||
#define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
|
||||
typedef enum {
|
||||
TCG_REG_G0 = 0,
|
||||
TCG_REG_G1,
|
||||
TCG_REG_G2,
|
||||
TCG_REG_G3,
|
||||
TCG_REG_G4,
|
||||
TCG_REG_G5,
|
||||
TCG_REG_G6,
|
||||
TCG_REG_G7,
|
||||
TCG_REG_O0,
|
||||
TCG_REG_O1,
|
||||
TCG_REG_O2,
|
||||
TCG_REG_O3,
|
||||
TCG_REG_O4,
|
||||
TCG_REG_O5,
|
||||
TCG_REG_O6,
|
||||
TCG_REG_O7,
|
||||
TCG_REG_L0,
|
||||
TCG_REG_L1,
|
||||
TCG_REG_L2,
|
||||
TCG_REG_L3,
|
||||
TCG_REG_L4,
|
||||
TCG_REG_L5,
|
||||
TCG_REG_L6,
|
||||
TCG_REG_L7,
|
||||
TCG_REG_I0,
|
||||
TCG_REG_I1,
|
||||
TCG_REG_I2,
|
||||
TCG_REG_I3,
|
||||
TCG_REG_I4,
|
||||
TCG_REG_I5,
|
||||
TCG_REG_I6,
|
||||
TCG_REG_I7,
|
||||
} TCGReg;
|
||||
|
||||
#define TCG_AREG0 TCG_REG_I0
|
||||
#define TCG_REG_ZERO TCG_REG_G0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg-has.h"
|
||||
|
||||
const TCGOpDef tcg_op_defs[] = {
|
||||
#define DEF(s, oargs, iargs, cargs, flags) \
|
||||
{ #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
|
||||
#include "tcg/tcg-opc.h"
|
||||
#undef DEF
|
||||
};
|
||||
const size_t tcg_op_defs_max = ARRAY_SIZE(tcg_op_defs);
|
||||
@@ -0,0 +1,49 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific opcode support
|
||||
* Copyright (c) 2024 Linaro, Ltd.
|
||||
*/
|
||||
|
||||
#ifndef TCG_HAS_H
|
||||
#define TCG_HAS_H
|
||||
|
||||
#include "tcg-target-has.h"
|
||||
|
||||
#if !defined(TCG_TARGET_HAS_v64) \
|
||||
&& !defined(TCG_TARGET_HAS_v128) \
|
||||
&& !defined(TCG_TARGET_HAS_v256)
|
||||
#define TCG_TARGET_MAYBE_vec 0
|
||||
#define TCG_TARGET_HAS_abs_vec 0
|
||||
#define TCG_TARGET_HAS_neg_vec 0
|
||||
#define TCG_TARGET_HAS_not_vec 0
|
||||
#define TCG_TARGET_HAS_andc_vec 0
|
||||
#define TCG_TARGET_HAS_orc_vec 0
|
||||
#define TCG_TARGET_HAS_nand_vec 0
|
||||
#define TCG_TARGET_HAS_nor_vec 0
|
||||
#define TCG_TARGET_HAS_eqv_vec 0
|
||||
#define TCG_TARGET_HAS_roti_vec 0
|
||||
#define TCG_TARGET_HAS_rots_vec 0
|
||||
#define TCG_TARGET_HAS_rotv_vec 0
|
||||
#define TCG_TARGET_HAS_shi_vec 0
|
||||
#define TCG_TARGET_HAS_shs_vec 0
|
||||
#define TCG_TARGET_HAS_shv_vec 0
|
||||
#define TCG_TARGET_HAS_mul_vec 0
|
||||
#define TCG_TARGET_HAS_sat_vec 0
|
||||
#define TCG_TARGET_HAS_minmax_vec 0
|
||||
#define TCG_TARGET_HAS_bitsel_vec 0
|
||||
#define TCG_TARGET_HAS_cmpsel_vec 0
|
||||
#define TCG_TARGET_HAS_tst_vec 0
|
||||
#else
|
||||
#define TCG_TARGET_MAYBE_vec 1
|
||||
#endif
|
||||
#ifndef TCG_TARGET_HAS_v64
|
||||
#define TCG_TARGET_HAS_v64 0
|
||||
#endif
|
||||
#ifndef TCG_TARGET_HAS_v128
|
||||
#define TCG_TARGET_HAS_v128 0
|
||||
#endif
|
||||
#ifndef TCG_TARGET_HAS_v256
|
||||
#define TCG_TARGET_HAS_v256 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Internal declarations for 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.
|
||||
*/
|
||||
|
||||
#ifndef TCG_INTERNAL_H
|
||||
#define TCG_INTERNAL_H
|
||||
|
||||
#include "tcg/helper-info.h"
|
||||
|
||||
#define TCG_HIGHWATER 1024
|
||||
|
||||
extern TCGContext tcg_init_ctx;
|
||||
extern TCGContext **tcg_ctxs;
|
||||
extern unsigned int tcg_cur_ctxs;
|
||||
extern unsigned int tcg_max_ctxs;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#define tcg_use_softmmu false
|
||||
#else
|
||||
#define tcg_use_softmmu true
|
||||
#endif
|
||||
|
||||
void tcg_region_init(size_t tb_size, int splitwx, unsigned max_threads);
|
||||
bool tcg_region_alloc(TCGContext *s);
|
||||
void tcg_region_thread_initial_alloc(TCGContext *s);
|
||||
void tcg_region_prologue_set(TCGContext *s);
|
||||
|
||||
static inline void *tcg_call_func(TCGOp *op)
|
||||
{
|
||||
return (void *)(uintptr_t)op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op)];
|
||||
}
|
||||
|
||||
static inline const TCGHelperInfo *tcg_call_info(TCGOp *op)
|
||||
{
|
||||
return (void *)(uintptr_t)op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
|
||||
}
|
||||
|
||||
static inline unsigned tcg_call_flags(TCGOp *op)
|
||||
{
|
||||
return tcg_call_info(op)->flags;
|
||||
}
|
||||
|
||||
static inline TCGv_i64 TCGV128_LOW(TCGv_i128 t)
|
||||
{
|
||||
return temp_tcgv_i64(tcgv_i128_temp(t) + HOST_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
static inline TCGv_i64 TCGV128_HIGH(TCGv_i128 t)
|
||||
{
|
||||
return temp_tcgv_i64(tcgv_i128_temp(t) + !HOST_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
bool tcg_target_has_memory_bswap(MemOp memop);
|
||||
|
||||
TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind);
|
||||
|
||||
/*
|
||||
* Locate or create a read-only temporary that is a constant.
|
||||
* This kind of temporary need not be freed, but for convenience
|
||||
* will be silently ignored by tcg_temp_free_*.
|
||||
*/
|
||||
TCGTemp *tcg_constant_internal(TCGType type, int64_t val);
|
||||
|
||||
TCGOp *tcg_gen_op1(TCGOpcode, TCGType, TCGArg);
|
||||
TCGOp *tcg_gen_op2(TCGOpcode, TCGType, TCGArg, TCGArg);
|
||||
TCGOp *tcg_gen_op3(TCGOpcode, TCGType, TCGArg, TCGArg, TCGArg);
|
||||
TCGOp *tcg_gen_op4(TCGOpcode, TCGType, TCGArg, TCGArg, TCGArg, TCGArg);
|
||||
TCGOp *tcg_gen_op5(TCGOpcode, TCGType, TCGArg, TCGArg, TCGArg, TCGArg, TCGArg);
|
||||
TCGOp *tcg_gen_op6(TCGOpcode, TCGType, TCGArg, TCGArg,
|
||||
TCGArg, TCGArg, TCGArg, TCGArg);
|
||||
|
||||
void vec_gen_2(TCGOpcode, TCGType, unsigned, TCGArg, TCGArg);
|
||||
void vec_gen_3(TCGOpcode, TCGType, unsigned, TCGArg, TCGArg, TCGArg);
|
||||
void vec_gen_4(TCGOpcode, TCGType, unsigned, TCGArg, TCGArg, TCGArg, TCGArg);
|
||||
void vec_gen_6(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r,
|
||||
TCGArg a, TCGArg b, TCGArg c, TCGArg d, TCGArg e);
|
||||
|
||||
TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *op,
|
||||
TCGOpcode, TCGType, unsigned nargs);
|
||||
TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op,
|
||||
TCGOpcode, TCGType, unsigned nargs);
|
||||
|
||||
/*
|
||||
* For a binary opcode OP, return true if the second input operand allows IMM.
|
||||
*/
|
||||
bool tcg_op_imm_match(TCGOpcode op, TCGType type, tcg_target_ulong imm);
|
||||
|
||||
#endif /* TCG_INTERNAL_H */
|
||||
+4090
File diff suppressed because it is too large
Load Diff
+1348
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,795 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2018 Linaro, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg/tcg-temp-internal.h"
|
||||
#include "tcg/tcg-op-common.h"
|
||||
#include "tcg/tcg-mo.h"
|
||||
#include "tcg-internal.h"
|
||||
#include "tcg-has.h"
|
||||
|
||||
/*
|
||||
* Vector optional opcode tracking.
|
||||
* Except for the basic logical operations (and, or, xor), and
|
||||
* data movement (mov, ld, st, dupi), many vector opcodes are
|
||||
* optional and may not be supported on the host. Thank Intel
|
||||
* for the irregularity in their instruction set.
|
||||
*
|
||||
* The gvec expanders allow custom vector operations to be composed,
|
||||
* generally via the .fniv callback in the GVecGen* structures. At
|
||||
* the same time, in deciding whether to use this hook we need to
|
||||
* know if the host supports the required operations. This is
|
||||
* presented as an array of opcodes, terminated by 0. Each opcode
|
||||
* is assumed to be expanded with the given VECE.
|
||||
*
|
||||
* For debugging, we want to validate this array. Therefore, when
|
||||
* tcg_ctx->vec_opt_opc is non-NULL, the tcg_gen_*_vec expanders
|
||||
* will validate that their opcode is present in the list.
|
||||
*/
|
||||
static void tcg_assert_listed_vecop(TCGOpcode op)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_TCG
|
||||
const TCGOpcode *p = tcg_ctx->vecop_list;
|
||||
if (p) {
|
||||
for (; *p; ++p) {
|
||||
if (*p == op) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
g_assert_not_reached();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool tcg_can_emit_vecop_list(const TCGOpcode *list,
|
||||
TCGType type, unsigned vece)
|
||||
{
|
||||
if (list == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (; *list; ++list) {
|
||||
TCGOpcode opc = *list;
|
||||
|
||||
#ifdef CONFIG_DEBUG_TCG
|
||||
switch (opc) {
|
||||
case INDEX_op_and_vec:
|
||||
case INDEX_op_or_vec:
|
||||
case INDEX_op_xor_vec:
|
||||
case INDEX_op_mov_vec:
|
||||
case INDEX_op_dup_vec:
|
||||
case INDEX_op_ld_vec:
|
||||
case INDEX_op_st_vec:
|
||||
case INDEX_op_bitsel_vec:
|
||||
/* These opcodes are mandatory and should not be listed. */
|
||||
g_assert_not_reached();
|
||||
case INDEX_op_not_vec:
|
||||
/* These opcodes have generic expansions using the above. */
|
||||
g_assert_not_reached();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tcg_can_emit_vec_op(opc, type, vece)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* The opcode list is created by front ends based on what they
|
||||
* actually invoke. We must mirror the logic in the routines
|
||||
* below for generic expansions using other opcodes.
|
||||
*/
|
||||
switch (opc) {
|
||||
case INDEX_op_neg_vec:
|
||||
if (tcg_can_emit_vec_op(INDEX_op_sub_vec, type, vece)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case INDEX_op_abs_vec:
|
||||
if (tcg_can_emit_vec_op(INDEX_op_sub_vec, type, vece)
|
||||
&& (tcg_can_emit_vec_op(INDEX_op_smax_vec, type, vece) > 0
|
||||
|| tcg_can_emit_vec_op(INDEX_op_sari_vec, type, vece) > 0
|
||||
|| tcg_can_emit_vec_op(INDEX_op_cmp_vec, type, vece))) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case INDEX_op_usadd_vec:
|
||||
if (tcg_can_emit_vec_op(INDEX_op_umin_vec, type, vece) ||
|
||||
tcg_can_emit_vec_op(INDEX_op_cmp_vec, type, vece)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case INDEX_op_ussub_vec:
|
||||
if (tcg_can_emit_vec_op(INDEX_op_umax_vec, type, vece) ||
|
||||
tcg_can_emit_vec_op(INDEX_op_cmp_vec, type, vece)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case INDEX_op_cmpsel_vec:
|
||||
case INDEX_op_smin_vec:
|
||||
case INDEX_op_smax_vec:
|
||||
case INDEX_op_umin_vec:
|
||||
case INDEX_op_umax_vec:
|
||||
if (tcg_can_emit_vec_op(INDEX_op_cmp_vec, type, vece)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void vec_gen_2(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r, TCGArg a)
|
||||
{
|
||||
TCGOp *op = tcg_emit_op(opc, 2);
|
||||
TCGOP_TYPE(op) = type;
|
||||
TCGOP_VECE(op) = vece;
|
||||
op->args[0] = r;
|
||||
op->args[1] = a;
|
||||
}
|
||||
|
||||
void vec_gen_3(TCGOpcode opc, TCGType type, unsigned vece,
|
||||
TCGArg r, TCGArg a, TCGArg b)
|
||||
{
|
||||
TCGOp *op = tcg_emit_op(opc, 3);
|
||||
TCGOP_TYPE(op) = type;
|
||||
TCGOP_VECE(op) = vece;
|
||||
op->args[0] = r;
|
||||
op->args[1] = a;
|
||||
op->args[2] = b;
|
||||
}
|
||||
|
||||
void vec_gen_4(TCGOpcode opc, TCGType type, unsigned vece,
|
||||
TCGArg r, TCGArg a, TCGArg b, TCGArg c)
|
||||
{
|
||||
TCGOp *op = tcg_emit_op(opc, 4);
|
||||
TCGOP_TYPE(op) = type;
|
||||
TCGOP_VECE(op) = vece;
|
||||
op->args[0] = r;
|
||||
op->args[1] = a;
|
||||
op->args[2] = b;
|
||||
op->args[3] = c;
|
||||
}
|
||||
|
||||
void vec_gen_6(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r,
|
||||
TCGArg a, TCGArg b, TCGArg c, TCGArg d, TCGArg e)
|
||||
{
|
||||
TCGOp *op = tcg_emit_op(opc, 6);
|
||||
TCGOP_TYPE(op) = type;
|
||||
TCGOP_VECE(op) = vece;
|
||||
op->args[0] = r;
|
||||
op->args[1] = a;
|
||||
op->args[2] = b;
|
||||
op->args[3] = c;
|
||||
op->args[4] = d;
|
||||
op->args[5] = e;
|
||||
}
|
||||
|
||||
static void vec_gen_op2(TCGOpcode opc, unsigned vece, TCGv_vec r, TCGv_vec a)
|
||||
{
|
||||
TCGTemp *rt = tcgv_vec_temp(r);
|
||||
TCGTemp *at = tcgv_vec_temp(a);
|
||||
TCGType type = rt->base_type;
|
||||
|
||||
/* Must enough inputs for the output. */
|
||||
tcg_debug_assert(at->base_type >= type);
|
||||
vec_gen_2(opc, type, vece, temp_arg(rt), temp_arg(at));
|
||||
}
|
||||
|
||||
static void vec_gen_op3(TCGOpcode opc, unsigned vece,
|
||||
TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
TCGTemp *rt = tcgv_vec_temp(r);
|
||||
TCGTemp *at = tcgv_vec_temp(a);
|
||||
TCGTemp *bt = tcgv_vec_temp(b);
|
||||
TCGType type = rt->base_type;
|
||||
|
||||
/* Must enough inputs for the output. */
|
||||
tcg_debug_assert(at->base_type >= type);
|
||||
tcg_debug_assert(bt->base_type >= type);
|
||||
vec_gen_3(opc, type, vece, temp_arg(rt), temp_arg(at), temp_arg(bt));
|
||||
}
|
||||
|
||||
void tcg_gen_mov_vec(TCGv_vec r, TCGv_vec a)
|
||||
{
|
||||
if (r != a) {
|
||||
vec_gen_op2(INDEX_op_mov_vec, 0, r, a);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_dupi_vec(unsigned vece, TCGv_vec r, uint64_t a)
|
||||
{
|
||||
TCGTemp *rt = tcgv_vec_temp(r);
|
||||
tcg_gen_mov_vec(r, tcg_constant_vec(rt->base_type, vece, a));
|
||||
}
|
||||
|
||||
void tcg_gen_dup_i64_vec(unsigned vece, TCGv_vec r, TCGv_i64 a)
|
||||
{
|
||||
TCGArg ri = tcgv_vec_arg(r);
|
||||
TCGArg ai = tcgv_i64_arg(a);
|
||||
TCGTemp *rt = arg_temp(ri);
|
||||
TCGType type = rt->base_type;
|
||||
|
||||
vec_gen_2(INDEX_op_dup_vec, type, vece, ri, ai);
|
||||
}
|
||||
|
||||
void tcg_gen_dup_i32_vec(unsigned vece, TCGv_vec r, TCGv_i32 a)
|
||||
{
|
||||
TCGArg ri = tcgv_vec_arg(r);
|
||||
TCGArg ai = tcgv_i32_arg(a);
|
||||
TCGTemp *rt = arg_temp(ri);
|
||||
TCGType type = rt->base_type;
|
||||
|
||||
vec_gen_2(INDEX_op_dup_vec, type, vece, ri, ai);
|
||||
}
|
||||
|
||||
void tcg_gen_dup_mem_vec(unsigned vece, TCGv_vec r, TCGv_ptr b,
|
||||
tcg_target_long ofs)
|
||||
{
|
||||
TCGArg ri = tcgv_vec_arg(r);
|
||||
TCGArg bi = tcgv_ptr_arg(b);
|
||||
TCGTemp *rt = arg_temp(ri);
|
||||
TCGType type = rt->base_type;
|
||||
|
||||
vec_gen_3(INDEX_op_dupm_vec, type, vece, ri, bi, ofs);
|
||||
}
|
||||
|
||||
static void vec_gen_ldst(TCGOpcode opc, TCGv_vec r, TCGv_ptr b, TCGArg o)
|
||||
{
|
||||
TCGArg ri = tcgv_vec_arg(r);
|
||||
TCGArg bi = tcgv_ptr_arg(b);
|
||||
TCGTemp *rt = arg_temp(ri);
|
||||
TCGType type = rt->base_type;
|
||||
|
||||
vec_gen_3(opc, type, 0, ri, bi, o);
|
||||
}
|
||||
|
||||
void tcg_gen_ld_vec(TCGv_vec r, TCGv_ptr b, TCGArg o)
|
||||
{
|
||||
vec_gen_ldst(INDEX_op_ld_vec, r, b, o);
|
||||
}
|
||||
|
||||
void tcg_gen_st_vec(TCGv_vec r, TCGv_ptr b, TCGArg o)
|
||||
{
|
||||
vec_gen_ldst(INDEX_op_st_vec, r, b, o);
|
||||
}
|
||||
|
||||
void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr b, TCGArg o, TCGType low_type)
|
||||
{
|
||||
TCGArg ri = tcgv_vec_arg(r);
|
||||
TCGArg bi = tcgv_ptr_arg(b);
|
||||
TCGTemp *rt = arg_temp(ri);
|
||||
TCGType type = rt->base_type;
|
||||
|
||||
tcg_debug_assert(low_type >= TCG_TYPE_V64);
|
||||
tcg_debug_assert(low_type <= type);
|
||||
vec_gen_3(INDEX_op_st_vec, low_type, 0, ri, bi, o);
|
||||
}
|
||||
|
||||
void tcg_gen_and_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
vec_gen_op3(INDEX_op_and_vec, 0, r, a, b);
|
||||
}
|
||||
|
||||
void tcg_gen_or_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
vec_gen_op3(INDEX_op_or_vec, 0, r, a, b);
|
||||
}
|
||||
|
||||
void tcg_gen_xor_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
vec_gen_op3(INDEX_op_xor_vec, 0, r, a, b);
|
||||
}
|
||||
|
||||
void tcg_gen_andc_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
if (TCG_TARGET_HAS_andc_vec) {
|
||||
vec_gen_op3(INDEX_op_andc_vec, 0, r, a, b);
|
||||
} else {
|
||||
TCGv_vec t = tcg_temp_new_vec_matching(r);
|
||||
tcg_gen_not_vec(0, t, b);
|
||||
tcg_gen_and_vec(0, r, a, t);
|
||||
tcg_temp_free_vec(t);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_orc_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
if (TCG_TARGET_HAS_orc_vec) {
|
||||
vec_gen_op3(INDEX_op_orc_vec, 0, r, a, b);
|
||||
} else {
|
||||
TCGv_vec t = tcg_temp_new_vec_matching(r);
|
||||
tcg_gen_not_vec(0, t, b);
|
||||
tcg_gen_or_vec(0, r, a, t);
|
||||
tcg_temp_free_vec(t);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_nand_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
if (TCG_TARGET_HAS_nand_vec) {
|
||||
vec_gen_op3(INDEX_op_nand_vec, 0, r, a, b);
|
||||
} else {
|
||||
tcg_gen_and_vec(0, r, a, b);
|
||||
tcg_gen_not_vec(0, r, r);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_nor_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
if (TCG_TARGET_HAS_nor_vec) {
|
||||
vec_gen_op3(INDEX_op_nor_vec, 0, r, a, b);
|
||||
} else {
|
||||
tcg_gen_or_vec(0, r, a, b);
|
||||
tcg_gen_not_vec(0, r, r);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_eqv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
if (TCG_TARGET_HAS_eqv_vec) {
|
||||
vec_gen_op3(INDEX_op_eqv_vec, 0, r, a, b);
|
||||
} else {
|
||||
tcg_gen_xor_vec(0, r, a, b);
|
||||
tcg_gen_not_vec(0, r, r);
|
||||
}
|
||||
}
|
||||
|
||||
static bool do_op2(unsigned vece, TCGv_vec r, TCGv_vec a, TCGOpcode opc)
|
||||
{
|
||||
TCGTemp *rt = tcgv_vec_temp(r);
|
||||
TCGTemp *at = tcgv_vec_temp(a);
|
||||
TCGArg ri = temp_arg(rt);
|
||||
TCGArg ai = temp_arg(at);
|
||||
TCGType type = rt->base_type;
|
||||
int can;
|
||||
|
||||
tcg_debug_assert(at->base_type >= type);
|
||||
tcg_assert_listed_vecop(opc);
|
||||
can = tcg_can_emit_vec_op(opc, type, vece);
|
||||
if (can > 0) {
|
||||
vec_gen_2(opc, type, vece, ri, ai);
|
||||
} else if (can < 0) {
|
||||
const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL);
|
||||
tcg_expand_vec_op(opc, type, vece, ri, ai);
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void tcg_gen_not_vec(unsigned vece, TCGv_vec r, TCGv_vec a)
|
||||
{
|
||||
if (TCG_TARGET_HAS_not_vec) {
|
||||
vec_gen_op2(INDEX_op_not_vec, 0, r, a);
|
||||
} else {
|
||||
tcg_gen_xor_vec(0, r, a, tcg_constant_vec_matching(r, 0, -1));
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_neg_vec(unsigned vece, TCGv_vec r, TCGv_vec a)
|
||||
{
|
||||
const TCGOpcode *hold_list;
|
||||
|
||||
tcg_assert_listed_vecop(INDEX_op_neg_vec);
|
||||
hold_list = tcg_swap_vecop_list(NULL);
|
||||
|
||||
if (!TCG_TARGET_HAS_neg_vec || !do_op2(vece, r, a, INDEX_op_neg_vec)) {
|
||||
tcg_gen_sub_vec(vece, r, tcg_constant_vec_matching(r, vece, 0), a);
|
||||
}
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
}
|
||||
|
||||
void tcg_gen_abs_vec(unsigned vece, TCGv_vec r, TCGv_vec a)
|
||||
{
|
||||
const TCGOpcode *hold_list;
|
||||
|
||||
tcg_assert_listed_vecop(INDEX_op_abs_vec);
|
||||
hold_list = tcg_swap_vecop_list(NULL);
|
||||
|
||||
if (!do_op2(vece, r, a, INDEX_op_abs_vec)) {
|
||||
TCGType type = tcgv_vec_temp(r)->base_type;
|
||||
TCGv_vec t = tcg_temp_new_vec(type);
|
||||
|
||||
tcg_debug_assert(tcg_can_emit_vec_op(INDEX_op_sub_vec, type, vece));
|
||||
if (tcg_can_emit_vec_op(INDEX_op_smax_vec, type, vece) > 0) {
|
||||
tcg_gen_neg_vec(vece, t, a);
|
||||
tcg_gen_smax_vec(vece, r, a, t);
|
||||
} else {
|
||||
if (tcg_can_emit_vec_op(INDEX_op_sari_vec, type, vece) > 0) {
|
||||
tcg_gen_sari_vec(vece, t, a, (8 << vece) - 1);
|
||||
} else {
|
||||
tcg_gen_cmp_vec(TCG_COND_LT, vece, t, a,
|
||||
tcg_constant_vec(type, vece, 0));
|
||||
}
|
||||
tcg_gen_xor_vec(vece, r, a, t);
|
||||
tcg_gen_sub_vec(vece, r, r, t);
|
||||
}
|
||||
|
||||
tcg_temp_free_vec(t);
|
||||
}
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
}
|
||||
|
||||
static void do_shifti(TCGOpcode opc, unsigned vece,
|
||||
TCGv_vec r, TCGv_vec a, int64_t i)
|
||||
{
|
||||
TCGTemp *rt = tcgv_vec_temp(r);
|
||||
TCGTemp *at = tcgv_vec_temp(a);
|
||||
TCGArg ri = temp_arg(rt);
|
||||
TCGArg ai = temp_arg(at);
|
||||
TCGType type = rt->base_type;
|
||||
int can;
|
||||
|
||||
tcg_debug_assert(at->base_type == type);
|
||||
tcg_debug_assert(i >= 0 && i < (8 << vece));
|
||||
tcg_assert_listed_vecop(opc);
|
||||
|
||||
if (i == 0) {
|
||||
tcg_gen_mov_vec(r, a);
|
||||
return;
|
||||
}
|
||||
|
||||
can = tcg_can_emit_vec_op(opc, type, vece);
|
||||
if (can > 0) {
|
||||
vec_gen_3(opc, type, vece, ri, ai, i);
|
||||
} else {
|
||||
/* We leave the choice of expansion via scalar or vector shift
|
||||
to the target. Often, but not always, dupi can feed a vector
|
||||
shift easier than a scalar. */
|
||||
const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL);
|
||||
tcg_debug_assert(can < 0);
|
||||
tcg_expand_vec_op(opc, type, vece, ri, ai, i);
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_shli_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i)
|
||||
{
|
||||
do_shifti(INDEX_op_shli_vec, vece, r, a, i);
|
||||
}
|
||||
|
||||
void tcg_gen_shri_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i)
|
||||
{
|
||||
do_shifti(INDEX_op_shri_vec, vece, r, a, i);
|
||||
}
|
||||
|
||||
void tcg_gen_sari_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i)
|
||||
{
|
||||
do_shifti(INDEX_op_sari_vec, vece, r, a, i);
|
||||
}
|
||||
|
||||
void tcg_gen_rotli_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i)
|
||||
{
|
||||
do_shifti(INDEX_op_rotli_vec, vece, r, a, i);
|
||||
}
|
||||
|
||||
void tcg_gen_rotri_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i)
|
||||
{
|
||||
int bits = 8 << vece;
|
||||
tcg_debug_assert(i >= 0 && i < bits);
|
||||
do_shifti(INDEX_op_rotli_vec, vece, r, a, -i & (bits - 1));
|
||||
}
|
||||
|
||||
void tcg_gen_cmp_vec(TCGCond cond, unsigned vece,
|
||||
TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
TCGTemp *rt = tcgv_vec_temp(r);
|
||||
TCGTemp *at = tcgv_vec_temp(a);
|
||||
TCGTemp *bt = tcgv_vec_temp(b);
|
||||
TCGTemp *tt = NULL;
|
||||
TCGArg ri = temp_arg(rt);
|
||||
TCGArg ai = temp_arg(at);
|
||||
TCGArg bi = temp_arg(bt);
|
||||
TCGArg ti;
|
||||
TCGType type = rt->base_type;
|
||||
int can;
|
||||
|
||||
tcg_debug_assert(at->base_type >= type);
|
||||
tcg_debug_assert(bt->base_type >= type);
|
||||
tcg_assert_listed_vecop(INDEX_op_cmp_vec);
|
||||
can = tcg_can_emit_vec_op(INDEX_op_cmp_vec, type, vece);
|
||||
|
||||
if (!TCG_TARGET_HAS_tst_vec && is_tst_cond(cond)) {
|
||||
tt = tcg_temp_new_internal(type, TEMP_EBB);
|
||||
ti = temp_arg(tt);
|
||||
vec_gen_3(INDEX_op_and_vec, type, 0, ti, ai, bi);
|
||||
at = tt;
|
||||
ai = ti;
|
||||
bt = tcg_constant_internal(type, 0);
|
||||
bi = temp_arg(bt);
|
||||
cond = tcg_tst_eqne_cond(cond);
|
||||
}
|
||||
|
||||
if (can > 0) {
|
||||
vec_gen_4(INDEX_op_cmp_vec, type, vece, ri, ai, bi, cond);
|
||||
} else {
|
||||
const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL);
|
||||
tcg_debug_assert(can < 0);
|
||||
tcg_expand_vec_op(INDEX_op_cmp_vec, type, vece, ri, ai, bi, cond);
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
}
|
||||
|
||||
if (tt) {
|
||||
tcg_temp_free_internal(tt);
|
||||
}
|
||||
}
|
||||
|
||||
static bool do_op3(unsigned vece, TCGv_vec r, TCGv_vec a,
|
||||
TCGv_vec b, TCGOpcode opc)
|
||||
{
|
||||
TCGTemp *rt = tcgv_vec_temp(r);
|
||||
TCGTemp *at = tcgv_vec_temp(a);
|
||||
TCGTemp *bt = tcgv_vec_temp(b);
|
||||
TCGArg ri = temp_arg(rt);
|
||||
TCGArg ai = temp_arg(at);
|
||||
TCGArg bi = temp_arg(bt);
|
||||
TCGType type = rt->base_type;
|
||||
int can;
|
||||
|
||||
tcg_debug_assert(at->base_type >= type);
|
||||
tcg_debug_assert(bt->base_type >= type);
|
||||
tcg_assert_listed_vecop(opc);
|
||||
can = tcg_can_emit_vec_op(opc, type, vece);
|
||||
if (can > 0) {
|
||||
vec_gen_3(opc, type, vece, ri, ai, bi);
|
||||
} else if (can < 0) {
|
||||
const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL);
|
||||
tcg_expand_vec_op(opc, type, vece, ri, ai, bi);
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void do_op3_nofail(unsigned vece, TCGv_vec r, TCGv_vec a,
|
||||
TCGv_vec b, TCGOpcode opc)
|
||||
{
|
||||
bool ok = do_op3(vece, r, a, b, opc);
|
||||
tcg_debug_assert(ok);
|
||||
}
|
||||
|
||||
void tcg_gen_add_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_op3_nofail(vece, r, a, b, INDEX_op_add_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_sub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_op3_nofail(vece, r, a, b, INDEX_op_sub_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_mul_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_op3_nofail(vece, r, a, b, INDEX_op_mul_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_ssadd_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_op3_nofail(vece, r, a, b, INDEX_op_ssadd_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_usadd_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
if (!do_op3(vece, r, a, b, INDEX_op_usadd_vec)) {
|
||||
const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL);
|
||||
TCGv_vec t = tcg_temp_new_vec_matching(r);
|
||||
|
||||
/* usadd(a, b) = min(a, ~b) + b */
|
||||
tcg_gen_not_vec(vece, t, b);
|
||||
tcg_gen_umin_vec(vece, t, t, a);
|
||||
tcg_gen_add_vec(vece, r, t, b);
|
||||
|
||||
tcg_temp_free_vec(t);
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_sssub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_op3_nofail(vece, r, a, b, INDEX_op_sssub_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_ussub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
if (!do_op3(vece, r, a, b, INDEX_op_ussub_vec)) {
|
||||
const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL);
|
||||
TCGv_vec t = tcg_temp_new_vec_matching(r);
|
||||
|
||||
/* ussub(a, b) = max(a, b) - b */
|
||||
tcg_gen_umax_vec(vece, t, a, b);
|
||||
tcg_gen_sub_vec(vece, r, t, b);
|
||||
|
||||
tcg_temp_free_vec(t);
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_minmax(unsigned vece, TCGv_vec r, TCGv_vec a,
|
||||
TCGv_vec b, TCGOpcode opc, TCGCond cond)
|
||||
{
|
||||
if (!do_op3(vece, r, a, b, opc)) {
|
||||
const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL);
|
||||
tcg_gen_cmpsel_vec(cond, vece, r, a, b, a, b);
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_smin_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_minmax(vece, r, a, b, INDEX_op_smin_vec, TCG_COND_LT);
|
||||
}
|
||||
|
||||
void tcg_gen_umin_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_minmax(vece, r, a, b, INDEX_op_umin_vec, TCG_COND_LTU);
|
||||
}
|
||||
|
||||
void tcg_gen_smax_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_minmax(vece, r, a, b, INDEX_op_smax_vec, TCG_COND_GT);
|
||||
}
|
||||
|
||||
void tcg_gen_umax_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_minmax(vece, r, a, b, INDEX_op_umax_vec, TCG_COND_GTU);
|
||||
}
|
||||
|
||||
void tcg_gen_shlv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_op3_nofail(vece, r, a, b, INDEX_op_shlv_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_shrv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_op3_nofail(vece, r, a, b, INDEX_op_shrv_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_sarv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_op3_nofail(vece, r, a, b, INDEX_op_sarv_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_rotlv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_op3_nofail(vece, r, a, b, INDEX_op_rotlv_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_rotrv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
|
||||
{
|
||||
do_op3_nofail(vece, r, a, b, INDEX_op_rotrv_vec);
|
||||
}
|
||||
|
||||
static void do_shifts(unsigned vece, TCGv_vec r, TCGv_vec a,
|
||||
TCGv_i32 s, TCGOpcode opc)
|
||||
{
|
||||
TCGTemp *rt = tcgv_vec_temp(r);
|
||||
TCGTemp *at = tcgv_vec_temp(a);
|
||||
TCGTemp *st = tcgv_i32_temp(s);
|
||||
TCGArg ri = temp_arg(rt);
|
||||
TCGArg ai = temp_arg(at);
|
||||
TCGArg si = temp_arg(st);
|
||||
TCGType type = rt->base_type;
|
||||
int can;
|
||||
|
||||
tcg_debug_assert(at->base_type >= type);
|
||||
tcg_assert_listed_vecop(opc);
|
||||
can = tcg_can_emit_vec_op(opc, type, vece);
|
||||
if (can > 0) {
|
||||
vec_gen_3(opc, type, vece, ri, ai, si);
|
||||
} else if (can < 0) {
|
||||
const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL);
|
||||
tcg_expand_vec_op(opc, type, vece, ri, ai, si);
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_shls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 b)
|
||||
{
|
||||
do_shifts(vece, r, a, b, INDEX_op_shls_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_shrs_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 b)
|
||||
{
|
||||
do_shifts(vece, r, a, b, INDEX_op_shrs_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_sars_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 b)
|
||||
{
|
||||
do_shifts(vece, r, a, b, INDEX_op_sars_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_rotls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s)
|
||||
{
|
||||
do_shifts(vece, r, a, s, INDEX_op_rotls_vec);
|
||||
}
|
||||
|
||||
void tcg_gen_bitsel_vec(unsigned vece, TCGv_vec r, TCGv_vec a,
|
||||
TCGv_vec b, TCGv_vec c)
|
||||
{
|
||||
TCGTemp *rt = tcgv_vec_temp(r);
|
||||
TCGTemp *at = tcgv_vec_temp(a);
|
||||
TCGTemp *bt = tcgv_vec_temp(b);
|
||||
TCGTemp *ct = tcgv_vec_temp(c);
|
||||
TCGType type = rt->base_type;
|
||||
|
||||
tcg_debug_assert(at->base_type >= type);
|
||||
tcg_debug_assert(bt->base_type >= type);
|
||||
tcg_debug_assert(ct->base_type >= type);
|
||||
|
||||
if (TCG_TARGET_HAS_bitsel_vec) {
|
||||
vec_gen_4(INDEX_op_bitsel_vec, type, MO_8,
|
||||
temp_arg(rt), temp_arg(at), temp_arg(bt), temp_arg(ct));
|
||||
} else {
|
||||
TCGv_vec t = tcg_temp_new_vec(type);
|
||||
tcg_gen_and_vec(MO_8, t, a, b);
|
||||
tcg_gen_andc_vec(MO_8, r, c, a);
|
||||
tcg_gen_or_vec(MO_8, r, r, t);
|
||||
tcg_temp_free_vec(t);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_cmpsel_vec(TCGCond cond, unsigned vece, TCGv_vec r,
|
||||
TCGv_vec a, TCGv_vec b, TCGv_vec c, TCGv_vec d)
|
||||
{
|
||||
TCGTemp *rt = tcgv_vec_temp(r);
|
||||
TCGTemp *at = tcgv_vec_temp(a);
|
||||
TCGTemp *bt = tcgv_vec_temp(b);
|
||||
TCGTemp *ct = tcgv_vec_temp(c);
|
||||
TCGTemp *dt = tcgv_vec_temp(d);
|
||||
TCGArg ri = temp_arg(rt);
|
||||
TCGArg ai = temp_arg(at);
|
||||
TCGArg bi = temp_arg(bt);
|
||||
TCGArg ci = temp_arg(ct);
|
||||
TCGArg di = temp_arg(dt);
|
||||
TCGType type = rt->base_type;
|
||||
const TCGOpcode *hold_list;
|
||||
int can;
|
||||
|
||||
tcg_debug_assert(at->base_type >= type);
|
||||
tcg_debug_assert(bt->base_type >= type);
|
||||
tcg_debug_assert(ct->base_type >= type);
|
||||
tcg_debug_assert(dt->base_type >= type);
|
||||
|
||||
tcg_assert_listed_vecop(INDEX_op_cmpsel_vec);
|
||||
hold_list = tcg_swap_vecop_list(NULL);
|
||||
can = tcg_can_emit_vec_op(INDEX_op_cmpsel_vec, type, vece);
|
||||
|
||||
if (can > 0) {
|
||||
vec_gen_6(INDEX_op_cmpsel_vec, type, vece, ri, ai, bi, ci, di, cond);
|
||||
} else if (can < 0) {
|
||||
tcg_expand_vec_op(INDEX_op_cmpsel_vec, type, vece,
|
||||
ri, ai, bi, ci, di, cond);
|
||||
} else {
|
||||
TCGv_vec t = tcg_temp_new_vec(type);
|
||||
tcg_gen_cmp_vec(cond, vece, t, a, b);
|
||||
tcg_gen_bitsel_vec(vece, r, t, c, d);
|
||||
tcg_temp_free_vec(t);
|
||||
}
|
||||
tcg_swap_vecop_list(hold_list);
|
||||
}
|
||||
+2732
File diff suppressed because it is too large
Load Diff
+120
@@ -0,0 +1,120 @@
|
||||
TCG Interpreter (TCI) - Copyright (c) 2011 Stefan Weil.
|
||||
|
||||
This file is released under the BSD license.
|
||||
|
||||
1) Introduction
|
||||
|
||||
TCG (Tiny Code Generator) is a code generator which translates
|
||||
code fragments ("basic blocks") from target code (any of the
|
||||
targets supported by QEMU) to a code representation which
|
||||
can be run on a host.
|
||||
|
||||
QEMU can create native code for some hosts (arm, i386, ia64, ppc, ppc64,
|
||||
s390, sparc, x86_64). For others, unofficial host support was written.
|
||||
|
||||
By adding a code generator for a virtual machine and using an
|
||||
interpreter for the generated bytecode, it is possible to
|
||||
support (almost) any host.
|
||||
|
||||
This is what TCI (Tiny Code Interpreter) does.
|
||||
|
||||
2) Implementation
|
||||
|
||||
Like each TCG host frontend, TCI implements the code generator in
|
||||
tcg-target.c.inc, tcg-target.h. Both files are in directory tcg/tci.
|
||||
|
||||
The additional file tcg/tci.c adds the interpreter and disassembler.
|
||||
|
||||
The bytecode consists of opcodes (with only a few exceptions, with
|
||||
the same same numeric values and semantics as used by TCG), and up
|
||||
to six arguments packed into a 32-bit integer. See comments in tci.c
|
||||
for details on the encoding.
|
||||
|
||||
3) Usage
|
||||
|
||||
For hosts without native TCG, the interpreter TCI must be enabled by
|
||||
|
||||
configure --enable-tcg-interpreter
|
||||
|
||||
If configure is called without --enable-tcg-interpreter, it will
|
||||
suggest using this option. Setting it automatically would need
|
||||
additional code in configure which must be fixed when new native TCG
|
||||
implementations are added.
|
||||
|
||||
For hosts with native TCG, the interpreter TCI can be enabled by
|
||||
|
||||
configure --enable-tcg-interpreter
|
||||
|
||||
The only difference from running QEMU with TCI to running without TCI
|
||||
should be speed. Especially during development of TCI, it was very
|
||||
useful to compare runs with and without TCI. Create /tmp/qemu.log by
|
||||
|
||||
qemu-system-i386 -d in_asm,op_opt,cpu -D /tmp/qemu.log -accel tcg,one-insn-per-tb=on
|
||||
|
||||
once with interpreter and once without interpreter and compare the resulting
|
||||
qemu.log files. This is also useful to see the effects of additional
|
||||
registers or additional opcodes (it is easy to modify the virtual machine).
|
||||
It can also be used to verify native TCGs.
|
||||
|
||||
Hosts with native TCG can also enable TCI by claiming to be unsupported:
|
||||
|
||||
configure --cpu=unknown --enable-tcg-interpreter
|
||||
|
||||
configure then no longer uses the native linker script (*.ld) for
|
||||
user mode emulation.
|
||||
|
||||
|
||||
4) Status
|
||||
|
||||
TCI needs special implementation for 32 and 64 bit host, 32 and 64 bit target,
|
||||
host and target with same or different endianness.
|
||||
|
||||
| host (le) host (be)
|
||||
| 32 64 32 64
|
||||
------------+------------------------------------------------------------
|
||||
target (le) | s0, u0 s1, u1 s?, u? s?, u?
|
||||
32 bit |
|
||||
|
|
||||
target (le) | sc, uc s1, u1 s?, u? s?, u?
|
||||
64 bit |
|
||||
|
|
||||
target (be) | sc, u0 sc, uc s?, u? s?, u?
|
||||
32 bit |
|
||||
|
|
||||
target (be) | sc, uc sc, uc s?, u? s?, u?
|
||||
64 bit |
|
||||
|
|
||||
|
||||
System emulation
|
||||
s? = untested
|
||||
sc = compiles
|
||||
s0 = bios works
|
||||
s1 = grub works
|
||||
s2 = Linux boots
|
||||
|
||||
Linux user mode emulation
|
||||
u? = untested
|
||||
uc = compiles
|
||||
u0 = static hello works
|
||||
u1 = linux-user-test works
|
||||
|
||||
5) Todo list
|
||||
|
||||
* TCI is not widely tested. It was written and tested on a x86_64 host
|
||||
running i386 and x86_64 system emulation and Linux user mode.
|
||||
A cross compiled QEMU for i386 host also works with the same basic tests.
|
||||
A cross compiled QEMU for mipsel host works, too. It is terribly slow
|
||||
because I run it in a mips malta emulation, so it is an interpreted
|
||||
emulation in an emulation.
|
||||
A cross compiled QEMU for arm host works (tested with pc bios).
|
||||
A cross compiled QEMU for ppc host works at least partially:
|
||||
i386-linux-user/qemu-i386 can run a simple hello-world program
|
||||
(tested in a ppc emulation).
|
||||
|
||||
* Some TCG opcodes are either missing in the code generator and/or
|
||||
in the interpreter. These opcodes raise a runtime exception, so it is
|
||||
possible to see where code must be added.
|
||||
|
||||
* It might be useful to have a runtime option which selects the native TCG
|
||||
or TCI, so QEMU would have to include two TCGs. Today, selecting TCI
|
||||
is a configure option, so you need two compilations of QEMU.
|
||||
@@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* TCI target-specific constraint sets.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs.
|
||||
* Each operand should be a sequence of constraint letters as defined by
|
||||
* tcg-target-con-str.h; the constraint combination is inclusive or.
|
||||
*/
|
||||
C_O0_I1(r)
|
||||
C_O0_I2(r, r)
|
||||
C_O0_I3(r, r, r)
|
||||
C_O0_I4(r, r, r, r)
|
||||
C_O1_I1(r, r)
|
||||
C_O1_I2(r, r, r)
|
||||
C_O1_I4(r, r, r, r, r)
|
||||
C_O2_I1(r, r, r)
|
||||
C_O2_I2(r, r, r, r)
|
||||
C_O2_I4(r, r, r, r, r, r)
|
||||
@@ -0,0 +1,11 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define TCI target-specific operand constraints.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define constraint letters for register sets:
|
||||
* REGS(letter, register_mask)
|
||||
*/
|
||||
REGS('r', MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS))
|
||||
@@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific opcode support
|
||||
* Copyright (c) 2009, 2011 Stefan Weil
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_HAS_H
|
||||
#define TCG_TARGET_HAS_H
|
||||
|
||||
#define TCG_TARGET_HAS_extr_i64_i32 0
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
#define TCG_TARGET_HAS_tst 1
|
||||
|
||||
#define TCG_TARGET_extract_valid(type, ofs, len) 1
|
||||
#define TCG_TARGET_sextract_valid(type, ofs, len) 1
|
||||
#define TCG_TARGET_deposit_valid(type, ofs, len) 1
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific memory model
|
||||
* Copyright (c) 2009, 2011 Stefan Weil
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_MO_H
|
||||
#define TCG_TARGET_MO_H
|
||||
|
||||
/*
|
||||
* We could notice __x86_64__ or __s390x__ and reduce the barriers depending
|
||||
* on the host. But if you want performance, you use the normal backend.
|
||||
* We prefer consistency across hosts on this.
|
||||
*/
|
||||
#define TCG_TARGET_DEFAULT_MO 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/* These opcodes for use between the tci generator and interpreter. */
|
||||
DEF(tci_movi, 1, 0, 1, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_movl, 1, 0, 1, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_setcarry, 0, 0, 0, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_clz32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_ctz32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_divs32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_divu32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_rems32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_remu32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_rotl32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_rotr32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_setcond32, 1, 2, 1, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_movcond32, 1, 2, 1, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_qemu_ld_rrr, 1, 2, 0, TCG_OPF_NOT_PRESENT)
|
||||
DEF(tci_qemu_st_rrr, 0, 3, 0, TCG_OPF_NOT_PRESENT)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2009, 2011 Stefan Weil
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code implements a TCG which does not generate machine code for some
|
||||
* real target machine but which generates virtual machine code for an
|
||||
* interpreter. Interpreted pseudo code is slow, but it works on any host.
|
||||
*
|
||||
* Some remarks might help in understanding the code:
|
||||
*
|
||||
* "target" or "TCG target" is the machine which runs the generated code.
|
||||
* This is different to the usual meaning in QEMU where "target" is the
|
||||
* emulated machine. So normally QEMU host is identical to TCG target.
|
||||
* Here the TCG target is a virtual machine, but this virtual machine must
|
||||
* use the same word size like the real machine.
|
||||
* Therefore, we need both 32 and 64 bit virtual machines (interpreter).
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_H
|
||||
#define TCG_TARGET_H
|
||||
|
||||
#define TCG_TARGET_INTERPRETER 1
|
||||
#define TCG_TARGET_INSN_UNIT_SIZE 4
|
||||
#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
|
||||
|
||||
/* Number of registers available. */
|
||||
#define TCG_TARGET_NB_REGS 16
|
||||
|
||||
/* List of registers which are used by TCG. */
|
||||
typedef enum {
|
||||
TCG_REG_R0 = 0,
|
||||
TCG_REG_R1,
|
||||
TCG_REG_R2,
|
||||
TCG_REG_R3,
|
||||
TCG_REG_R4,
|
||||
TCG_REG_R5,
|
||||
TCG_REG_R6,
|
||||
TCG_REG_R7,
|
||||
TCG_REG_R8,
|
||||
TCG_REG_R9,
|
||||
TCG_REG_R10,
|
||||
TCG_REG_R11,
|
||||
TCG_REG_R12,
|
||||
TCG_REG_R13,
|
||||
TCG_REG_R14,
|
||||
TCG_REG_R15,
|
||||
|
||||
TCG_REG_TMP = TCG_REG_R13,
|
||||
TCG_AREG0 = TCG_REG_R14,
|
||||
TCG_REG_CALL_STACK = TCG_REG_R15,
|
||||
} TCGReg;
|
||||
|
||||
#define HAVE_TCG_QEMU_TB_EXEC
|
||||
|
||||
#endif /* TCG_TARGET_H */
|
||||
@@ -0,0 +1,60 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define i386 target-specific constraint sets.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*/
|
||||
|
||||
/*
|
||||
* C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs.
|
||||
* Each operand should be a sequence of constraint letters as defined by
|
||||
* tcg-target-con-str.h; the constraint combination is inclusive or.
|
||||
*
|
||||
* C_N1_Im(...) defines a constraint set with 1 output and <m> inputs,
|
||||
* except that the output must use a new register.
|
||||
*
|
||||
* C_Nn_Om_Ik(...) defines a constraint set with <n + m> outputs and <k>
|
||||
* inputs, except that the first <n> outputs must use new registers.
|
||||
*/
|
||||
C_O0_I1(r)
|
||||
C_O0_I2(L, L)
|
||||
C_O0_I2(qi, r)
|
||||
C_O0_I2(re, r)
|
||||
C_O0_I2(ri, r)
|
||||
C_O0_I2(r, reT)
|
||||
C_O0_I2(s, L)
|
||||
C_O0_I2(x, r)
|
||||
C_O0_I3(L, L, L)
|
||||
C_O0_I3(s, L, L)
|
||||
C_O0_I4(L, L, L, L)
|
||||
C_O0_I4(r, r, ri, ri)
|
||||
C_O1_I1(r, 0)
|
||||
C_O1_I1(r, L)
|
||||
C_O1_I1(r, q)
|
||||
C_O1_I1(r, r)
|
||||
C_O1_I1(x, r)
|
||||
C_O1_I1(x, x)
|
||||
C_O1_I2(q, 0, qi)
|
||||
C_O1_I2(q, r, reT)
|
||||
C_O1_I2(r, 0, ci)
|
||||
C_O1_I2(r, 0, r)
|
||||
C_O1_I2(r, 0, re)
|
||||
C_O1_I2(r, 0, reZ)
|
||||
C_O1_I2(r, 0, ri)
|
||||
C_O1_I2(r, 0, rI)
|
||||
C_O1_I2(r, L, L)
|
||||
C_O1_I2(r, r, r)
|
||||
C_O1_I2(r, r, re)
|
||||
C_O1_I2(r, r, ri)
|
||||
C_O1_I2(r, rO, re)
|
||||
C_O1_I2(x, x, x)
|
||||
C_N1_I2(r, r, r)
|
||||
C_N1_I2(r, r, rW)
|
||||
C_O1_I3(x, 0, x, x)
|
||||
C_O1_I3(x, x, x, x)
|
||||
C_O1_I4(x, x, x, xO, x)
|
||||
C_O1_I4(r, r, reT, r, 0)
|
||||
C_O1_I4(r, r, r, ri, ri)
|
||||
C_O2_I1(r, r, L)
|
||||
C_O2_I2(a, d, a, r)
|
||||
C_O2_I2(r, r, L, L)
|
||||
C_O2_I3(a, d, 0, 1, r)
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define i386 target-specific operand constraints.
|
||||
* Copyright (c) 2021 Linaro
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define constraint letters for register sets:
|
||||
* REGS(letter, register_mask)
|
||||
*/
|
||||
REGS('a', 1u << TCG_REG_EAX)
|
||||
REGS('b', 1u << TCG_REG_EBX)
|
||||
REGS('c', 1u << TCG_REG_ECX)
|
||||
REGS('d', 1u << TCG_REG_EDX)
|
||||
REGS('S', 1u << TCG_REG_ESI)
|
||||
REGS('D', 1u << TCG_REG_EDI)
|
||||
|
||||
REGS('r', ALL_GENERAL_REGS)
|
||||
REGS('x', ALL_VECTOR_REGS)
|
||||
REGS('q', ALL_BYTEL_REGS) /* regs that can be used as a byte operand */
|
||||
REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_ld/st */
|
||||
REGS('s', ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_st MO_8 data */
|
||||
|
||||
/*
|
||||
* Define constraint letters for constants:
|
||||
* CONST(letter, TCG_CT_CONST_* bit set)
|
||||
*/
|
||||
CONST('e', TCG_CT_CONST_S32)
|
||||
CONST('I', TCG_CT_CONST_I32)
|
||||
CONST('O', TCG_CT_CONST_ZERO)
|
||||
CONST('T', TCG_CT_CONST_TST)
|
||||
CONST('W', TCG_CT_CONST_WSZ)
|
||||
CONST('Z', TCG_CT_CONST_U32)
|
||||
@@ -0,0 +1,108 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific opcode support
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_HAS_H
|
||||
#define TCG_TARGET_HAS_H
|
||||
|
||||
#include "host/cpuinfo.h"
|
||||
|
||||
#define have_bmi1 (cpuinfo & CPUINFO_BMI1)
|
||||
#define have_popcnt (cpuinfo & CPUINFO_POPCNT)
|
||||
#define have_avx1 (cpuinfo & CPUINFO_AVX1)
|
||||
#define have_avx2 (cpuinfo & CPUINFO_AVX2)
|
||||
#define have_movbe (cpuinfo & CPUINFO_MOVBE)
|
||||
|
||||
/*
|
||||
* There are interesting instructions in AVX512, so long as we have AVX512VL,
|
||||
* which indicates support for EVEX on sizes smaller than 512 bits.
|
||||
*/
|
||||
#define have_avx512vl ((cpuinfo & CPUINFO_AVX512VL) && \
|
||||
(cpuinfo & CPUINFO_AVX512F))
|
||||
#define have_avx512bw ((cpuinfo & CPUINFO_AVX512BW) && have_avx512vl)
|
||||
#define have_avx512dq ((cpuinfo & CPUINFO_AVX512DQ) && have_avx512vl)
|
||||
#define have_avx512vbmi2 ((cpuinfo & CPUINFO_AVX512VBMI2) && have_avx512vl)
|
||||
|
||||
/* optional instructions */
|
||||
/* Keep 32-bit values zero-extended in a register. */
|
||||
#define TCG_TARGET_HAS_extr_i64_i32 1
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 (cpuinfo & CPUINFO_ATOMIC_VMOVDQA)
|
||||
|
||||
#define TCG_TARGET_HAS_tst 1
|
||||
|
||||
/* We do not support older SSE systems, only beginning with AVX1. */
|
||||
#define TCG_TARGET_HAS_v64 have_avx1
|
||||
#define TCG_TARGET_HAS_v128 have_avx1
|
||||
#define TCG_TARGET_HAS_v256 have_avx2
|
||||
|
||||
#define TCG_TARGET_HAS_andc_vec 1
|
||||
#define TCG_TARGET_HAS_orc_vec have_avx512vl
|
||||
#define TCG_TARGET_HAS_nand_vec have_avx512vl
|
||||
#define TCG_TARGET_HAS_nor_vec have_avx512vl
|
||||
#define TCG_TARGET_HAS_eqv_vec have_avx512vl
|
||||
#define TCG_TARGET_HAS_not_vec have_avx512vl
|
||||
#define TCG_TARGET_HAS_neg_vec 0
|
||||
#define TCG_TARGET_HAS_abs_vec 1
|
||||
#define TCG_TARGET_HAS_roti_vec have_avx512vl
|
||||
#define TCG_TARGET_HAS_rots_vec 0
|
||||
#define TCG_TARGET_HAS_rotv_vec have_avx512vl
|
||||
#define TCG_TARGET_HAS_shi_vec 1
|
||||
#define TCG_TARGET_HAS_shs_vec 1
|
||||
#define TCG_TARGET_HAS_shv_vec have_avx2
|
||||
#define TCG_TARGET_HAS_mul_vec 1
|
||||
#define TCG_TARGET_HAS_sat_vec 1
|
||||
#define TCG_TARGET_HAS_minmax_vec 1
|
||||
#define TCG_TARGET_HAS_bitsel_vec have_avx512vl
|
||||
#define TCG_TARGET_HAS_cmpsel_vec 1
|
||||
#define TCG_TARGET_HAS_tst_vec have_avx512bw
|
||||
|
||||
#define TCG_TARGET_deposit_valid(type, ofs, len) \
|
||||
((ofs) == 0 && ((len) == 8 || (len) == 16))
|
||||
|
||||
/*
|
||||
* Check for the possibility of low byte/word extraction, high-byte extraction
|
||||
* and zero-extending 32-bit right-shift.
|
||||
*
|
||||
* We cannot sign-extend from high byte to 64-bits without using the
|
||||
* REX prefix that explicitly excludes access to the high-byte registers.
|
||||
*/
|
||||
static inline bool
|
||||
tcg_target_sextract_valid(TCGType type, unsigned ofs, unsigned len)
|
||||
{
|
||||
switch (ofs) {
|
||||
case 0:
|
||||
switch (len) {
|
||||
case 8:
|
||||
case 16:
|
||||
return true;
|
||||
case 32:
|
||||
return type == TCG_TYPE_I64;
|
||||
}
|
||||
return false;
|
||||
case 8:
|
||||
return len == 8 && type == TCG_TYPE_I32;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#define TCG_TARGET_sextract_valid tcg_target_sextract_valid
|
||||
|
||||
static inline bool
|
||||
tcg_target_extract_valid(TCGType type, unsigned ofs, unsigned len)
|
||||
{
|
||||
if (type == TCG_TYPE_I64 && ofs + len == 32) {
|
||||
return true;
|
||||
}
|
||||
switch (ofs) {
|
||||
case 0:
|
||||
return len == 8 || len == 16;
|
||||
case 8:
|
||||
return len == 8;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#define TCG_TARGET_extract_valid tcg_target_extract_valid
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Define target-specific memory model
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*/
|
||||
|
||||
#ifndef TCG_TARGET_MO_H
|
||||
#define TCG_TARGET_MO_H
|
||||
|
||||
/*
|
||||
* This defines the natural memory order supported by this architecture
|
||||
* before guarantees made by various barrier instructions.
|
||||
*
|
||||
* The x86 has a pretty strong memory ordering which only really
|
||||
* allows for some stores to be re-ordered after loads.
|
||||
*/
|
||||
#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Linaro
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Target-specific opcodes for host vector expansion. These will be
|
||||
* emitted by tcg_expand_vec_op. For those familiar with GCC internals,
|
||||
* consider these to be UNSPEC with names.
|
||||
*/
|
||||
|
||||
DEF(x86_shufps_vec, 1, 2, 1, TCG_OPF_VECTOR)
|
||||
DEF(x86_blend_vec, 1, 2, 1, TCG_OPF_VECTOR)
|
||||
DEF(x86_packss_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
DEF(x86_packus_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
DEF(x86_psrldq_vec, 1, 1, 1, TCG_OPF_VECTOR)
|
||||
DEF(x86_vperm2i128_vec, 1, 2, 1, TCG_OPF_VECTOR)
|
||||
DEF(x86_punpckl_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
DEF(x86_punpckh_vec, 1, 2, 0, TCG_OPF_VECTOR)
|
||||
DEF(x86_vpshldi_vec, 1, 2, 1, TCG_OPF_VECTOR)
|
||||
DEF(x86_vpshldv_vec, 1, 3, 0, TCG_OPF_VECTOR)
|
||||
DEF(x86_vpshrdv_vec, 1, 3, 0, TCG_OPF_VECTOR)
|
||||
DEF(x86_vgf2p8affineqb_vec, 1, 2, 1, TCG_OPF_VECTOR)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef I386_TCG_TARGET_H
|
||||
#define I386_TCG_TARGET_H
|
||||
|
||||
#define TCG_TARGET_INSN_UNIT_SIZE 1
|
||||
|
||||
#define TCG_TARGET_NB_REGS 32
|
||||
#define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
|
||||
typedef enum {
|
||||
TCG_REG_EAX = 0,
|
||||
TCG_REG_ECX,
|
||||
TCG_REG_EDX,
|
||||
TCG_REG_EBX,
|
||||
TCG_REG_ESP,
|
||||
TCG_REG_EBP,
|
||||
TCG_REG_ESI,
|
||||
TCG_REG_EDI,
|
||||
|
||||
TCG_REG_R8,
|
||||
TCG_REG_R9,
|
||||
TCG_REG_R10,
|
||||
TCG_REG_R11,
|
||||
TCG_REG_R12,
|
||||
TCG_REG_R13,
|
||||
TCG_REG_R14,
|
||||
TCG_REG_R15,
|
||||
|
||||
TCG_REG_XMM0,
|
||||
TCG_REG_XMM1,
|
||||
TCG_REG_XMM2,
|
||||
TCG_REG_XMM3,
|
||||
TCG_REG_XMM4,
|
||||
TCG_REG_XMM5,
|
||||
TCG_REG_XMM6,
|
||||
TCG_REG_XMM7,
|
||||
TCG_REG_XMM8,
|
||||
TCG_REG_XMM9,
|
||||
TCG_REG_XMM10,
|
||||
TCG_REG_XMM11,
|
||||
TCG_REG_XMM12,
|
||||
TCG_REG_XMM13,
|
||||
TCG_REG_XMM14,
|
||||
TCG_REG_XMM15,
|
||||
|
||||
TCG_REG_RAX = TCG_REG_EAX,
|
||||
TCG_REG_RCX = TCG_REG_ECX,
|
||||
TCG_REG_RDX = TCG_REG_EDX,
|
||||
TCG_REG_RBX = TCG_REG_EBX,
|
||||
TCG_REG_RSP = TCG_REG_ESP,
|
||||
TCG_REG_RBP = TCG_REG_EBP,
|
||||
TCG_REG_RSI = TCG_REG_ESI,
|
||||
TCG_REG_RDI = TCG_REG_EDI,
|
||||
|
||||
TCG_AREG0 = TCG_REG_EBP,
|
||||
TCG_REG_CALL_STACK = TCG_REG_ESP
|
||||
} TCGReg;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user