1 | The following changes since commit 77f3804ab7ed94b471a14acb260e5aeacf26193f: | 1 | The following changes since commit 222059a0fccf4af3be776fe35a5ea2d6a68f9a0b: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging (2021-02-02 16:47:51 +0000) | 3 | Merge tag 'pull-ppc-20221221' of https://gitlab.com/danielhb/qemu into staging (2022-12-21 18:08:09 +0000) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | https://gitlab.com/rth7680/qemu.git tags/pull-tcg-20210202 | 7 | https://gitlab.com/rth7680/qemu.git tags/pull-tcg-20221229 |
8 | 8 | ||
9 | for you to fetch changes up to 0c823e596877a30fd6c17a1ae9f98218a53055ea: | 9 | for you to fetch changes up to b05e35533782a71a9fda472afd08442f50622a3e: |
10 | 10 | ||
11 | tcg: Remove TCG_TARGET_CON_SET_H (2021-02-02 12:12:43 -1000) | 11 | tests/tcg/multiarch: add vma-pthread.c (2022-12-29 12:39:45 -0800) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | TCG backend constraints cleanup | 14 | Fix race conditions in new user-only vma tracking. |
15 | Add tcg backend paired register allocation. | ||
16 | Cleanup tcg backend function call abi. | ||
15 | 17 | ||
16 | ---------------------------------------------------------------- | 18 | ---------------------------------------------------------------- |
17 | Richard Henderson (24): | 19 | Ilya Leoshkevich (1): |
18 | tcg/tci: Drop L and S constraints | 20 | tests/tcg/multiarch: add vma-pthread.c |
19 | tcg/tci: Remove TCG_TARGET_HAS_* ifdefs | ||
20 | tcg/i386: Move constraint type check to tcg_target_const_match | ||
21 | tcg/i386: Tidy register constraint definitions | ||
22 | tcg/i386: Split out target constraints to tcg-target-con-str.h | ||
23 | tcg/arm: Split out target constraints to tcg-target-con-str.h | ||
24 | tcg/aarch64: Split out target constraints to tcg-target-con-str.h | ||
25 | tcg/ppc: Split out target constraints to tcg-target-con-str.h | ||
26 | tcg/tci: Split out target constraints to tcg-target-con-str.h | ||
27 | tcg/mips: Split out target constraints to tcg-target-con-str.h | ||
28 | tcg/riscv: Split out target constraints to tcg-target-con-str.h | ||
29 | tcg/s390: Split out target constraints to tcg-target-con-str.h | ||
30 | tcg/sparc: Split out target constraints to tcg-target-con-str.h | ||
31 | tcg: Remove TCG_TARGET_CON_STR_H | ||
32 | tcg/i386: Split out constraint sets to tcg-target-con-set.h | ||
33 | tcg/aarch64: Split out constraint sets to tcg-target-con-set.h | ||
34 | tcg/arm: Split out constraint sets to tcg-target-con-set.h | ||
35 | tcg/mips: Split out constraint sets to tcg-target-con-set.h | ||
36 | tcg/ppc: Split out constraint sets to tcg-target-con-set.h | ||
37 | tcg/riscv: Split out constraint sets to tcg-target-con-set.h | ||
38 | tcg/s390: Split out constraint sets to tcg-target-con-set.h | ||
39 | tcg/sparc: Split out constraint sets to tcg-target-con-set.h | ||
40 | tcg/tci: Split out constraint sets to tcg-target-con-set.h | ||
41 | tcg: Remove TCG_TARGET_CON_SET_H | ||
42 | 21 | ||
43 | tcg/aarch64/tcg-target-con-set.h | 36 ++++ | 22 | Mark Cave-Ayland (1): |
44 | tcg/aarch64/tcg-target-con-str.h | 24 +++ | 23 | tcg: convert tcg/README to rst |
45 | tcg/arm/tcg-target-con-set.h | 35 ++++ | ||
46 | tcg/arm/tcg-target-con-str.h | 22 +++ | ||
47 | tcg/i386/tcg-target-con-set.h | 55 ++++++ | ||
48 | tcg/i386/tcg-target-con-str.h | 33 ++++ | ||
49 | tcg/mips/tcg-target-con-set.h | 36 ++++ | ||
50 | tcg/mips/tcg-target-con-str.h | 24 +++ | ||
51 | tcg/ppc/tcg-target-con-set.h | 42 +++++ | ||
52 | tcg/ppc/tcg-target-con-str.h | 30 ++++ | ||
53 | tcg/riscv/tcg-target-con-set.h | 30 ++++ | ||
54 | tcg/riscv/tcg-target-con-str.h | 21 +++ | ||
55 | tcg/s390/tcg-target-con-set.h | 29 ++++ | ||
56 | tcg/s390/tcg-target-con-str.h | 28 +++ | ||
57 | tcg/sparc/tcg-target-con-set.h | 32 ++++ | ||
58 | tcg/sparc/tcg-target-con-str.h | 23 +++ | ||
59 | tcg/sparc/tcg-target.h | 4 - | ||
60 | tcg/tci/tcg-target-con-set.h | 25 +++ | ||
61 | tcg/tci/tcg-target-con-str.h | 11 ++ | ||
62 | tcg/tcg.c | 136 +++++++++++++-- | ||
63 | tcg/aarch64/tcg-target.c.inc | 137 ++++----------- | ||
64 | tcg/arm/tcg-target.c.inc | 168 ++++++------------ | ||
65 | tcg/i386/tcg-target.c.inc | 317 +++++++++++----------------------- | ||
66 | tcg/mips/tcg-target.c.inc | 173 ++++++------------- | ||
67 | tcg/ppc/tcg-target.c.inc | 209 ++++++++--------------- | ||
68 | tcg/riscv/tcg-target.c.inc | 135 ++++----------- | ||
69 | tcg/s390/tcg-target.c.inc | 174 +++++++------------ | ||
70 | tcg/sparc/tcg-target.c.inc | 156 ++++++----------- | ||
71 | tcg/tci/tcg-target.c.inc | 359 ++++++++++++++------------------------- | ||
72 | 29 files changed, 1244 insertions(+), 1260 deletions(-) | ||
73 | create mode 100644 tcg/aarch64/tcg-target-con-set.h | ||
74 | create mode 100644 tcg/aarch64/tcg-target-con-str.h | ||
75 | create mode 100644 tcg/arm/tcg-target-con-set.h | ||
76 | create mode 100644 tcg/arm/tcg-target-con-str.h | ||
77 | create mode 100644 tcg/i386/tcg-target-con-set.h | ||
78 | create mode 100644 tcg/i386/tcg-target-con-str.h | ||
79 | create mode 100644 tcg/mips/tcg-target-con-set.h | ||
80 | create mode 100644 tcg/mips/tcg-target-con-str.h | ||
81 | create mode 100644 tcg/ppc/tcg-target-con-set.h | ||
82 | create mode 100644 tcg/ppc/tcg-target-con-str.h | ||
83 | create mode 100644 tcg/riscv/tcg-target-con-set.h | ||
84 | create mode 100644 tcg/riscv/tcg-target-con-str.h | ||
85 | create mode 100644 tcg/s390/tcg-target-con-set.h | ||
86 | create mode 100644 tcg/s390/tcg-target-con-str.h | ||
87 | create mode 100644 tcg/sparc/tcg-target-con-set.h | ||
88 | create mode 100644 tcg/sparc/tcg-target-con-str.h | ||
89 | create mode 100644 tcg/tci/tcg-target-con-set.h | ||
90 | create mode 100644 tcg/tci/tcg-target-con-str.h | ||
91 | 24 | ||
25 | Philippe Mathieu-Daudé (5): | ||
26 | tcg/s390x: Fix coding style | ||
27 | tcg: Massage process_op_defs() | ||
28 | tcg: Pass number of arguments to tcg_emit_op() / tcg_op_insert_*() | ||
29 | tcg: Convert typecode_to_ffi from array to function | ||
30 | tcg: Factor init_ffi_layouts() out of tcg_context_init() | ||
31 | |||
32 | Richard Henderson (40): | ||
33 | meson: Move CONFIG_TCG_INTERPRETER to config_host | ||
34 | tcg: Cleanup trailing whitespace | ||
35 | qemu/main-loop: Introduce QEMU_IOTHREAD_LOCK_GUARD | ||
36 | hw/mips: Use QEMU_IOTHREAD_LOCK_GUARD in cpu_mips_irq_request | ||
37 | target/ppc: Use QEMU_IOTHREAD_LOCK_GUARD in ppc_maybe_interrupt | ||
38 | target/ppc: Use QEMU_IOTHREAD_LOCK_GUARD in cpu_interrupt_exittb | ||
39 | target/riscv: Use QEMU_IOTHREAD_LOCK_GUARD in riscv_cpu_update_mip | ||
40 | hw/ppc: Use QEMU_IOTHREAD_LOCK_GUARD in ppc_set_irq | ||
41 | accel/tcg: Use QEMU_IOTHREAD_LOCK_GUARD in io_readx/io_writex | ||
42 | tcg: Tidy tcg_reg_alloc_op | ||
43 | tcg: Remove TCG_TARGET_STACK_GROWSUP | ||
44 | tci: MAX_OPC_PARAM_IARGS is no longer used | ||
45 | tcg: Fix tcg_reg_alloc_dup* | ||
46 | tcg: Centralize updates to reg_to_temp | ||
47 | tcg: Remove check_regs | ||
48 | tcg: Introduce paired register allocation | ||
49 | accel/tcg: Set cflags_next_tb in cpu_common_initfn | ||
50 | target/sparc: Avoid TCGV_{LOW,HIGH} | ||
51 | tcg: Move TCG_{LOW,HIGH} to tcg-internal.h | ||
52 | tcg: Add temp_subindex to TCGTemp | ||
53 | tcg: Simplify calls to temp_sync vs mem_coherent | ||
54 | tcg: Allocate TCGTemp pairs in host memory order | ||
55 | tcg: Move TCG_TYPE_COUNT outside enum | ||
56 | tcg: Introduce tcg_type_size | ||
57 | tcg: Introduce TCGCallReturnKind and TCGCallArgumentKind | ||
58 | tcg: Replace TCG_TARGET_CALL_ALIGN_ARGS with TCG_TARGET_CALL_ARG_I64 | ||
59 | tcg: Replace TCG_TARGET_EXTEND_ARGS with TCG_TARGET_CALL_ARG_I32 | ||
60 | tcg: Use TCG_CALL_ARG_EVEN for TCI special case | ||
61 | accel/tcg/plugin: Don't search for the function pointer index | ||
62 | accel/tcg/plugin: Avoid duplicate copy in copy_call | ||
63 | accel/tcg/plugin: Use copy_op in append_{udata,mem}_cb | ||
64 | tcg: Vary the allocation size for TCGOp | ||
65 | tcg: Use output_pref wrapper function | ||
66 | tcg: Reorg function calls | ||
67 | tcg: Move ffi_cif pointer into TCGHelperInfo | ||
68 | tcg/aarch64: Merge tcg_out_callr into tcg_out_call | ||
69 | tcg: Add TCGHelperInfo argument to tcg_out_call | ||
70 | accel/tcg: Fix tb_invalidate_phys_page_unwind | ||
71 | accel/tcg: Use g_free_rcu for user-exec interval trees | ||
72 | accel/tcg: Handle false negative lookup in page_check_range | ||
73 | |||
74 | docs/devel/atomics.rst | 2 + | ||
75 | docs/devel/index-tcg.rst | 1 + | ||
76 | docs/devel/tcg-ops.rst | 941 +++++++++++++++++++ | ||
77 | docs/devel/tcg.rst | 2 +- | ||
78 | meson.build | 4 +- | ||
79 | include/exec/helper-head.h | 2 +- | ||
80 | include/qemu/main-loop.h | 29 + | ||
81 | include/tcg/tcg-op.h | 35 +- | ||
82 | include/tcg/tcg.h | 96 +- | ||
83 | tcg/aarch64/tcg-target.h | 4 +- | ||
84 | tcg/arm/tcg-target.h | 4 +- | ||
85 | tcg/i386/tcg-target.h | 2 + | ||
86 | tcg/loongarch64/tcg-target.h | 3 +- | ||
87 | tcg/mips/tcg-target.h | 4 +- | ||
88 | tcg/riscv/tcg-target.h | 7 +- | ||
89 | tcg/s390x/tcg-target.h | 3 +- | ||
90 | tcg/sparc64/tcg-target.h | 3 +- | ||
91 | tcg/tcg-internal.h | 58 +- | ||
92 | tcg/tci/tcg-target.h | 7 + | ||
93 | tests/tcg/multiarch/nop_func.h | 25 + | ||
94 | accel/tcg/cputlb.c | 25 +- | ||
95 | accel/tcg/plugin-gen.c | 54 +- | ||
96 | accel/tcg/tb-maint.c | 78 +- | ||
97 | accel/tcg/user-exec.c | 59 +- | ||
98 | hw/core/cpu-common.c | 1 + | ||
99 | hw/mips/mips_int.c | 11 +- | ||
100 | hw/ppc/ppc.c | 10 +- | ||
101 | target/ppc/excp_helper.c | 11 +- | ||
102 | target/ppc/helper_regs.c | 14 +- | ||
103 | target/riscv/cpu_helper.c | 10 +- | ||
104 | target/sparc/translate.c | 21 +- | ||
105 | tcg/optimize.c | 10 +- | ||
106 | tcg/tcg-op-vec.c | 10 +- | ||
107 | tcg/tcg-op.c | 49 +- | ||
108 | tcg/tcg.c | 1658 +++++++++++++++++++++------------- | ||
109 | tcg/tci.c | 1 - | ||
110 | tests/tcg/multiarch/munmap-pthread.c | 16 +- | ||
111 | tests/tcg/multiarch/vma-pthread.c | 207 +++++ | ||
112 | tcg/aarch64/tcg-target.c.inc | 19 +- | ||
113 | tcg/arm/tcg-target.c.inc | 10 +- | ||
114 | tcg/i386/tcg-target.c.inc | 5 +- | ||
115 | tcg/loongarch64/tcg-target.c.inc | 7 +- | ||
116 | tcg/mips/tcg-target.c.inc | 3 +- | ||
117 | tcg/ppc/tcg-target.c.inc | 36 +- | ||
118 | tcg/riscv/tcg-target.c.inc | 7 +- | ||
119 | tcg/s390x/tcg-target.c.inc | 32 +- | ||
120 | tcg/sparc64/tcg-target.c.inc | 3 +- | ||
121 | tcg/tci/tcg-target.c.inc | 7 +- | ||
122 | tcg/README | 784 ---------------- | ||
123 | tests/tcg/multiarch/Makefile.target | 3 + | ||
124 | 50 files changed, 2630 insertions(+), 1763 deletions(-) | ||
125 | create mode 100644 docs/devel/tcg-ops.rst | ||
126 | create mode 100644 tests/tcg/multiarch/nop_func.h | ||
127 | create mode 100644 tests/tcg/multiarch/vma-pthread.c | ||
128 | delete mode 100644 tcg/README | ||
129 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> | ||
1 | 2 | ||
3 | Convert tcg/README to rst and move it to docs/devel as a new "TCG Intermediate | ||
4 | Representation" page. There are a few minor changes to improve the aesthetic | ||
5 | of the final output which are as follows: | ||
6 | |||
7 | - Rename the title from "Tiny Code Generator - Fabrice Bellard" to "TCG | ||
8 | Intermediate Representation" | ||
9 | |||
10 | - Remove the section numbering | ||
11 | |||
12 | - Add the missing parameters to the ssadd_vec operations in the "Host | ||
13 | vector operations" section | ||
14 | |||
15 | - Change the path to the Atomic Operations document to use a proper | ||
16 | reference | ||
17 | |||
18 | - Replace tcg/README in tcg.rst with a proper reference to the new document | ||
19 | |||
20 | Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> | ||
21 | Reviewed-by: Fabiano Rosas <farosas@suse.de> | ||
22 | Message-Id: <20221130100434.64207-2-mark.cave-ayland@ilande.co.uk> | ||
23 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
24 | --- | ||
25 | docs/devel/atomics.rst | 2 + | ||
26 | docs/devel/index-tcg.rst | 1 + | ||
27 | docs/devel/tcg-ops.rst | 941 +++++++++++++++++++++++++++++++++++++++ | ||
28 | docs/devel/tcg.rst | 2 +- | ||
29 | tcg/README | 784 -------------------------------- | ||
30 | 5 files changed, 945 insertions(+), 785 deletions(-) | ||
31 | create mode 100644 docs/devel/tcg-ops.rst | ||
32 | delete mode 100644 tcg/README | ||
33 | |||
34 | diff --git a/docs/devel/atomics.rst b/docs/devel/atomics.rst | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/docs/devel/atomics.rst | ||
37 | +++ b/docs/devel/atomics.rst | ||
38 | @@ -XXX,XX +XXX,XX @@ | ||
39 | +.. _atomics-ref: | ||
40 | + | ||
41 | ========================= | ||
42 | Atomic operations in QEMU | ||
43 | ========================= | ||
44 | diff --git a/docs/devel/index-tcg.rst b/docs/devel/index-tcg.rst | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/docs/devel/index-tcg.rst | ||
47 | +++ b/docs/devel/index-tcg.rst | ||
48 | @@ -XXX,XX +XXX,XX @@ are only implementing things for HW accelerated hypervisors. | ||
49 | :maxdepth: 2 | ||
50 | |||
51 | tcg | ||
52 | + tcg-ops | ||
53 | decodetree | ||
54 | multi-thread-tcg | ||
55 | tcg-icount | ||
56 | diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst | ||
57 | new file mode 100644 | ||
58 | index XXXXXXX..XXXXXXX | ||
59 | --- /dev/null | ||
60 | +++ b/docs/devel/tcg-ops.rst | ||
61 | @@ -XXX,XX +XXX,XX @@ | ||
62 | +.. _tcg-ops-ref: | ||
63 | + | ||
64 | +******************************* | ||
65 | +TCG Intermediate Representation | ||
66 | +******************************* | ||
67 | + | ||
68 | +Introduction | ||
69 | +============ | ||
70 | + | ||
71 | +TCG (Tiny Code Generator) began as a generic backend for a C | ||
72 | +compiler. It was simplified to be used in QEMU. It also has its roots | ||
73 | +in the QOP code generator written by Paul Brook. | ||
74 | + | ||
75 | +Definitions | ||
76 | +=========== | ||
77 | + | ||
78 | +TCG receives RISC-like *TCG ops* and performs some optimizations on them, | ||
79 | +including liveness analysis and trivial constant expression | ||
80 | +evaluation. TCG ops are then implemented in the host CPU back end, | ||
81 | +also known as the TCG target. | ||
82 | + | ||
83 | +The TCG *target* is the architecture for which we generate the | ||
84 | +code. It is of course not the same as the "target" of QEMU which is | ||
85 | +the emulated architecture. As TCG started as a generic C backend used | ||
86 | +for cross compiling, it is assumed that the TCG target is different | ||
87 | +from the host, although it is never the case for QEMU. | ||
88 | + | ||
89 | +In this document, we use *guest* to specify what architecture we are | ||
90 | +emulating; *target* always means the TCG target, the machine on which | ||
91 | +we are running QEMU. | ||
92 | + | ||
93 | +A TCG *function* corresponds to a QEMU Translated Block (TB). | ||
94 | + | ||
95 | +A TCG *temporary* is a variable only live in a basic block. Temporaries are allocated explicitly in each function. | ||
96 | + | ||
97 | +A TCG *local temporary* is a variable only live in a function. Local temporaries are allocated explicitly in each function. | ||
98 | + | ||
99 | +A TCG *global* is a variable which is live in all the functions | ||
100 | +(equivalent of a C global variable). They are defined before the | ||
101 | +functions defined. A TCG global can be a memory location (e.g. a QEMU | ||
102 | +CPU register), a fixed host register (e.g. the QEMU CPU state pointer) | ||
103 | +or a memory location which is stored in a register outside QEMU TBs | ||
104 | +(not implemented yet). | ||
105 | + | ||
106 | +A TCG *basic block* corresponds to a list of instructions terminated | ||
107 | +by a branch instruction. | ||
108 | + | ||
109 | +An operation with *undefined behavior* may result in a crash. | ||
110 | + | ||
111 | +An operation with *unspecified behavior* shall not crash. However, | ||
112 | +the result may be one of several possibilities so may be considered | ||
113 | +an *undefined result*. | ||
114 | + | ||
115 | +Intermediate representation | ||
116 | +=========================== | ||
117 | + | ||
118 | +Introduction | ||
119 | +------------ | ||
120 | + | ||
121 | +TCG instructions operate on variables which are temporaries, local | ||
122 | +temporaries or globals. TCG instructions and variables are strongly | ||
123 | +typed. Two types are supported: 32 bit integers and 64 bit | ||
124 | +integers. Pointers are defined as an alias to 32 bit or 64 bit | ||
125 | +integers depending on the TCG target word size. | ||
126 | + | ||
127 | +Each instruction has a fixed number of output variable operands, input | ||
128 | +variable operands and always constant operands. | ||
129 | + | ||
130 | +The notable exception is the call instruction which has a variable | ||
131 | +number of outputs and inputs. | ||
132 | + | ||
133 | +In the textual form, output operands usually come first, followed by | ||
134 | +input operands, followed by constant operands. The output type is | ||
135 | +included in the instruction name. Constants are prefixed with a '$'. | ||
136 | + | ||
137 | +.. code-block:: none | ||
138 | + | ||
139 | + add_i32 t0, t1, t2 /* (t0 <- t1 + t2) */ | ||
140 | + | ||
141 | + | ||
142 | +Assumptions | ||
143 | +----------- | ||
144 | + | ||
145 | +Basic blocks | ||
146 | +^^^^^^^^^^^^ | ||
147 | + | ||
148 | +* Basic blocks end after branches (e.g. brcond_i32 instruction), | ||
149 | + goto_tb and exit_tb instructions. | ||
150 | + | ||
151 | +* Basic blocks start after the end of a previous basic block, or at a | ||
152 | + set_label instruction. | ||
153 | + | ||
154 | +After the end of a basic block, the content of temporaries is | ||
155 | +destroyed, but local temporaries and globals are preserved. | ||
156 | + | ||
157 | +Floating point types | ||
158 | +^^^^^^^^^^^^^^^^^^^^ | ||
159 | + | ||
160 | +* Floating point types are not supported yet | ||
161 | + | ||
162 | +Pointers | ||
163 | +^^^^^^^^ | ||
164 | + | ||
165 | +* Depending on the TCG target, pointer size is 32 bit or 64 | ||
166 | + bit. The type ``TCG_TYPE_PTR`` is an alias to ``TCG_TYPE_I32`` or | ||
167 | + ``TCG_TYPE_I64``. | ||
168 | + | ||
169 | +Helpers | ||
170 | +^^^^^^^ | ||
171 | + | ||
172 | +* Using the tcg_gen_helper_x_y it is possible to call any function | ||
173 | + taking i32, i64 or pointer types. By default, before calling a helper, | ||
174 | + all globals are stored at their canonical location and it is assumed | ||
175 | + that the function can modify them. By default, the helper is allowed to | ||
176 | + modify the CPU state or raise an exception. | ||
177 | + | ||
178 | + This can be overridden using the following function modifiers: | ||
179 | + | ||
180 | + - ``TCG_CALL_NO_READ_GLOBALS`` means that the helper does not read globals, | ||
181 | + either directly or via an exception. They will not be saved to their | ||
182 | + canonical locations before calling the helper. | ||
183 | + | ||
184 | + - ``TCG_CALL_NO_WRITE_GLOBALS`` means that the helper does not modify any globals. | ||
185 | + They will only be saved to their canonical location before calling helpers, | ||
186 | + but they won't be reloaded afterwards. | ||
187 | + | ||
188 | + - ``TCG_CALL_NO_SIDE_EFFECTS`` means that the call to the function is removed if | ||
189 | + the return value is not used. | ||
190 | + | ||
191 | + Note that ``TCG_CALL_NO_READ_GLOBALS`` implies ``TCG_CALL_NO_WRITE_GLOBALS``. | ||
192 | + | ||
193 | + On some TCG targets (e.g. x86), several calling conventions are | ||
194 | + supported. | ||
195 | + | ||
196 | +Branches | ||
197 | +^^^^^^^^ | ||
198 | + | ||
199 | +* Use the instruction 'br' to jump to a label. | ||
200 | + | ||
201 | +Code Optimizations | ||
202 | +------------------ | ||
203 | + | ||
204 | +When generating instructions, you can count on at least the following | ||
205 | +optimizations: | ||
206 | + | ||
207 | +- Single instructions are simplified, e.g. | ||
208 | + | ||
209 | + .. code-block:: none | ||
210 | + | ||
211 | + and_i32 t0, t0, $0xffffffff | ||
212 | + | ||
213 | + is suppressed. | ||
214 | + | ||
215 | +- A liveness analysis is done at the basic block level. The | ||
216 | + information is used to suppress moves from a dead variable to | ||
217 | + another one. It is also used to remove instructions which compute | ||
218 | + dead results. The later is especially useful for condition code | ||
219 | + optimization in QEMU. | ||
220 | + | ||
221 | + In the following example: | ||
222 | + | ||
223 | + .. code-block:: none | ||
224 | + | ||
225 | + add_i32 t0, t1, t2 | ||
226 | + add_i32 t0, t0, $1 | ||
227 | + mov_i32 t0, $1 | ||
228 | + | ||
229 | + only the last instruction is kept. | ||
230 | + | ||
231 | + | ||
232 | +Instruction Reference | ||
233 | +===================== | ||
234 | + | ||
235 | +Function call | ||
236 | +------------- | ||
237 | + | ||
238 | +.. list-table:: | ||
239 | + | ||
240 | + * - call *<ret>* *<params>* ptr | ||
241 | + | ||
242 | + - | call function 'ptr' (pointer type) | ||
243 | + | | ||
244 | + | *<ret>* optional 32 bit or 64 bit return value | ||
245 | + | *<params>* optional 32 bit or 64 bit parameters | ||
246 | + | ||
247 | +Jumps/Labels | ||
248 | +------------ | ||
249 | + | ||
250 | +.. list-table:: | ||
251 | + | ||
252 | + * - set_label $label | ||
253 | + | ||
254 | + - | Define label 'label' at the current program point. | ||
255 | + | ||
256 | + * - br $label | ||
257 | + | ||
258 | + - | Jump to label. | ||
259 | + | ||
260 | + * - brcond_i32/i64 *t0*, *t1*, *cond*, *label* | ||
261 | + | ||
262 | + - | Conditional jump if *t0* *cond* *t1* is true. *cond* can be: | ||
263 | + | | ||
264 | + | ``TCG_COND_EQ`` | ||
265 | + | ``TCG_COND_NE`` | ||
266 | + | ``TCG_COND_LT /* signed */`` | ||
267 | + | ``TCG_COND_GE /* signed */`` | ||
268 | + | ``TCG_COND_LE /* signed */`` | ||
269 | + | ``TCG_COND_GT /* signed */`` | ||
270 | + | ``TCG_COND_LTU /* unsigned */`` | ||
271 | + | ``TCG_COND_GEU /* unsigned */`` | ||
272 | + | ``TCG_COND_LEU /* unsigned */`` | ||
273 | + | ``TCG_COND_GTU /* unsigned */`` | ||
274 | + | ||
275 | +Arithmetic | ||
276 | +---------- | ||
277 | + | ||
278 | +.. list-table:: | ||
279 | + | ||
280 | + * - add_i32/i64 *t0*, *t1*, *t2* | ||
281 | + | ||
282 | + - | *t0* = *t1* + *t2* | ||
283 | + | ||
284 | + * - sub_i32/i64 *t0*, *t1*, *t2* | ||
285 | + | ||
286 | + - | *t0* = *t1* - *t2* | ||
287 | + | ||
288 | + * - neg_i32/i64 *t0*, *t1* | ||
289 | + | ||
290 | + - | *t0* = -*t1* (two's complement) | ||
291 | + | ||
292 | + * - mul_i32/i64 *t0*, *t1*, *t2* | ||
293 | + | ||
294 | + - | *t0* = *t1* * *t2* | ||
295 | + | ||
296 | + * - div_i32/i64 *t0*, *t1*, *t2* | ||
297 | + | ||
298 | + - | *t0* = *t1* / *t2* (signed) | ||
299 | + | Undefined behavior if division by zero or overflow. | ||
300 | + | ||
301 | + * - divu_i32/i64 *t0*, *t1*, *t2* | ||
302 | + | ||
303 | + - | *t0* = *t1* / *t2* (unsigned) | ||
304 | + | Undefined behavior if division by zero. | ||
305 | + | ||
306 | + * - rem_i32/i64 *t0*, *t1*, *t2* | ||
307 | + | ||
308 | + - | *t0* = *t1* % *t2* (signed) | ||
309 | + | Undefined behavior if division by zero or overflow. | ||
310 | + | ||
311 | + * - remu_i32/i64 *t0*, *t1*, *t2* | ||
312 | + | ||
313 | + - | *t0* = *t1* % *t2* (unsigned) | ||
314 | + | Undefined behavior if division by zero. | ||
315 | + | ||
316 | + | ||
317 | +Logical | ||
318 | +------- | ||
319 | + | ||
320 | +.. list-table:: | ||
321 | + | ||
322 | + * - and_i32/i64 *t0*, *t1*, *t2* | ||
323 | + | ||
324 | + - | *t0* = *t1* & *t2* | ||
325 | + | ||
326 | + * - or_i32/i64 *t0*, *t1*, *t2* | ||
327 | + | ||
328 | + - | *t0* = *t1* | *t2* | ||
329 | + | ||
330 | + * - xor_i32/i64 *t0*, *t1*, *t2* | ||
331 | + | ||
332 | + - | *t0* = *t1* ^ *t2* | ||
333 | + | ||
334 | + * - not_i32/i64 *t0*, *t1* | ||
335 | + | ||
336 | + - | *t0* = ~\ *t1* | ||
337 | + | ||
338 | + * - andc_i32/i64 *t0*, *t1*, *t2* | ||
339 | + | ||
340 | + - | *t0* = *t1* & ~\ *t2* | ||
341 | + | ||
342 | + * - eqv_i32/i64 *t0*, *t1*, *t2* | ||
343 | + | ||
344 | + - | *t0* = ~(*t1* ^ *t2*), or equivalently, *t0* = *t1* ^ ~\ *t2* | ||
345 | + | ||
346 | + * - nand_i32/i64 *t0*, *t1*, *t2* | ||
347 | + | ||
348 | + - | *t0* = ~(*t1* & *t2*) | ||
349 | + | ||
350 | + * - nor_i32/i64 *t0*, *t1*, *t2* | ||
351 | + | ||
352 | + - | *t0* = ~(*t1* | *t2*) | ||
353 | + | ||
354 | + * - orc_i32/i64 *t0*, *t1*, *t2* | ||
355 | + | ||
356 | + - | *t0* = *t1* | ~\ *t2* | ||
357 | + | ||
358 | + * - clz_i32/i64 *t0*, *t1*, *t2* | ||
359 | + | ||
360 | + - | *t0* = *t1* ? clz(*t1*) : *t2* | ||
361 | + | ||
362 | + * - ctz_i32/i64 *t0*, *t1*, *t2* | ||
363 | + | ||
364 | + - | *t0* = *t1* ? ctz(*t1*) : *t2* | ||
365 | + | ||
366 | + * - ctpop_i32/i64 *t0*, *t1* | ||
367 | + | ||
368 | + - | *t0* = number of bits set in *t1* | ||
369 | + | | ||
370 | + | With *ctpop* short for "count population", matching | ||
371 | + | the function name used in ``include/qemu/host-utils.h``. | ||
372 | + | ||
373 | + | ||
374 | +Shifts/Rotates | ||
375 | +-------------- | ||
376 | + | ||
377 | +.. list-table:: | ||
378 | + | ||
379 | + * - shl_i32/i64 *t0*, *t1*, *t2* | ||
380 | + | ||
381 | + - | *t0* = *t1* << *t2* | ||
382 | + | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) | ||
383 | + | ||
384 | + * - shr_i32/i64 *t0*, *t1*, *t2* | ||
385 | + | ||
386 | + - | *t0* = *t1* >> *t2* (unsigned) | ||
387 | + | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) | ||
388 | + | ||
389 | + * - sar_i32/i64 *t0*, *t1*, *t2* | ||
390 | + | ||
391 | + - | *t0* = *t1* >> *t2* (signed) | ||
392 | + | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) | ||
393 | + | ||
394 | + * - rotl_i32/i64 *t0*, *t1*, *t2* | ||
395 | + | ||
396 | + - | Rotation of *t2* bits to the left | ||
397 | + | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) | ||
398 | + | ||
399 | + * - rotr_i32/i64 *t0*, *t1*, *t2* | ||
400 | + | ||
401 | + - | Rotation of *t2* bits to the right. | ||
402 | + | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) | ||
403 | + | ||
404 | + | ||
405 | +Misc | ||
406 | +---- | ||
407 | + | ||
408 | +.. list-table:: | ||
409 | + | ||
410 | + * - mov_i32/i64 *t0*, *t1* | ||
411 | + | ||
412 | + - | *t0* = *t1* | ||
413 | + | Move *t1* to *t0* (both operands must have the same type). | ||
414 | + | ||
415 | + * - ext8s_i32/i64 *t0*, *t1* | ||
416 | + | ||
417 | + ext8u_i32/i64 *t0*, *t1* | ||
418 | + | ||
419 | + ext16s_i32/i64 *t0*, *t1* | ||
420 | + | ||
421 | + ext16u_i32/i64 *t0*, *t1* | ||
422 | + | ||
423 | + ext32s_i64 *t0*, *t1* | ||
424 | + | ||
425 | + ext32u_i64 *t0*, *t1* | ||
426 | + | ||
427 | + - | 8, 16 or 32 bit sign/zero extension (both operands must have the same type) | ||
428 | + | ||
429 | + * - bswap16_i32/i64 *t0*, *t1*, *flags* | ||
430 | + | ||
431 | + - | 16 bit byte swap on the low bits of a 32/64 bit input. | ||
432 | + | | ||
433 | + | If *flags* & ``TCG_BSWAP_IZ``, then *t1* is known to be zero-extended from bit 15. | ||
434 | + | If *flags* & ``TCG_BSWAP_OZ``, then *t0* will be zero-extended from bit 15. | ||
435 | + | If *flags* & ``TCG_BSWAP_OS``, then *t0* will be sign-extended from bit 15. | ||
436 | + | | ||
437 | + | If neither ``TCG_BSWAP_OZ`` nor ``TCG_BSWAP_OS`` are set, then the bits of *t0* above bit 15 may contain any value. | ||
438 | + | ||
439 | + * - bswap32_i64 *t0*, *t1*, *flags* | ||
440 | + | ||
441 | + - | 32 bit byte swap on a 64-bit value. The flags are the same as for bswap16, | ||
442 | + except they apply from bit 31 instead of bit 15. | ||
443 | + | ||
444 | + * - bswap32_i32 *t0*, *t1*, *flags* | ||
445 | + | ||
446 | + bswap64_i64 *t0*, *t1*, *flags* | ||
447 | + | ||
448 | + - | 32/64 bit byte swap. The flags are ignored, but still present | ||
449 | + for consistency with the other bswap opcodes. | ||
450 | + | ||
451 | + * - discard_i32/i64 *t0* | ||
452 | + | ||
453 | + - | Indicate that the value of *t0* won't be used later. It is useful to | ||
454 | + force dead code elimination. | ||
455 | + | ||
456 | + * - deposit_i32/i64 *dest*, *t1*, *t2*, *pos*, *len* | ||
457 | + | ||
458 | + - | Deposit *t2* as a bitfield into *t1*, placing the result in *dest*. | ||
459 | + | | ||
460 | + | The bitfield is described by *pos*/*len*, which are immediate values: | ||
461 | + | | ||
462 | + | *len* - the length of the bitfield | ||
463 | + | *pos* - the position of the first bit, counting from the LSB | ||
464 | + | | ||
465 | + | For example, "deposit_i32 dest, t1, t2, 8, 4" indicates a 4-bit field | ||
466 | + at bit 8. This operation would be equivalent to | ||
467 | + | | ||
468 | + | *dest* = (*t1* & ~0x0f00) | ((*t2* << 8) & 0x0f00) | ||
469 | + | ||
470 | + * - extract_i32/i64 *dest*, *t1*, *pos*, *len* | ||
471 | + | ||
472 | + sextract_i32/i64 *dest*, *t1*, *pos*, *len* | ||
473 | + | ||
474 | + - | Extract a bitfield from *t1*, placing the result in *dest*. | ||
475 | + | | ||
476 | + | The bitfield is described by *pos*/*len*, which are immediate values, | ||
477 | + as above for deposit. For extract_*, the result will be extended | ||
478 | + to the left with zeros; for sextract_*, the result will be extended | ||
479 | + to the left with copies of the bitfield sign bit at *pos* + *len* - 1. | ||
480 | + | | ||
481 | + | For example, "sextract_i32 dest, t1, 8, 4" indicates a 4-bit field | ||
482 | + at bit 8. This operation would be equivalent to | ||
483 | + | | ||
484 | + | *dest* = (*t1* << 20) >> 28 | ||
485 | + | | ||
486 | + | (using an arithmetic right shift). | ||
487 | + | ||
488 | + * - extract2_i32/i64 *dest*, *t1*, *t2*, *pos* | ||
489 | + | ||
490 | + - | For N = {32,64}, extract an N-bit quantity from the concatenation | ||
491 | + of *t2*:*t1*, beginning at *pos*. The tcg_gen_extract2_{i32,i64} expander | ||
492 | + accepts 0 <= *pos* <= N as inputs. The backend code generator will | ||
493 | + not see either 0 or N as inputs for these opcodes. | ||
494 | + | ||
495 | + * - extrl_i64_i32 *t0*, *t1* | ||
496 | + | ||
497 | + - | For 64-bit hosts only, extract the low 32-bits of input *t1* and place it | ||
498 | + into 32-bit output *t0*. Depending on the host, this may be a simple move, | ||
499 | + or may require additional canonicalization. | ||
500 | + | ||
501 | + * - extrh_i64_i32 *t0*, *t1* | ||
502 | + | ||
503 | + - | For 64-bit hosts only, extract the high 32-bits of input *t1* and place it | ||
504 | + into 32-bit output *t0*. Depending on the host, this may be a simple shift, | ||
505 | + or may require additional canonicalization. | ||
506 | + | ||
507 | + | ||
508 | +Conditional moves | ||
509 | +----------------- | ||
510 | + | ||
511 | +.. list-table:: | ||
512 | + | ||
513 | + * - setcond_i32/i64 *dest*, *t1*, *t2*, *cond* | ||
514 | + | ||
515 | + - | *dest* = (*t1* *cond* *t2*) | ||
516 | + | | ||
517 | + | Set *dest* to 1 if (*t1* *cond* *t2*) is true, otherwise set to 0. | ||
518 | + | ||
519 | + * - movcond_i32/i64 *dest*, *c1*, *c2*, *v1*, *v2*, *cond* | ||
520 | + | ||
521 | + - | *dest* = (*c1* *cond* *c2* ? *v1* : *v2*) | ||
522 | + | | ||
523 | + | Set *dest* to *v1* if (*c1* *cond* *c2*) is true, otherwise set to *v2*. | ||
524 | + | ||
525 | + | ||
526 | +Type conversions | ||
527 | +---------------- | ||
528 | + | ||
529 | +.. list-table:: | ||
530 | + | ||
531 | + * - ext_i32_i64 *t0*, *t1* | ||
532 | + | ||
533 | + - | Convert *t1* (32 bit) to *t0* (64 bit) and does sign extension | ||
534 | + | ||
535 | + * - extu_i32_i64 *t0*, *t1* | ||
536 | + | ||
537 | + - | Convert *t1* (32 bit) to *t0* (64 bit) and does zero extension | ||
538 | + | ||
539 | + * - trunc_i64_i32 *t0*, *t1* | ||
540 | + | ||
541 | + - | Truncate *t1* (64 bit) to *t0* (32 bit) | ||
542 | + | ||
543 | + * - concat_i32_i64 *t0*, *t1*, *t2* | ||
544 | + | ||
545 | + - | Construct *t0* (64-bit) taking the low half from *t1* (32 bit) and the high half | ||
546 | + from *t2* (32 bit). | ||
547 | + | ||
548 | + * - concat32_i64 *t0*, *t1*, *t2* | ||
549 | + | ||
550 | + - | Construct *t0* (64-bit) taking the low half from *t1* (64 bit) and the high half | ||
551 | + from *t2* (64 bit). | ||
552 | + | ||
553 | + | ||
554 | +Load/Store | ||
555 | +---------- | ||
556 | + | ||
557 | +.. list-table:: | ||
558 | + | ||
559 | + * - ld_i32/i64 *t0*, *t1*, *offset* | ||
560 | + | ||
561 | + ld8s_i32/i64 *t0*, *t1*, *offset* | ||
562 | + | ||
563 | + ld8u_i32/i64 *t0*, *t1*, *offset* | ||
564 | + | ||
565 | + ld16s_i32/i64 *t0*, *t1*, *offset* | ||
566 | + | ||
567 | + ld16u_i32/i64 *t0*, *t1*, *offset* | ||
568 | + | ||
569 | + ld32s_i64 t0, *t1*, *offset* | ||
570 | + | ||
571 | + ld32u_i64 t0, *t1*, *offset* | ||
572 | + | ||
573 | + - | *t0* = read(*t1* + *offset*) | ||
574 | + | | ||
575 | + | Load 8, 16, 32 or 64 bits with or without sign extension from host memory. | ||
576 | + *offset* must be a constant. | ||
577 | + | ||
578 | + * - st_i32/i64 *t0*, *t1*, *offset* | ||
579 | + | ||
580 | + st8_i32/i64 *t0*, *t1*, *offset* | ||
581 | + | ||
582 | + st16_i32/i64 *t0*, *t1*, *offset* | ||
583 | + | ||
584 | + st32_i64 *t0*, *t1*, *offset* | ||
585 | + | ||
586 | + - | write(*t0*, *t1* + *offset*) | ||
587 | + | | ||
588 | + | Write 8, 16, 32 or 64 bits to host memory. | ||
589 | + | ||
590 | +All this opcodes assume that the pointed host memory doesn't correspond | ||
591 | +to a global. In the latter case the behaviour is unpredictable. | ||
592 | + | ||
593 | + | ||
594 | +Multiword arithmetic support | ||
595 | +---------------------------- | ||
596 | + | ||
597 | +.. list-table:: | ||
598 | + | ||
599 | + * - add2_i32/i64 *t0_low*, *t0_high*, *t1_low*, *t1_high*, *t2_low*, *t2_high* | ||
600 | + | ||
601 | + sub2_i32/i64 *t0_low*, *t0_high*, *t1_low*, *t1_high*, *t2_low*, *t2_high* | ||
602 | + | ||
603 | + - | Similar to add/sub, except that the double-word inputs *t1* and *t2* are | ||
604 | + formed from two single-word arguments, and the double-word output *t0* | ||
605 | + is returned in two single-word outputs. | ||
606 | + | ||
607 | + * - mulu2_i32/i64 *t0_low*, *t0_high*, *t1*, *t2* | ||
608 | + | ||
609 | + - | Similar to mul, except two unsigned inputs *t1* and *t2* yielding the full | ||
610 | + double-word product *t0*. The latter is returned in two single-word outputs. | ||
611 | + | ||
612 | + * - muls2_i32/i64 *t0_low*, *t0_high*, *t1*, *t2* | ||
613 | + | ||
614 | + - | Similar to mulu2, except the two inputs *t1* and *t2* are signed. | ||
615 | + | ||
616 | + * - mulsh_i32/i64 *t0*, *t1*, *t2* | ||
617 | + | ||
618 | + muluh_i32/i64 *t0*, *t1*, *t2* | ||
619 | + | ||
620 | + - | Provide the high part of a signed or unsigned multiply, respectively. | ||
621 | + | | ||
622 | + | If mulu2/muls2 are not provided by the backend, the tcg-op generator | ||
623 | + can obtain the same results by emitting a pair of opcodes, mul + muluh/mulsh. | ||
624 | + | ||
625 | + | ||
626 | +Memory Barrier support | ||
627 | +---------------------- | ||
628 | + | ||
629 | +.. list-table:: | ||
630 | + | ||
631 | + * - mb *<$arg>* | ||
632 | + | ||
633 | + - | Generate a target memory barrier instruction to ensure memory ordering | ||
634 | + as being enforced by a corresponding guest memory barrier instruction. | ||
635 | + | | ||
636 | + | The ordering enforced by the backend may be stricter than the ordering | ||
637 | + required by the guest. It cannot be weaker. This opcode takes a constant | ||
638 | + argument which is required to generate the appropriate barrier | ||
639 | + instruction. The backend should take care to emit the target barrier | ||
640 | + instruction only when necessary i.e., for SMP guests and when MTTCG is | ||
641 | + enabled. | ||
642 | + | | ||
643 | + | The guest translators should generate this opcode for all guest instructions | ||
644 | + which have ordering side effects. | ||
645 | + | | ||
646 | + | Please see :ref:`atomics-ref` for more information on memory barriers. | ||
647 | + | ||
648 | + | ||
649 | +64-bit guest on 32-bit host support | ||
650 | +----------------------------------- | ||
651 | + | ||
652 | +The following opcodes are internal to TCG. Thus they are to be implemented by | ||
653 | +32-bit host code generators, but are not to be emitted by guest translators. | ||
654 | +They are emitted as needed by inline functions within ``tcg-op.h``. | ||
655 | + | ||
656 | +.. list-table:: | ||
657 | + | ||
658 | + * - brcond2_i32 *t0_low*, *t0_high*, *t1_low*, *t1_high*, *cond*, *label* | ||
659 | + | ||
660 | + - | Similar to brcond, except that the 64-bit values *t0* and *t1* | ||
661 | + are formed from two 32-bit arguments. | ||
662 | + | ||
663 | + * - setcond2_i32 *dest*, *t1_low*, *t1_high*, *t2_low*, *t2_high*, *cond* | ||
664 | + | ||
665 | + - | Similar to setcond, except that the 64-bit values *t1* and *t2* are | ||
666 | + formed from two 32-bit arguments. The result is a 32-bit value. | ||
667 | + | ||
668 | + | ||
669 | +QEMU specific operations | ||
670 | +------------------------ | ||
671 | + | ||
672 | +.. list-table:: | ||
673 | + | ||
674 | + * - exit_tb *t0* | ||
675 | + | ||
676 | + - | Exit the current TB and return the value *t0* (word type). | ||
677 | + | ||
678 | + * - goto_tb *index* | ||
679 | + | ||
680 | + - | Exit the current TB and jump to the TB index *index* (constant) if the | ||
681 | + current TB was linked to this TB. Otherwise execute the next | ||
682 | + instructions. Only indices 0 and 1 are valid and tcg_gen_goto_tb may be issued | ||
683 | + at most once with each slot index per TB. | ||
684 | + | ||
685 | + * - lookup_and_goto_ptr *tb_addr* | ||
686 | + | ||
687 | + - | Look up a TB address *tb_addr* and jump to it if valid. If not valid, | ||
688 | + jump to the TCG epilogue to go back to the exec loop. | ||
689 | + | | ||
690 | + | This operation is optional. If the TCG backend does not implement the | ||
691 | + goto_ptr opcode, emitting this op is equivalent to emitting exit_tb(0). | ||
692 | + | ||
693 | + * - qemu_ld_i32/i64 *t0*, *t1*, *flags*, *memidx* | ||
694 | + | ||
695 | + qemu_st_i32/i64 *t0*, *t1*, *flags*, *memidx* | ||
696 | + | ||
697 | + qemu_st8_i32 *t0*, *t1*, *flags*, *memidx* | ||
698 | + | ||
699 | + - | Load data at the guest address *t1* into *t0*, or store data in *t0* at guest | ||
700 | + address *t1*. The _i32/_i64 size applies to the size of the input/output | ||
701 | + register *t0* only. The address *t1* is always sized according to the guest, | ||
702 | + and the width of the memory operation is controlled by *flags*. | ||
703 | + | | ||
704 | + | Both *t0* and *t1* may be split into little-endian ordered pairs of registers | ||
705 | + if dealing with 64-bit quantities on a 32-bit host. | ||
706 | + | | ||
707 | + | The *memidx* selects the qemu tlb index to use (e.g. user or kernel access). | ||
708 | + The flags are the MemOp bits, selecting the sign, width, and endianness | ||
709 | + of the memory access. | ||
710 | + | | ||
711 | + | For a 32-bit host, qemu_ld/st_i64 is guaranteed to only be used with a | ||
712 | + 64-bit memory access specified in *flags*. | ||
713 | + | | ||
714 | + | For i386, qemu_st8_i32 is exactly like qemu_st_i32, except the size of | ||
715 | + the memory operation is known to be 8-bit. This allows the backend to | ||
716 | + provide a different set of register constraints. | ||
717 | + | ||
718 | + | ||
719 | +Host vector operations | ||
720 | +---------------------- | ||
721 | + | ||
722 | +All of the vector ops have two parameters, ``TCGOP_VECL`` & ``TCGOP_VECE``. | ||
723 | +The former specifies the length of the vector in log2 64-bit units; the | ||
724 | +latter specifies the length of the element (if applicable) in log2 8-bit units. | ||
725 | +E.g. VECL = 1 -> 64 << 1 -> v128, and VECE = 2 -> 1 << 2 -> i32. | ||
726 | + | ||
727 | +.. list-table:: | ||
728 | + | ||
729 | + * - mov_vec *v0*, *v1* | ||
730 | + ld_vec *v0*, *t1* | ||
731 | + st_vec *v0*, *t1* | ||
732 | + | ||
733 | + - | Move, load and store. | ||
734 | + | ||
735 | + * - dup_vec *v0*, *r1* | ||
736 | + | ||
737 | + - | Duplicate the low N bits of *r1* into VECL/VECE copies across *v0*. | ||
738 | + | ||
739 | + * - dupi_vec *v0*, *c* | ||
740 | + | ||
741 | + - | Similarly, for a constant. | ||
742 | + | Smaller values will be replicated to host register size by the expanders. | ||
743 | + | ||
744 | + * - dup2_vec *v0*, *r1*, *r2* | ||
745 | + | ||
746 | + - | Duplicate *r2*:*r1* into VECL/64 copies across *v0*. This opcode is | ||
747 | + only present for 32-bit hosts. | ||
748 | + | ||
749 | + * - add_vec *v0*, *v1*, *v2* | ||
750 | + | ||
751 | + - | *v0* = *v1* + *v2*, in elements across the vector. | ||
752 | + | ||
753 | + * - sub_vec *v0*, *v1*, *v2* | ||
754 | + | ||
755 | + - | Similarly, *v0* = *v1* - *v2*. | ||
756 | + | ||
757 | + * - mul_vec *v0*, *v1*, *v2* | ||
758 | + | ||
759 | + - | Similarly, *v0* = *v1* * *v2*. | ||
760 | + | ||
761 | + * - neg_vec *v0*, *v1* | ||
762 | + | ||
763 | + - | Similarly, *v0* = -*v1*. | ||
764 | + | ||
765 | + * - abs_vec *v0*, *v1* | ||
766 | + | ||
767 | + - | Similarly, *v0* = *v1* < 0 ? -*v1* : *v1*, in elements across the vector. | ||
768 | + | ||
769 | + * - smin_vec *v0*, *v1*, *v2* | ||
770 | + | ||
771 | + umin_vec *v0*, *v1*, *v2* | ||
772 | + | ||
773 | + - | Similarly, *v0* = MIN(*v1*, *v2*), for signed and unsigned element types. | ||
774 | + | ||
775 | + * - smax_vec *v0*, *v1*, *v2* | ||
776 | + | ||
777 | + umax_vec *v0*, *v1*, *v2* | ||
778 | + | ||
779 | + - | Similarly, *v0* = MAX(*v1*, *v2*), for signed and unsigned element types. | ||
780 | + | ||
781 | + * - ssadd_vec *v0*, *v1*, *v2* | ||
782 | + | ||
783 | + sssub_vec *v0*, *v1*, *v2* | ||
784 | + | ||
785 | + usadd_vec *v0*, *v1*, *v2* | ||
786 | + | ||
787 | + ussub_vec *v0*, *v1*, *v2* | ||
788 | + | ||
789 | + - | Signed and unsigned saturating addition and subtraction. | ||
790 | + | | ||
791 | + | If the true result is not representable within the element type, the | ||
792 | + element is set to the minimum or maximum value for the type. | ||
793 | + | ||
794 | + * - and_vec *v0*, *v1*, *v2* | ||
795 | + | ||
796 | + or_vec *v0*, *v1*, *v2* | ||
797 | + | ||
798 | + xor_vec *v0*, *v1*, *v2* | ||
799 | + | ||
800 | + andc_vec *v0*, *v1*, *v2* | ||
801 | + | ||
802 | + orc_vec *v0*, *v1*, *v2* | ||
803 | + | ||
804 | + not_vec *v0*, *v1* | ||
805 | + | ||
806 | + - | Similarly, logical operations with and without complement. | ||
807 | + | | ||
808 | + | Note that VECE is unused. | ||
809 | + | ||
810 | + * - shli_vec *v0*, *v1*, *i2* | ||
811 | + | ||
812 | + shls_vec *v0*, *v1*, *s2* | ||
813 | + | ||
814 | + - | Shift all elements from v1 by a scalar *i2*/*s2*. I.e. | ||
815 | + | ||
816 | + .. code-block:: c | ||
817 | + | ||
818 | + for (i = 0; i < VECL/VECE; ++i) { | ||
819 | + v0[i] = v1[i] << s2; | ||
820 | + } | ||
821 | + | ||
822 | + * - shri_vec *v0*, *v1*, *i2* | ||
823 | + | ||
824 | + sari_vec *v0*, *v1*, *i2* | ||
825 | + | ||
826 | + rotli_vec *v0*, *v1*, *i2* | ||
827 | + | ||
828 | + shrs_vec *v0*, *v1*, *s2* | ||
829 | + | ||
830 | + sars_vec *v0*, *v1*, *s2* | ||
831 | + | ||
832 | + - | Similarly for logical and arithmetic right shift, and left rotate. | ||
833 | + | ||
834 | + * - shlv_vec *v0*, *v1*, *v2* | ||
835 | + | ||
836 | + - | Shift elements from *v1* by elements from *v2*. I.e. | ||
837 | + | ||
838 | + .. code-block:: c | ||
839 | + | ||
840 | + for (i = 0; i < VECL/VECE; ++i) { | ||
841 | + v0[i] = v1[i] << v2[i]; | ||
842 | + } | ||
843 | + | ||
844 | + * - shrv_vec *v0*, *v1*, *v2* | ||
845 | + | ||
846 | + sarv_vec *v0*, *v1*, *v2* | ||
847 | + | ||
848 | + rotlv_vec *v0*, *v1*, *v2* | ||
849 | + | ||
850 | + rotrv_vec *v0*, *v1*, *v2* | ||
851 | + | ||
852 | + - | Similarly for logical and arithmetic right shift, and rotates. | ||
853 | + | ||
854 | + * - cmp_vec *v0*, *v1*, *v2*, *cond* | ||
855 | + | ||
856 | + - | Compare vectors by element, storing -1 for true and 0 for false. | ||
857 | + | ||
858 | + * - bitsel_vec *v0*, *v1*, *v2*, *v3* | ||
859 | + | ||
860 | + - | Bitwise select, *v0* = (*v2* & *v1*) | (*v3* & ~\ *v1*), across the entire vector. | ||
861 | + | ||
862 | + * - cmpsel_vec *v0*, *c1*, *c2*, *v3*, *v4*, *cond* | ||
863 | + | ||
864 | + - | Select elements based on comparison results: | ||
865 | + | ||
866 | + .. code-block:: c | ||
867 | + | ||
868 | + for (i = 0; i < n; ++i) { | ||
869 | + v0[i] = (c1[i] cond c2[i]) ? v3[i] : v4[i]. | ||
870 | + } | ||
871 | + | ||
872 | +**Note 1**: Some shortcuts are defined when the last operand is known to be | ||
873 | +a constant (e.g. addi for add, movi for mov). | ||
874 | + | ||
875 | +**Note 2**: When using TCG, the opcodes must never be generated directly | ||
876 | +as some of them may not be available as "real" opcodes. Always use the | ||
877 | +function tcg_gen_xxx(args). | ||
878 | + | ||
879 | + | ||
880 | +Backend | ||
881 | +======= | ||
882 | + | ||
883 | +``tcg-target.h`` contains the target specific definitions. ``tcg-target.c.inc`` | ||
884 | +contains the target specific code; it is #included by ``tcg/tcg.c``, rather | ||
885 | +than being a standalone C file. | ||
886 | + | ||
887 | +Assumptions | ||
888 | +----------- | ||
889 | + | ||
890 | +The target word size (``TCG_TARGET_REG_BITS``) is expected to be 32 bit or | ||
891 | +64 bit. It is expected that the pointer has the same size as the word. | ||
892 | + | ||
893 | +On a 32 bit target, all 64 bit operations are converted to 32 bits. A | ||
894 | +few specific operations must be implemented to allow it (see add2_i32, | ||
895 | +sub2_i32, brcond2_i32). | ||
896 | + | ||
897 | +On a 64 bit target, the values are transferred between 32 and 64-bit | ||
898 | +registers using the following ops: | ||
899 | + | ||
900 | +- trunc_shr_i64_i32 | ||
901 | +- ext_i32_i64 | ||
902 | +- extu_i32_i64 | ||
903 | + | ||
904 | +They ensure that the values are correctly truncated or extended when | ||
905 | +moved from a 32-bit to a 64-bit register or vice-versa. Note that the | ||
906 | +trunc_shr_i64_i32 is an optional op. It is not necessary to implement | ||
907 | +it if all the following conditions are met: | ||
908 | + | ||
909 | +- 64-bit registers can hold 32-bit values | ||
910 | +- 32-bit values in a 64-bit register do not need to stay zero or | ||
911 | + sign extended | ||
912 | +- all 32-bit TCG ops ignore the high part of 64-bit registers | ||
913 | + | ||
914 | +Floating point operations are not supported in this version. A | ||
915 | +previous incarnation of the code generator had full support of them, | ||
916 | +but it is better to concentrate on integer operations first. | ||
917 | + | ||
918 | +Constraints | ||
919 | +---------------- | ||
920 | + | ||
921 | +GCC like constraints are used to define the constraints of every | ||
922 | +instruction. Memory constraints are not supported in this | ||
923 | +version. Aliases are specified in the input operands as for GCC. | ||
924 | + | ||
925 | +The same register may be used for both an input and an output, even when | ||
926 | +they are not explicitly aliased. If an op expands to multiple target | ||
927 | +instructions then care must be taken to avoid clobbering input values. | ||
928 | +GCC style "early clobber" outputs are supported, with '``&``'. | ||
929 | + | ||
930 | +A target can define specific register or constant constraints. If an | ||
931 | +operation uses a constant input constraint which does not allow all | ||
932 | +constants, it must also accept registers in order to have a fallback. | ||
933 | +The constraint '``i``' is defined generically to accept any constant. | ||
934 | +The constraint '``r``' is not defined generically, but is consistently | ||
935 | +used by each backend to indicate all registers. | ||
936 | + | ||
937 | +The movi_i32 and movi_i64 operations must accept any constants. | ||
938 | + | ||
939 | +The mov_i32 and mov_i64 operations must accept any registers of the | ||
940 | +same type. | ||
941 | + | ||
942 | +The ld/st/sti instructions must accept signed 32 bit constant offsets. | ||
943 | +This can be implemented by reserving a specific register in which to | ||
944 | +compute the address if the offset is too big. | ||
945 | + | ||
946 | +The ld/st instructions must accept any destination (ld) or source (st) | ||
947 | +register. | ||
948 | + | ||
949 | +The sti instruction may fail if it cannot store the given constant. | ||
950 | + | ||
951 | +Function call assumptions | ||
952 | +------------------------- | ||
953 | + | ||
954 | +- The only supported types for parameters and return value are: 32 and | ||
955 | + 64 bit integers and pointer. | ||
956 | +- The stack grows downwards. | ||
957 | +- The first N parameters are passed in registers. | ||
958 | +- The next parameters are passed on the stack by storing them as words. | ||
959 | +- Some registers are clobbered during the call. | ||
960 | +- The function can return 0 or 1 value in registers. On a 32 bit | ||
961 | + target, functions must be able to return 2 values in registers for | ||
962 | + 64 bit return type. | ||
963 | + | ||
964 | + | ||
965 | +Recommended coding rules for best performance | ||
966 | +============================================= | ||
967 | + | ||
968 | +- Use globals to represent the parts of the QEMU CPU state which are | ||
969 | + often modified, e.g. the integer registers and the condition | ||
970 | + codes. TCG will be able to use host registers to store them. | ||
971 | + | ||
972 | +- Avoid globals stored in fixed registers. They must be used only to | ||
973 | + store the pointer to the CPU state and possibly to store a pointer | ||
974 | + to a register window. | ||
975 | + | ||
976 | +- Use temporaries. Use local temporaries only when really needed, | ||
977 | + e.g. when you need to use a value after a jump. Local temporaries | ||
978 | + introduce a performance hit in the current TCG implementation: their | ||
979 | + content is saved to memory at end of each basic block. | ||
980 | + | ||
981 | +- Free temporaries and local temporaries when they are no longer used | ||
982 | + (tcg_temp_free). Since tcg_const_x() also creates a temporary, you | ||
983 | + should free it after it is used. Freeing temporaries does not yield | ||
984 | + a better generated code, but it reduces the memory usage of TCG and | ||
985 | + the speed of the translation. | ||
986 | + | ||
987 | +- Don't hesitate to use helpers for complicated or seldom used guest | ||
988 | + instructions. There is little performance advantage in using TCG to | ||
989 | + implement guest instructions taking more than about twenty TCG | ||
990 | + instructions. Note that this rule of thumb is more applicable to | ||
991 | + helpers doing complex logic or arithmetic, where the C compiler has | ||
992 | + scope to do a good job of optimisation; it is less relevant where | ||
993 | + the instruction is mostly doing loads and stores, and in those cases | ||
994 | + inline TCG may still be faster for longer sequences. | ||
995 | + | ||
996 | +- The hard limit on the number of TCG instructions you can generate | ||
997 | + per guest instruction is set by ``MAX_OP_PER_INSTR`` in ``exec-all.h`` -- | ||
998 | + you cannot exceed this without risking a buffer overrun. | ||
999 | + | ||
1000 | +- Use the 'discard' instruction if you know that TCG won't be able to | ||
1001 | + prove that a given global is "dead" at a given program point. The | ||
1002 | + x86 guest uses it to improve the condition codes optimisation. | ||
1003 | diff --git a/docs/devel/tcg.rst b/docs/devel/tcg.rst | ||
1004 | index XXXXXXX..XXXXXXX 100644 | ||
1005 | --- a/docs/devel/tcg.rst | ||
1006 | +++ b/docs/devel/tcg.rst | ||
1007 | @@ -XXX,XX +XXX,XX @@ which make it relatively easily portable and simple while achieving good | ||
1008 | performances. | ||
1009 | |||
1010 | QEMU's dynamic translation backend is called TCG, for "Tiny Code | ||
1011 | -Generator". For more information, please take a look at ``tcg/README``. | ||
1012 | +Generator". For more information, please take a look at :ref:`tcg-ops-ref`. | ||
1013 | |||
1014 | The following sections outline some notable features and implementation | ||
1015 | details of QEMU's dynamic translator. | ||
1016 | diff --git a/tcg/README b/tcg/README | ||
1017 | deleted file mode 100644 | ||
1018 | index XXXXXXX..XXXXXXX | ||
1019 | --- a/tcg/README | ||
1020 | +++ /dev/null | ||
1021 | @@ -XXX,XX +XXX,XX @@ | ||
1022 | -Tiny Code Generator - Fabrice Bellard. | ||
1023 | - | ||
1024 | -1) Introduction | ||
1025 | - | ||
1026 | -TCG (Tiny Code Generator) began as a generic backend for a C | ||
1027 | -compiler. It was simplified to be used in QEMU. It also has its roots | ||
1028 | -in the QOP code generator written by Paul Brook. | ||
1029 | - | ||
1030 | -2) Definitions | ||
1031 | - | ||
1032 | -TCG receives RISC-like "TCG ops" and performs some optimizations on them, | ||
1033 | -including liveness analysis and trivial constant expression | ||
1034 | -evaluation. TCG ops are then implemented in the host CPU back end, | ||
1035 | -also known as the TCG "target". | ||
1036 | - | ||
1037 | -The TCG "target" is the architecture for which we generate the | ||
1038 | -code. It is of course not the same as the "target" of QEMU which is | ||
1039 | -the emulated architecture. As TCG started as a generic C backend used | ||
1040 | -for cross compiling, it is assumed that the TCG target is different | ||
1041 | -from the host, although it is never the case for QEMU. | ||
1042 | - | ||
1043 | -In this document, we use "guest" to specify what architecture we are | ||
1044 | -emulating; "target" always means the TCG target, the machine on which | ||
1045 | -we are running QEMU. | ||
1046 | - | ||
1047 | -A TCG "function" corresponds to a QEMU Translated Block (TB). | ||
1048 | - | ||
1049 | -A TCG "temporary" is a variable only live in a basic | ||
1050 | -block. Temporaries are allocated explicitly in each function. | ||
1051 | - | ||
1052 | -A TCG "local temporary" is a variable only live in a function. Local | ||
1053 | -temporaries are allocated explicitly in each function. | ||
1054 | - | ||
1055 | -A TCG "global" is a variable which is live in all the functions | ||
1056 | -(equivalent of a C global variable). They are defined before the | ||
1057 | -functions defined. A TCG global can be a memory location (e.g. a QEMU | ||
1058 | -CPU register), a fixed host register (e.g. the QEMU CPU state pointer) | ||
1059 | -or a memory location which is stored in a register outside QEMU TBs | ||
1060 | -(not implemented yet). | ||
1061 | - | ||
1062 | -A TCG "basic block" corresponds to a list of instructions terminated | ||
1063 | -by a branch instruction. | ||
1064 | - | ||
1065 | -An operation with "undefined behavior" may result in a crash. | ||
1066 | - | ||
1067 | -An operation with "unspecified behavior" shall not crash. However, | ||
1068 | -the result may be one of several possibilities so may be considered | ||
1069 | -an "undefined result". | ||
1070 | - | ||
1071 | -3) Intermediate representation | ||
1072 | - | ||
1073 | -3.1) Introduction | ||
1074 | - | ||
1075 | -TCG instructions operate on variables which are temporaries, local | ||
1076 | -temporaries or globals. TCG instructions and variables are strongly | ||
1077 | -typed. Two types are supported: 32 bit integers and 64 bit | ||
1078 | -integers. Pointers are defined as an alias to 32 bit or 64 bit | ||
1079 | -integers depending on the TCG target word size. | ||
1080 | - | ||
1081 | -Each instruction has a fixed number of output variable operands, input | ||
1082 | -variable operands and always constant operands. | ||
1083 | - | ||
1084 | -The notable exception is the call instruction which has a variable | ||
1085 | -number of outputs and inputs. | ||
1086 | - | ||
1087 | -In the textual form, output operands usually come first, followed by | ||
1088 | -input operands, followed by constant operands. The output type is | ||
1089 | -included in the instruction name. Constants are prefixed with a '$'. | ||
1090 | - | ||
1091 | -add_i32 t0, t1, t2 (t0 <- t1 + t2) | ||
1092 | - | ||
1093 | -3.2) Assumptions | ||
1094 | - | ||
1095 | -* Basic blocks | ||
1096 | - | ||
1097 | -- Basic blocks end after branches (e.g. brcond_i32 instruction), | ||
1098 | - goto_tb and exit_tb instructions. | ||
1099 | -- Basic blocks start after the end of a previous basic block, or at a | ||
1100 | - set_label instruction. | ||
1101 | - | ||
1102 | -After the end of a basic block, the content of temporaries is | ||
1103 | -destroyed, but local temporaries and globals are preserved. | ||
1104 | - | ||
1105 | -* Floating point types are not supported yet | ||
1106 | - | ||
1107 | -* Pointers: depending on the TCG target, pointer size is 32 bit or 64 | ||
1108 | - bit. The type TCG_TYPE_PTR is an alias to TCG_TYPE_I32 or | ||
1109 | - TCG_TYPE_I64. | ||
1110 | - | ||
1111 | -* Helpers: | ||
1112 | - | ||
1113 | -Using the tcg_gen_helper_x_y it is possible to call any function | ||
1114 | -taking i32, i64 or pointer types. By default, before calling a helper, | ||
1115 | -all globals are stored at their canonical location and it is assumed | ||
1116 | -that the function can modify them. By default, the helper is allowed to | ||
1117 | -modify the CPU state or raise an exception. | ||
1118 | - | ||
1119 | -This can be overridden using the following function modifiers: | ||
1120 | -- TCG_CALL_NO_READ_GLOBALS means that the helper does not read globals, | ||
1121 | - either directly or via an exception. They will not be saved to their | ||
1122 | - canonical locations before calling the helper. | ||
1123 | -- TCG_CALL_NO_WRITE_GLOBALS means that the helper does not modify any globals. | ||
1124 | - They will only be saved to their canonical location before calling helpers, | ||
1125 | - but they won't be reloaded afterwards. | ||
1126 | -- TCG_CALL_NO_SIDE_EFFECTS means that the call to the function is removed if | ||
1127 | - the return value is not used. | ||
1128 | - | ||
1129 | -Note that TCG_CALL_NO_READ_GLOBALS implies TCG_CALL_NO_WRITE_GLOBALS. | ||
1130 | - | ||
1131 | -On some TCG targets (e.g. x86), several calling conventions are | ||
1132 | -supported. | ||
1133 | - | ||
1134 | -* Branches: | ||
1135 | - | ||
1136 | -Use the instruction 'br' to jump to a label. | ||
1137 | - | ||
1138 | -3.3) Code Optimizations | ||
1139 | - | ||
1140 | -When generating instructions, you can count on at least the following | ||
1141 | -optimizations: | ||
1142 | - | ||
1143 | -- Single instructions are simplified, e.g. | ||
1144 | - | ||
1145 | - and_i32 t0, t0, $0xffffffff | ||
1146 | - | ||
1147 | - is suppressed. | ||
1148 | - | ||
1149 | -- A liveness analysis is done at the basic block level. The | ||
1150 | - information is used to suppress moves from a dead variable to | ||
1151 | - another one. It is also used to remove instructions which compute | ||
1152 | - dead results. The later is especially useful for condition code | ||
1153 | - optimization in QEMU. | ||
1154 | - | ||
1155 | - In the following example: | ||
1156 | - | ||
1157 | - add_i32 t0, t1, t2 | ||
1158 | - add_i32 t0, t0, $1 | ||
1159 | - mov_i32 t0, $1 | ||
1160 | - | ||
1161 | - only the last instruction is kept. | ||
1162 | - | ||
1163 | -3.4) Instruction Reference | ||
1164 | - | ||
1165 | -********* Function call | ||
1166 | - | ||
1167 | -* call <ret> <params> ptr | ||
1168 | - | ||
1169 | -call function 'ptr' (pointer type) | ||
1170 | - | ||
1171 | -<ret> optional 32 bit or 64 bit return value | ||
1172 | -<params> optional 32 bit or 64 bit parameters | ||
1173 | - | ||
1174 | -********* Jumps/Labels | ||
1175 | - | ||
1176 | -* set_label $label | ||
1177 | - | ||
1178 | -Define label 'label' at the current program point. | ||
1179 | - | ||
1180 | -* br $label | ||
1181 | - | ||
1182 | -Jump to label. | ||
1183 | - | ||
1184 | -* brcond_i32/i64 t0, t1, cond, label | ||
1185 | - | ||
1186 | -Conditional jump if t0 cond t1 is true. cond can be: | ||
1187 | - TCG_COND_EQ | ||
1188 | - TCG_COND_NE | ||
1189 | - TCG_COND_LT /* signed */ | ||
1190 | - TCG_COND_GE /* signed */ | ||
1191 | - TCG_COND_LE /* signed */ | ||
1192 | - TCG_COND_GT /* signed */ | ||
1193 | - TCG_COND_LTU /* unsigned */ | ||
1194 | - TCG_COND_GEU /* unsigned */ | ||
1195 | - TCG_COND_LEU /* unsigned */ | ||
1196 | - TCG_COND_GTU /* unsigned */ | ||
1197 | - | ||
1198 | -********* Arithmetic | ||
1199 | - | ||
1200 | -* add_i32/i64 t0, t1, t2 | ||
1201 | - | ||
1202 | -t0=t1+t2 | ||
1203 | - | ||
1204 | -* sub_i32/i64 t0, t1, t2 | ||
1205 | - | ||
1206 | -t0=t1-t2 | ||
1207 | - | ||
1208 | -* neg_i32/i64 t0, t1 | ||
1209 | - | ||
1210 | -t0=-t1 (two's complement) | ||
1211 | - | ||
1212 | -* mul_i32/i64 t0, t1, t2 | ||
1213 | - | ||
1214 | -t0=t1*t2 | ||
1215 | - | ||
1216 | -* div_i32/i64 t0, t1, t2 | ||
1217 | - | ||
1218 | -t0=t1/t2 (signed). Undefined behavior if division by zero or overflow. | ||
1219 | - | ||
1220 | -* divu_i32/i64 t0, t1, t2 | ||
1221 | - | ||
1222 | -t0=t1/t2 (unsigned). Undefined behavior if division by zero. | ||
1223 | - | ||
1224 | -* rem_i32/i64 t0, t1, t2 | ||
1225 | - | ||
1226 | -t0=t1%t2 (signed). Undefined behavior if division by zero or overflow. | ||
1227 | - | ||
1228 | -* remu_i32/i64 t0, t1, t2 | ||
1229 | - | ||
1230 | -t0=t1%t2 (unsigned). Undefined behavior if division by zero. | ||
1231 | - | ||
1232 | -********* Logical | ||
1233 | - | ||
1234 | -* and_i32/i64 t0, t1, t2 | ||
1235 | - | ||
1236 | -t0=t1&t2 | ||
1237 | - | ||
1238 | -* or_i32/i64 t0, t1, t2 | ||
1239 | - | ||
1240 | -t0=t1|t2 | ||
1241 | - | ||
1242 | -* xor_i32/i64 t0, t1, t2 | ||
1243 | - | ||
1244 | -t0=t1^t2 | ||
1245 | - | ||
1246 | -* not_i32/i64 t0, t1 | ||
1247 | - | ||
1248 | -t0=~t1 | ||
1249 | - | ||
1250 | -* andc_i32/i64 t0, t1, t2 | ||
1251 | - | ||
1252 | -t0=t1&~t2 | ||
1253 | - | ||
1254 | -* eqv_i32/i64 t0, t1, t2 | ||
1255 | - | ||
1256 | -t0=~(t1^t2), or equivalently, t0=t1^~t2 | ||
1257 | - | ||
1258 | -* nand_i32/i64 t0, t1, t2 | ||
1259 | - | ||
1260 | -t0=~(t1&t2) | ||
1261 | - | ||
1262 | -* nor_i32/i64 t0, t1, t2 | ||
1263 | - | ||
1264 | -t0=~(t1|t2) | ||
1265 | - | ||
1266 | -* orc_i32/i64 t0, t1, t2 | ||
1267 | - | ||
1268 | -t0=t1|~t2 | ||
1269 | - | ||
1270 | -* clz_i32/i64 t0, t1, t2 | ||
1271 | - | ||
1272 | -t0 = t1 ? clz(t1) : t2 | ||
1273 | - | ||
1274 | -* ctz_i32/i64 t0, t1, t2 | ||
1275 | - | ||
1276 | -t0 = t1 ? ctz(t1) : t2 | ||
1277 | - | ||
1278 | -* ctpop_i32/i64 t0, t1 | ||
1279 | - | ||
1280 | -t0 = number of bits set in t1 | ||
1281 | -With "ctpop" short for "count population", matching | ||
1282 | -the function name used in include/qemu/host-utils.h. | ||
1283 | - | ||
1284 | -********* Shifts/Rotates | ||
1285 | - | ||
1286 | -* shl_i32/i64 t0, t1, t2 | ||
1287 | - | ||
1288 | -t0=t1 << t2. Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64) | ||
1289 | - | ||
1290 | -* shr_i32/i64 t0, t1, t2 | ||
1291 | - | ||
1292 | -t0=t1 >> t2 (unsigned). Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64) | ||
1293 | - | ||
1294 | -* sar_i32/i64 t0, t1, t2 | ||
1295 | - | ||
1296 | -t0=t1 >> t2 (signed). Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64) | ||
1297 | - | ||
1298 | -* rotl_i32/i64 t0, t1, t2 | ||
1299 | - | ||
1300 | -Rotation of t2 bits to the left. | ||
1301 | -Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64) | ||
1302 | - | ||
1303 | -* rotr_i32/i64 t0, t1, t2 | ||
1304 | - | ||
1305 | -Rotation of t2 bits to the right. | ||
1306 | -Unspecified behavior if t2 < 0 or t2 >= 32 (resp 64) | ||
1307 | - | ||
1308 | -********* Misc | ||
1309 | - | ||
1310 | -* mov_i32/i64 t0, t1 | ||
1311 | - | ||
1312 | -t0 = t1 | ||
1313 | - | ||
1314 | -Move t1 to t0 (both operands must have the same type). | ||
1315 | - | ||
1316 | -* ext8s_i32/i64 t0, t1 | ||
1317 | -ext8u_i32/i64 t0, t1 | ||
1318 | -ext16s_i32/i64 t0, t1 | ||
1319 | -ext16u_i32/i64 t0, t1 | ||
1320 | -ext32s_i64 t0, t1 | ||
1321 | -ext32u_i64 t0, t1 | ||
1322 | - | ||
1323 | -8, 16 or 32 bit sign/zero extension (both operands must have the same type) | ||
1324 | - | ||
1325 | -* bswap16_i32/i64 t0, t1, flags | ||
1326 | - | ||
1327 | -16 bit byte swap on the low bits of a 32/64 bit input. | ||
1328 | -If flags & TCG_BSWAP_IZ, then t1 is known to be zero-extended from bit 15. | ||
1329 | -If flags & TCG_BSWAP_OZ, then t0 will be zero-extended from bit 15. | ||
1330 | -If flags & TCG_BSWAP_OS, then t0 will be sign-extended from bit 15. | ||
1331 | -If neither TCG_BSWAP_OZ nor TCG_BSWAP_OS are set, then the bits of | ||
1332 | -t0 above bit 15 may contain any value. | ||
1333 | - | ||
1334 | -* bswap32_i64 t0, t1, flags | ||
1335 | - | ||
1336 | -32 bit byte swap on a 64-bit value. The flags are the same as for bswap16, | ||
1337 | -except they apply from bit 31 instead of bit 15. | ||
1338 | - | ||
1339 | -* bswap32_i32 t0, t1, flags | ||
1340 | -* bswap64_i64 t0, t1, flags | ||
1341 | - | ||
1342 | -32/64 bit byte swap. The flags are ignored, but still present | ||
1343 | -for consistency with the other bswap opcodes. | ||
1344 | - | ||
1345 | -* discard_i32/i64 t0 | ||
1346 | - | ||
1347 | -Indicate that the value of t0 won't be used later. It is useful to | ||
1348 | -force dead code elimination. | ||
1349 | - | ||
1350 | -* deposit_i32/i64 dest, t1, t2, pos, len | ||
1351 | - | ||
1352 | -Deposit T2 as a bitfield into T1, placing the result in DEST. | ||
1353 | -The bitfield is described by POS/LEN, which are immediate values: | ||
1354 | - | ||
1355 | - LEN - the length of the bitfield | ||
1356 | - POS - the position of the first bit, counting from the LSB | ||
1357 | - | ||
1358 | -For example, "deposit_i32 dest, t1, t2, 8, 4" indicates a 4-bit field | ||
1359 | -at bit 8. This operation would be equivalent to | ||
1360 | - | ||
1361 | - dest = (t1 & ~0x0f00) | ((t2 << 8) & 0x0f00) | ||
1362 | - | ||
1363 | -* extract_i32/i64 dest, t1, pos, len | ||
1364 | -* sextract_i32/i64 dest, t1, pos, len | ||
1365 | - | ||
1366 | -Extract a bitfield from T1, placing the result in DEST. | ||
1367 | -The bitfield is described by POS/LEN, which are immediate values, | ||
1368 | -as above for deposit. For extract_*, the result will be extended | ||
1369 | -to the left with zeros; for sextract_*, the result will be extended | ||
1370 | -to the left with copies of the bitfield sign bit at pos + len - 1. | ||
1371 | - | ||
1372 | -For example, "sextract_i32 dest, t1, 8, 4" indicates a 4-bit field | ||
1373 | -at bit 8. This operation would be equivalent to | ||
1374 | - | ||
1375 | - dest = (t1 << 20) >> 28 | ||
1376 | - | ||
1377 | -(using an arithmetic right shift). | ||
1378 | - | ||
1379 | -* extract2_i32/i64 dest, t1, t2, pos | ||
1380 | - | ||
1381 | -For N = {32,64}, extract an N-bit quantity from the concatenation | ||
1382 | -of t2:t1, beginning at pos. The tcg_gen_extract2_{i32,i64} expander | ||
1383 | -accepts 0 <= pos <= N as inputs. The backend code generator will | ||
1384 | -not see either 0 or N as inputs for these opcodes. | ||
1385 | - | ||
1386 | -* extrl_i64_i32 t0, t1 | ||
1387 | - | ||
1388 | -For 64-bit hosts only, extract the low 32-bits of input T1 and place it | ||
1389 | -into 32-bit output T0. Depending on the host, this may be a simple move, | ||
1390 | -or may require additional canonicalization. | ||
1391 | - | ||
1392 | -* extrh_i64_i32 t0, t1 | ||
1393 | - | ||
1394 | -For 64-bit hosts only, extract the high 32-bits of input T1 and place it | ||
1395 | -into 32-bit output T0. Depending on the host, this may be a simple shift, | ||
1396 | -or may require additional canonicalization. | ||
1397 | - | ||
1398 | -********* Conditional moves | ||
1399 | - | ||
1400 | -* setcond_i32/i64 dest, t1, t2, cond | ||
1401 | - | ||
1402 | -dest = (t1 cond t2) | ||
1403 | - | ||
1404 | -Set DEST to 1 if (T1 cond T2) is true, otherwise set to 0. | ||
1405 | - | ||
1406 | -* movcond_i32/i64 dest, c1, c2, v1, v2, cond | ||
1407 | - | ||
1408 | -dest = (c1 cond c2 ? v1 : v2) | ||
1409 | - | ||
1410 | -Set DEST to V1 if (C1 cond C2) is true, otherwise set to V2. | ||
1411 | - | ||
1412 | -********* Type conversions | ||
1413 | - | ||
1414 | -* ext_i32_i64 t0, t1 | ||
1415 | -Convert t1 (32 bit) to t0 (64 bit) and does sign extension | ||
1416 | - | ||
1417 | -* extu_i32_i64 t0, t1 | ||
1418 | -Convert t1 (32 bit) to t0 (64 bit) and does zero extension | ||
1419 | - | ||
1420 | -* trunc_i64_i32 t0, t1 | ||
1421 | -Truncate t1 (64 bit) to t0 (32 bit) | ||
1422 | - | ||
1423 | -* concat_i32_i64 t0, t1, t2 | ||
1424 | -Construct t0 (64-bit) taking the low half from t1 (32 bit) and the high half | ||
1425 | -from t2 (32 bit). | ||
1426 | - | ||
1427 | -* concat32_i64 t0, t1, t2 | ||
1428 | -Construct t0 (64-bit) taking the low half from t1 (64 bit) and the high half | ||
1429 | -from t2 (64 bit). | ||
1430 | - | ||
1431 | -********* Load/Store | ||
1432 | - | ||
1433 | -* ld_i32/i64 t0, t1, offset | ||
1434 | -ld8s_i32/i64 t0, t1, offset | ||
1435 | -ld8u_i32/i64 t0, t1, offset | ||
1436 | -ld16s_i32/i64 t0, t1, offset | ||
1437 | -ld16u_i32/i64 t0, t1, offset | ||
1438 | -ld32s_i64 t0, t1, offset | ||
1439 | -ld32u_i64 t0, t1, offset | ||
1440 | - | ||
1441 | -t0 = read(t1 + offset) | ||
1442 | -Load 8, 16, 32 or 64 bits with or without sign extension from host memory. | ||
1443 | -offset must be a constant. | ||
1444 | - | ||
1445 | -* st_i32/i64 t0, t1, offset | ||
1446 | -st8_i32/i64 t0, t1, offset | ||
1447 | -st16_i32/i64 t0, t1, offset | ||
1448 | -st32_i64 t0, t1, offset | ||
1449 | - | ||
1450 | -write(t0, t1 + offset) | ||
1451 | -Write 8, 16, 32 or 64 bits to host memory. | ||
1452 | - | ||
1453 | -All this opcodes assume that the pointed host memory doesn't correspond | ||
1454 | -to a global. In the latter case the behaviour is unpredictable. | ||
1455 | - | ||
1456 | -********* Multiword arithmetic support | ||
1457 | - | ||
1458 | -* add2_i32/i64 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high | ||
1459 | -* sub2_i32/i64 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high | ||
1460 | - | ||
1461 | -Similar to add/sub, except that the double-word inputs T1 and T2 are | ||
1462 | -formed from two single-word arguments, and the double-word output T0 | ||
1463 | -is returned in two single-word outputs. | ||
1464 | - | ||
1465 | -* mulu2_i32/i64 t0_low, t0_high, t1, t2 | ||
1466 | - | ||
1467 | -Similar to mul, except two unsigned inputs T1 and T2 yielding the full | ||
1468 | -double-word product T0. The later is returned in two single-word outputs. | ||
1469 | - | ||
1470 | -* muls2_i32/i64 t0_low, t0_high, t1, t2 | ||
1471 | - | ||
1472 | -Similar to mulu2, except the two inputs T1 and T2 are signed. | ||
1473 | - | ||
1474 | -* mulsh_i32/i64 t0, t1, t2 | ||
1475 | -* muluh_i32/i64 t0, t1, t2 | ||
1476 | - | ||
1477 | -Provide the high part of a signed or unsigned multiply, respectively. | ||
1478 | -If mulu2/muls2 are not provided by the backend, the tcg-op generator | ||
1479 | -can obtain the same results can be obtained by emitting a pair of | ||
1480 | -opcodes, mul+muluh/mulsh. | ||
1481 | - | ||
1482 | -********* Memory Barrier support | ||
1483 | - | ||
1484 | -* mb <$arg> | ||
1485 | - | ||
1486 | -Generate a target memory barrier instruction to ensure memory ordering as being | ||
1487 | -enforced by a corresponding guest memory barrier instruction. The ordering | ||
1488 | -enforced by the backend may be stricter than the ordering required by the guest. | ||
1489 | -It cannot be weaker. This opcode takes a constant argument which is required to | ||
1490 | -generate the appropriate barrier instruction. The backend should take care to | ||
1491 | -emit the target barrier instruction only when necessary i.e., for SMP guests and | ||
1492 | -when MTTCG is enabled. | ||
1493 | - | ||
1494 | -The guest translators should generate this opcode for all guest instructions | ||
1495 | -which have ordering side effects. | ||
1496 | - | ||
1497 | -Please see docs/devel/atomics.rst for more information on memory barriers. | ||
1498 | - | ||
1499 | -********* 64-bit guest on 32-bit host support | ||
1500 | - | ||
1501 | -The following opcodes are internal to TCG. Thus they are to be implemented by | ||
1502 | -32-bit host code generators, but are not to be emitted by guest translators. | ||
1503 | -They are emitted as needed by inline functions within "tcg-op.h". | ||
1504 | - | ||
1505 | -* brcond2_i32 t0_low, t0_high, t1_low, t1_high, cond, label | ||
1506 | - | ||
1507 | -Similar to brcond, except that the 64-bit values T0 and T1 | ||
1508 | -are formed from two 32-bit arguments. | ||
1509 | - | ||
1510 | -* setcond2_i32 dest, t1_low, t1_high, t2_low, t2_high, cond | ||
1511 | - | ||
1512 | -Similar to setcond, except that the 64-bit values T1 and T2 are | ||
1513 | -formed from two 32-bit arguments. The result is a 32-bit value. | ||
1514 | - | ||
1515 | -********* QEMU specific operations | ||
1516 | - | ||
1517 | -* exit_tb t0 | ||
1518 | - | ||
1519 | -Exit the current TB and return the value t0 (word type). | ||
1520 | - | ||
1521 | -* goto_tb index | ||
1522 | - | ||
1523 | -Exit the current TB and jump to the TB index 'index' (constant) if the | ||
1524 | -current TB was linked to this TB. Otherwise execute the next | ||
1525 | -instructions. Only indices 0 and 1 are valid and tcg_gen_goto_tb may be issued | ||
1526 | -at most once with each slot index per TB. | ||
1527 | - | ||
1528 | -* lookup_and_goto_ptr tb_addr | ||
1529 | - | ||
1530 | -Look up a TB address ('tb_addr') and jump to it if valid. If not valid, | ||
1531 | -jump to the TCG epilogue to go back to the exec loop. | ||
1532 | - | ||
1533 | -This operation is optional. If the TCG backend does not implement the | ||
1534 | -goto_ptr opcode, emitting this op is equivalent to emitting exit_tb(0). | ||
1535 | - | ||
1536 | -* qemu_ld_i32/i64 t0, t1, flags, memidx | ||
1537 | -* qemu_st_i32/i64 t0, t1, flags, memidx | ||
1538 | -* qemu_st8_i32 t0, t1, flags, memidx | ||
1539 | - | ||
1540 | -Load data at the guest address t1 into t0, or store data in t0 at guest | ||
1541 | -address t1. The _i32/_i64 size applies to the size of the input/output | ||
1542 | -register t0 only. The address t1 is always sized according to the guest, | ||
1543 | -and the width of the memory operation is controlled by flags. | ||
1544 | - | ||
1545 | -Both t0 and t1 may be split into little-endian ordered pairs of registers | ||
1546 | -if dealing with 64-bit quantities on a 32-bit host. | ||
1547 | - | ||
1548 | -The memidx selects the qemu tlb index to use (e.g. user or kernel access). | ||
1549 | -The flags are the MemOp bits, selecting the sign, width, and endianness | ||
1550 | -of the memory access. | ||
1551 | - | ||
1552 | -For a 32-bit host, qemu_ld/st_i64 is guaranteed to only be used with a | ||
1553 | -64-bit memory access specified in flags. | ||
1554 | - | ||
1555 | -For i386, qemu_st8_i32 is exactly like qemu_st_i32, except the size of | ||
1556 | -the memory operation is known to be 8-bit. This allows the backend to | ||
1557 | -provide a different set of register constraints. | ||
1558 | - | ||
1559 | -********* Host vector operations | ||
1560 | - | ||
1561 | -All of the vector ops have two parameters, TCGOP_VECL & TCGOP_VECE. | ||
1562 | -The former specifies the length of the vector in log2 64-bit units; the | ||
1563 | -later specifies the length of the element (if applicable) in log2 8-bit units. | ||
1564 | -E.g. VECL=1 -> 64 << 1 -> v128, and VECE=2 -> 1 << 2 -> i32. | ||
1565 | - | ||
1566 | -* mov_vec v0, v1 | ||
1567 | -* ld_vec v0, t1 | ||
1568 | -* st_vec v0, t1 | ||
1569 | - | ||
1570 | - Move, load and store. | ||
1571 | - | ||
1572 | -* dup_vec v0, r1 | ||
1573 | - | ||
1574 | - Duplicate the low N bits of R1 into VECL/VECE copies across V0. | ||
1575 | - | ||
1576 | -* dupi_vec v0, c | ||
1577 | - | ||
1578 | - Similarly, for a constant. | ||
1579 | - Smaller values will be replicated to host register size by the expanders. | ||
1580 | - | ||
1581 | -* dup2_vec v0, r1, r2 | ||
1582 | - | ||
1583 | - Duplicate r2:r1 into VECL/64 copies across V0. This opcode is | ||
1584 | - only present for 32-bit hosts. | ||
1585 | - | ||
1586 | -* add_vec v0, v1, v2 | ||
1587 | - | ||
1588 | - v0 = v1 + v2, in elements across the vector. | ||
1589 | - | ||
1590 | -* sub_vec v0, v1, v2 | ||
1591 | - | ||
1592 | - Similarly, v0 = v1 - v2. | ||
1593 | - | ||
1594 | -* mul_vec v0, v1, v2 | ||
1595 | - | ||
1596 | - Similarly, v0 = v1 * v2. | ||
1597 | - | ||
1598 | -* neg_vec v0, v1 | ||
1599 | - | ||
1600 | - Similarly, v0 = -v1. | ||
1601 | - | ||
1602 | -* abs_vec v0, v1 | ||
1603 | - | ||
1604 | - Similarly, v0 = v1 < 0 ? -v1 : v1, in elements across the vector. | ||
1605 | - | ||
1606 | -* smin_vec: | ||
1607 | -* umin_vec: | ||
1608 | - | ||
1609 | - Similarly, v0 = MIN(v1, v2), for signed and unsigned element types. | ||
1610 | - | ||
1611 | -* smax_vec: | ||
1612 | -* umax_vec: | ||
1613 | - | ||
1614 | - Similarly, v0 = MAX(v1, v2), for signed and unsigned element types. | ||
1615 | - | ||
1616 | -* ssadd_vec: | ||
1617 | -* sssub_vec: | ||
1618 | -* usadd_vec: | ||
1619 | -* ussub_vec: | ||
1620 | - | ||
1621 | - Signed and unsigned saturating addition and subtraction. If the true | ||
1622 | - result is not representable within the element type, the element is | ||
1623 | - set to the minimum or maximum value for the type. | ||
1624 | - | ||
1625 | -* and_vec v0, v1, v2 | ||
1626 | -* or_vec v0, v1, v2 | ||
1627 | -* xor_vec v0, v1, v2 | ||
1628 | -* andc_vec v0, v1, v2 | ||
1629 | -* orc_vec v0, v1, v2 | ||
1630 | -* not_vec v0, v1 | ||
1631 | - | ||
1632 | - Similarly, logical operations with and without complement. | ||
1633 | - Note that VECE is unused. | ||
1634 | - | ||
1635 | -* shli_vec v0, v1, i2 | ||
1636 | -* shls_vec v0, v1, s2 | ||
1637 | - | ||
1638 | - Shift all elements from v1 by a scalar i2/s2. I.e. | ||
1639 | - | ||
1640 | - for (i = 0; i < VECL/VECE; ++i) { | ||
1641 | - v0[i] = v1[i] << s2; | ||
1642 | - } | ||
1643 | - | ||
1644 | -* shri_vec v0, v1, i2 | ||
1645 | -* sari_vec v0, v1, i2 | ||
1646 | -* rotli_vec v0, v1, i2 | ||
1647 | -* shrs_vec v0, v1, s2 | ||
1648 | -* sars_vec v0, v1, s2 | ||
1649 | - | ||
1650 | - Similarly for logical and arithmetic right shift, and left rotate. | ||
1651 | - | ||
1652 | -* shlv_vec v0, v1, v2 | ||
1653 | - | ||
1654 | - Shift elements from v1 by elements from v2. I.e. | ||
1655 | - | ||
1656 | - for (i = 0; i < VECL/VECE; ++i) { | ||
1657 | - v0[i] = v1[i] << v2[i]; | ||
1658 | - } | ||
1659 | - | ||
1660 | -* shrv_vec v0, v1, v2 | ||
1661 | -* sarv_vec v0, v1, v2 | ||
1662 | -* rotlv_vec v0, v1, v2 | ||
1663 | -* rotrv_vec v0, v1, v2 | ||
1664 | - | ||
1665 | - Similarly for logical and arithmetic right shift, and rotates. | ||
1666 | - | ||
1667 | -* cmp_vec v0, v1, v2, cond | ||
1668 | - | ||
1669 | - Compare vectors by element, storing -1 for true and 0 for false. | ||
1670 | - | ||
1671 | -* bitsel_vec v0, v1, v2, v3 | ||
1672 | - | ||
1673 | - Bitwise select, v0 = (v2 & v1) | (v3 & ~v1), across the entire vector. | ||
1674 | - | ||
1675 | -* cmpsel_vec v0, c1, c2, v3, v4, cond | ||
1676 | - | ||
1677 | - Select elements based on comparison results: | ||
1678 | - for (i = 0; i < n; ++i) { | ||
1679 | - v0[i] = (c1[i] cond c2[i]) ? v3[i] : v4[i]. | ||
1680 | - } | ||
1681 | - | ||
1682 | -********* | ||
1683 | - | ||
1684 | -Note 1: Some shortcuts are defined when the last operand is known to be | ||
1685 | -a constant (e.g. addi for add, movi for mov). | ||
1686 | - | ||
1687 | -Note 2: When using TCG, the opcodes must never be generated directly | ||
1688 | -as some of them may not be available as "real" opcodes. Always use the | ||
1689 | -function tcg_gen_xxx(args). | ||
1690 | - | ||
1691 | -4) Backend | ||
1692 | - | ||
1693 | -tcg-target.h contains the target specific definitions. tcg-target.c.inc | ||
1694 | -contains the target specific code; it is #included by tcg/tcg.c, rather | ||
1695 | -than being a standalone C file. | ||
1696 | - | ||
1697 | -4.1) Assumptions | ||
1698 | - | ||
1699 | -The target word size (TCG_TARGET_REG_BITS) is expected to be 32 bit or | ||
1700 | -64 bit. It is expected that the pointer has the same size as the word. | ||
1701 | - | ||
1702 | -On a 32 bit target, all 64 bit operations are converted to 32 bits. A | ||
1703 | -few specific operations must be implemented to allow it (see add2_i32, | ||
1704 | -sub2_i32, brcond2_i32). | ||
1705 | - | ||
1706 | -On a 64 bit target, the values are transferred between 32 and 64-bit | ||
1707 | -registers using the following ops: | ||
1708 | -- trunc_shr_i64_i32 | ||
1709 | -- ext_i32_i64 | ||
1710 | -- extu_i32_i64 | ||
1711 | - | ||
1712 | -They ensure that the values are correctly truncated or extended when | ||
1713 | -moved from a 32-bit to a 64-bit register or vice-versa. Note that the | ||
1714 | -trunc_shr_i64_i32 is an optional op. It is not necessary to implement | ||
1715 | -it if all the following conditions are met: | ||
1716 | -- 64-bit registers can hold 32-bit values | ||
1717 | -- 32-bit values in a 64-bit register do not need to stay zero or | ||
1718 | - sign extended | ||
1719 | -- all 32-bit TCG ops ignore the high part of 64-bit registers | ||
1720 | - | ||
1721 | -Floating point operations are not supported in this version. A | ||
1722 | -previous incarnation of the code generator had full support of them, | ||
1723 | -but it is better to concentrate on integer operations first. | ||
1724 | - | ||
1725 | -4.2) Constraints | ||
1726 | - | ||
1727 | -GCC like constraints are used to define the constraints of every | ||
1728 | -instruction. Memory constraints are not supported in this | ||
1729 | -version. Aliases are specified in the input operands as for GCC. | ||
1730 | - | ||
1731 | -The same register may be used for both an input and an output, even when | ||
1732 | -they are not explicitly aliased. If an op expands to multiple target | ||
1733 | -instructions then care must be taken to avoid clobbering input values. | ||
1734 | -GCC style "early clobber" outputs are supported, with '&'. | ||
1735 | - | ||
1736 | -A target can define specific register or constant constraints. If an | ||
1737 | -operation uses a constant input constraint which does not allow all | ||
1738 | -constants, it must also accept registers in order to have a fallback. | ||
1739 | -The constraint 'i' is defined generically to accept any constant. | ||
1740 | -The constraint 'r' is not defined generically, but is consistently | ||
1741 | -used by each backend to indicate all registers. | ||
1742 | - | ||
1743 | -The movi_i32 and movi_i64 operations must accept any constants. | ||
1744 | - | ||
1745 | -The mov_i32 and mov_i64 operations must accept any registers of the | ||
1746 | -same type. | ||
1747 | - | ||
1748 | -The ld/st/sti instructions must accept signed 32 bit constant offsets. | ||
1749 | -This can be implemented by reserving a specific register in which to | ||
1750 | -compute the address if the offset is too big. | ||
1751 | - | ||
1752 | -The ld/st instructions must accept any destination (ld) or source (st) | ||
1753 | -register. | ||
1754 | - | ||
1755 | -The sti instruction may fail if it cannot store the given constant. | ||
1756 | - | ||
1757 | -4.3) Function call assumptions | ||
1758 | - | ||
1759 | -- The only supported types for parameters and return value are: 32 and | ||
1760 | - 64 bit integers and pointer. | ||
1761 | -- The stack grows downwards. | ||
1762 | -- The first N parameters are passed in registers. | ||
1763 | -- The next parameters are passed on the stack by storing them as words. | ||
1764 | -- Some registers are clobbered during the call. | ||
1765 | -- The function can return 0 or 1 value in registers. On a 32 bit | ||
1766 | - target, functions must be able to return 2 values in registers for | ||
1767 | - 64 bit return type. | ||
1768 | - | ||
1769 | -5) Recommended coding rules for best performance | ||
1770 | - | ||
1771 | -- Use globals to represent the parts of the QEMU CPU state which are | ||
1772 | - often modified, e.g. the integer registers and the condition | ||
1773 | - codes. TCG will be able to use host registers to store them. | ||
1774 | - | ||
1775 | -- Avoid globals stored in fixed registers. They must be used only to | ||
1776 | - store the pointer to the CPU state and possibly to store a pointer | ||
1777 | - to a register window. | ||
1778 | - | ||
1779 | -- Use temporaries. Use local temporaries only when really needed, | ||
1780 | - e.g. when you need to use a value after a jump. Local temporaries | ||
1781 | - introduce a performance hit in the current TCG implementation: their | ||
1782 | - content is saved to memory at end of each basic block. | ||
1783 | - | ||
1784 | -- Free temporaries and local temporaries when they are no longer used | ||
1785 | - (tcg_temp_free). Since tcg_const_x() also creates a temporary, you | ||
1786 | - should free it after it is used. Freeing temporaries does not yield | ||
1787 | - a better generated code, but it reduces the memory usage of TCG and | ||
1788 | - the speed of the translation. | ||
1789 | - | ||
1790 | -- Don't hesitate to use helpers for complicated or seldom used guest | ||
1791 | - instructions. There is little performance advantage in using TCG to | ||
1792 | - implement guest instructions taking more than about twenty TCG | ||
1793 | - instructions. Note that this rule of thumb is more applicable to | ||
1794 | - helpers doing complex logic or arithmetic, where the C compiler has | ||
1795 | - scope to do a good job of optimisation; it is less relevant where | ||
1796 | - the instruction is mostly doing loads and stores, and in those cases | ||
1797 | - inline TCG may still be faster for longer sequences. | ||
1798 | - | ||
1799 | -- The hard limit on the number of TCG instructions you can generate | ||
1800 | - per guest instruction is set by MAX_OP_PER_INSTR in exec-all.h -- | ||
1801 | - you cannot exceed this without risking a buffer overrun. | ||
1802 | - | ||
1803 | -- Use the 'discard' instruction if you know that TCG won't be able to | ||
1804 | - prove that a given global is "dead" at a given program point. The | ||
1805 | - x86 guest uses it to improve the condition codes optimisation. | ||
1806 | -- | ||
1807 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Like CONFIG_TCG, the enabled method of execution is a host property | ||
2 | not a guest property. This exposes the define to compile-once files. | ||
1 | 3 | ||
4 | Acked-by: Paolo Bonzini <pbonzini@redhat.com> | ||
5 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | --- | ||
8 | meson.build | 4 +--- | ||
9 | 1 file changed, 1 insertion(+), 3 deletions(-) | ||
10 | |||
11 | diff --git a/meson.build b/meson.build | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/meson.build | ||
14 | +++ b/meson.build | ||
15 | @@ -XXX,XX +XXX,XX @@ if get_option('tcg').allowed() | ||
16 | endif | ||
17 | if get_option('tcg_interpreter') | ||
18 | tcg_arch = 'tci' | ||
19 | + config_host += { 'CONFIG_TCG_INTERPRETER': 'y' } | ||
20 | elif host_arch == 'x86_64' | ||
21 | tcg_arch = 'i386' | ||
22 | elif host_arch == 'ppc64' | ||
23 | @@ -XXX,XX +XXX,XX @@ foreach target : target_dirs | ||
24 | if sym == 'CONFIG_TCG' or target in accelerator_targets.get(sym, []) | ||
25 | config_target += { sym: 'y' } | ||
26 | config_all += { sym: 'y' } | ||
27 | - if sym == 'CONFIG_TCG' and tcg_arch == 'tci' | ||
28 | - config_target += { 'CONFIG_TCG_INTERPRETER': 'y' } | ||
29 | - endif | ||
30 | if target in modular_tcg | ||
31 | config_target += { 'CONFIG_TCG_MODULAR': 'y' } | ||
32 | else | ||
33 | -- | ||
34 | 2.34.1 | ||
35 | |||
36 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
1 | 2 | ||
3 | We are going to modify this code, so fix its style first to avoid: | ||
4 | |||
5 | ERROR: spaces required around that '*' (ctx:VxV) | ||
6 | #281: FILE: tcg/s390x/tcg-target.c.inc:1224: | ||
7 | + uintptr_t mask = ~(0xffffull << i*16); | ||
8 | ^ | ||
9 | |||
10 | Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> | ||
11 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
12 | Message-Id: <20221130132654.76369-2-philmd@linaro.org> | ||
13 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
14 | --- | ||
15 | tcg/s390x/tcg-target.c.inc | 20 ++++++++++---------- | ||
16 | 1 file changed, 10 insertions(+), 10 deletions(-) | ||
17 | |||
18 | diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/tcg/s390x/tcg-target.c.inc | ||
21 | +++ b/tcg/s390x/tcg-target.c.inc | ||
22 | @@ -XXX,XX +XXX,XX @@ static bool maybe_out_small_movi(TCGContext *s, TCGType type, | ||
23 | } | ||
24 | |||
25 | for (i = 0; i < 4; i++) { | ||
26 | - tcg_target_long mask = 0xffffull << i*16; | ||
27 | + tcg_target_long mask = 0xffffull << i * 16; | ||
28 | if ((uval & mask) == uval) { | ||
29 | - tcg_out_insn_RI(s, lli_insns[i], ret, uval >> i*16); | ||
30 | + tcg_out_insn_RI(s, lli_insns[i], ret, uval >> i * 16); | ||
31 | return true; | ||
32 | } | ||
33 | } | ||
34 | @@ -XXX,XX +XXX,XX @@ static void tgen_andi(TCGContext *s, TCGType type, TCGReg dest, uint64_t val) | ||
35 | |||
36 | /* Try all 32-bit insns that can perform it in one go. */ | ||
37 | for (i = 0; i < 4; i++) { | ||
38 | - tcg_target_ulong mask = ~(0xffffull << i*16); | ||
39 | + tcg_target_ulong mask = ~(0xffffull << i * 16); | ||
40 | if (((val | ~valid) & mask) == mask) { | ||
41 | - tcg_out_insn_RI(s, ni_insns[i], dest, val >> i*16); | ||
42 | + tcg_out_insn_RI(s, ni_insns[i], dest, val >> i * 16); | ||
43 | return; | ||
44 | } | ||
45 | } | ||
46 | @@ -XXX,XX +XXX,XX @@ static void tgen_andi(TCGContext *s, TCGType type, TCGReg dest, uint64_t val) | ||
47 | /* Try all 48-bit insns that can perform it in one go. */ | ||
48 | if (HAVE_FACILITY(EXT_IMM)) { | ||
49 | for (i = 0; i < 2; i++) { | ||
50 | - tcg_target_ulong mask = ~(0xffffffffull << i*32); | ||
51 | + tcg_target_ulong mask = ~(0xffffffffull << i * 32); | ||
52 | if (((val | ~valid) & mask) == mask) { | ||
53 | - tcg_out_insn_RIL(s, nif_insns[i], dest, val >> i*32); | ||
54 | + tcg_out_insn_RIL(s, nif_insns[i], dest, val >> i * 32); | ||
55 | return; | ||
56 | } | ||
57 | } | ||
58 | @@ -XXX,XX +XXX,XX @@ static void tgen_ori(TCGContext *s, TCGType type, TCGReg dest, uint64_t val) | ||
59 | |||
60 | /* Try all 32-bit insns that can perform it in one go. */ | ||
61 | for (i = 0; i < 4; i++) { | ||
62 | - tcg_target_ulong mask = (0xffffull << i*16); | ||
63 | + tcg_target_ulong mask = (0xffffull << i * 16); | ||
64 | if ((val & mask) != 0 && (val & ~mask) == 0) { | ||
65 | - tcg_out_insn_RI(s, oi_insns[i], dest, val >> i*16); | ||
66 | + tcg_out_insn_RI(s, oi_insns[i], dest, val >> i * 16); | ||
67 | return; | ||
68 | } | ||
69 | } | ||
70 | @@ -XXX,XX +XXX,XX @@ static void tgen_ori(TCGContext *s, TCGType type, TCGReg dest, uint64_t val) | ||
71 | /* Try all 48-bit insns that can perform it in one go. */ | ||
72 | if (HAVE_FACILITY(EXT_IMM)) { | ||
73 | for (i = 0; i < 2; i++) { | ||
74 | - tcg_target_ulong mask = (0xffffffffull << i*32); | ||
75 | + tcg_target_ulong mask = (0xffffffffull << i * 32); | ||
76 | if ((val & mask) != 0 && (val & ~mask) == 0) { | ||
77 | - tcg_out_insn_RIL(s, oif_insns[i], dest, val >> i*32); | ||
78 | + tcg_out_insn_RIL(s, oif_insns[i], dest, val >> i * 32); | ||
79 | return; | ||
80 | } | ||
81 | } | ||
82 | -- | ||
83 | 2.34.1 | ||
84 | |||
85 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | Remove whitespace at end of line, plus one place this also |
---|---|---|---|
2 | highlights some missing braces. | ||
3 | |||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 6 | --- |
4 | tcg/ppc/tcg-target-con-str.h | 30 +++++++++++++++ | 7 | tcg/tcg.c | 33 +++++++++++++++++---------------- |
5 | tcg/ppc/tcg-target.h | 1 + | 8 | tcg/ppc/tcg-target.c.inc | 2 +- |
6 | tcg/ppc/tcg-target.c.inc | 73 ++++++++---------------------------- | 9 | 2 files changed, 18 insertions(+), 17 deletions(-) |
7 | 3 files changed, 46 insertions(+), 58 deletions(-) | ||
8 | create mode 100644 tcg/ppc/tcg-target-con-str.h | ||
9 | 10 | ||
10 | diff --git a/tcg/ppc/tcg-target-con-str.h b/tcg/ppc/tcg-target-con-str.h | 11 | diff --git a/tcg/tcg.c b/tcg/tcg.c |
11 | new file mode 100644 | 12 | index XXXXXXX..XXXXXXX 100644 |
12 | index XXXXXXX..XXXXXXX | 13 | --- a/tcg/tcg.c |
13 | --- /dev/null | 14 | +++ b/tcg/tcg.c |
14 | +++ b/tcg/ppc/tcg-target-con-str.h | 15 | @@ -XXX,XX +XXX,XX @@ void *tcg_malloc_internal(TCGContext *s, int size) |
15 | @@ -XXX,XX +XXX,XX @@ | 16 | { |
16 | +/* SPDX-License-Identifier: MIT */ | 17 | TCGPool *p; |
17 | +/* | 18 | int pool_size; |
18 | + * Define PowerPC target-specific operand constraints. | 19 | - |
19 | + * Copyright (c) 2021 Linaro | ||
20 | + */ | ||
21 | + | 20 | + |
22 | +/* | 21 | if (size > TCG_POOL_CHUNK_SIZE) { |
23 | + * Define constraint letters for register sets: | 22 | /* big malloc: insert a new pool (XXX: could optimize) */ |
24 | + * REGS(letter, register_mask) | 23 | p = g_malloc(sizeof(TCGPool) + size); |
25 | + */ | 24 | @@ -XXX,XX +XXX,XX @@ void *tcg_malloc_internal(TCGContext *s, int size) |
26 | +REGS('r', ALL_GENERAL_REGS) | 25 | p = g_malloc(sizeof(TCGPool) + pool_size); |
27 | +REGS('v', ALL_VECTOR_REGS) | 26 | p->size = pool_size; |
28 | +REGS('A', 1u << TCG_REG_R3) | 27 | p->next = NULL; |
29 | +REGS('B', 1u << TCG_REG_R4) | 28 | - if (s->pool_current) |
30 | +REGS('C', 1u << TCG_REG_R5) | 29 | + if (s->pool_current) { |
31 | +REGS('D', 1u << TCG_REG_R6) | 30 | s->pool_current->next = p; |
32 | +REGS('L', ALL_QLOAD_REGS) | 31 | - else |
33 | +REGS('S', ALL_QSTORE_REGS) | 32 | + } else { |
33 | s->pool_first = p; | ||
34 | + } | ||
35 | } else { | ||
36 | p = p->next; | ||
37 | } | ||
38 | @@ -XXX,XX +XXX,XX @@ static void dump_regs(TCGContext *s) | ||
39 | |||
40 | for(i = 0; i < TCG_TARGET_NB_REGS; i++) { | ||
41 | if (s->reg_to_temp[i] != NULL) { | ||
42 | - printf("%s: %s\n", | ||
43 | - tcg_target_reg_names[i], | ||
44 | + printf("%s: %s\n", | ||
45 | + tcg_target_reg_names[i], | ||
46 | tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); | ||
47 | } | ||
48 | } | ||
49 | @@ -XXX,XX +XXX,XX @@ static void check_regs(TCGContext *s) | ||
50 | ts = s->reg_to_temp[reg]; | ||
51 | if (ts != NULL) { | ||
52 | if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { | ||
53 | - printf("Inconsistency for register %s:\n", | ||
54 | + printf("Inconsistency for register %s:\n", | ||
55 | tcg_target_reg_names[reg]); | ||
56 | goto fail; | ||
57 | } | ||
58 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
59 | nb_iargs = def->nb_iargs; | ||
60 | |||
61 | /* copy constants */ | ||
62 | - memcpy(new_args + nb_oargs + nb_iargs, | ||
63 | + memcpy(new_args + nb_oargs + nb_iargs, | ||
64 | op->args + nb_oargs + nb_iargs, | ||
65 | sizeof(TCGArg) * def->nb_cargs); | ||
66 | |||
67 | i_allocated_regs = s->reserved_regs; | ||
68 | o_allocated_regs = s->reserved_regs; | ||
69 | |||
70 | - /* satisfy input constraints */ | ||
71 | + /* satisfy input constraints */ | ||
72 | for (k = 0; k < nb_iargs; k++) { | ||
73 | TCGRegSet i_preferred_regs, o_preferred_regs; | ||
74 | |||
75 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
76 | const_args[i] = 0; | ||
77 | tcg_regset_set_reg(i_allocated_regs, reg); | ||
78 | } | ||
79 | - | ||
34 | + | 80 | + |
35 | +/* | 81 | /* mark dead temporaries and free the associated registers */ |
36 | + * Define constraint letters for constants: | 82 | for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { |
37 | + * CONST(letter, TCG_CT_CONST_* bit set) | 83 | if (IS_DEAD_ARG(i)) { |
38 | + */ | 84 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) |
39 | +CONST('I', TCG_CT_CONST_S16) | 85 | tcg_reg_alloc_bb_end(s, i_allocated_regs); |
40 | +CONST('J', TCG_CT_CONST_U16) | 86 | } else { |
41 | +CONST('M', TCG_CT_CONST_MONE) | 87 | if (def->flags & TCG_OPF_CALL_CLOBBER) { |
42 | +CONST('T', TCG_CT_CONST_S32) | 88 | - /* XXX: permit generic clobber register list ? */ |
43 | +CONST('U', TCG_CT_CONST_U32) | 89 | + /* XXX: permit generic clobber register list ? */ |
44 | +CONST('W', TCG_CT_CONST_WSZ) | 90 | for (i = 0; i < TCG_TARGET_NB_REGS; i++) { |
45 | +CONST('Z', TCG_CT_CONST_ZERO) | 91 | if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { |
46 | diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h | 92 | tcg_reg_free(s, i, i_allocated_regs); |
47 | index XXXXXXX..XXXXXXX 100644 | 93 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) |
48 | --- a/tcg/ppc/tcg-target.h | 94 | an exception. */ |
49 | +++ b/tcg/ppc/tcg-target.h | 95 | sync_globals(s, i_allocated_regs); |
50 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 96 | } |
51 | #define TCG_TARGET_NEED_LDST_LABELS | 97 | - |
98 | + | ||
99 | /* satisfy the output constraints */ | ||
100 | for(k = 0; k < nb_oargs; k++) { | ||
101 | i = def->args_ct[k].sort_index; | ||
102 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) | ||
103 | |||
104 | /* assign stack slots first */ | ||
105 | call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); | ||
106 | - call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & | ||
107 | + call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & | ||
108 | ~(TCG_TARGET_STACK_ALIGN - 1); | ||
109 | allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); | ||
110 | if (allocate_args) { | ||
111 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) | ||
112 | stack_offset += sizeof(tcg_target_long); | ||
52 | #endif | 113 | #endif |
53 | #define TCG_TARGET_NEED_POOL_LABELS | 114 | } |
54 | +#define TCG_TARGET_CON_STR_H | 115 | - |
55 | 116 | + | |
56 | #endif | 117 | /* assign input registers */ |
118 | allocated_regs = s->reserved_regs; | ||
119 | for (i = 0; i < nb_regs; i++) { | ||
120 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) | ||
121 | tcg_regset_set_reg(allocated_regs, reg); | ||
122 | } | ||
123 | } | ||
124 | - | ||
125 | + | ||
126 | /* mark dead temporaries and free the associated registers */ | ||
127 | for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { | ||
128 | if (IS_DEAD_ARG(i)) { | ||
129 | temp_dead(s, arg_temp(op->args[i])); | ||
130 | } | ||
131 | } | ||
132 | - | ||
133 | + | ||
134 | /* clobber call registers */ | ||
135 | for (i = 0; i < TCG_TARGET_NB_REGS; i++) { | ||
136 | if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { | ||
137 | @@ -XXX,XX +XXX,XX @@ void tcg_dump_info(GString *buf) | ||
138 | (double)s->code_out_len / tb_div_count); | ||
139 | g_string_append_printf(buf, "avg search data/TB %0.1f\n", | ||
140 | (double)s->search_out_len / tb_div_count); | ||
141 | - | ||
142 | + | ||
143 | g_string_append_printf(buf, "cycles/op %0.1f\n", | ||
144 | s->op_count ? (double)tot / s->op_count : 0); | ||
145 | g_string_append_printf(buf, "cycles/in byte %0.1f\n", | ||
57 | diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc | 146 | diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc |
58 | index XXXXXXX..XXXXXXX 100644 | 147 | index XXXXXXX..XXXXXXX 100644 |
59 | --- a/tcg/ppc/tcg-target.c.inc | 148 | --- a/tcg/ppc/tcg-target.c.inc |
60 | +++ b/tcg/ppc/tcg-target.c.inc | 149 | +++ b/tcg/ppc/tcg-target.c.inc |
61 | @@ -XXX,XX +XXX,XX @@ | 150 | @@ -XXX,XX +XXX,XX @@ |
62 | #define TCG_CT_CONST_MONE 0x2000 | 151 | # else |
63 | #define TCG_CT_CONST_WSZ 0x4000 | 152 | # error "Unknown ABI" |
64 | 153 | # endif | |
65 | +#define ALL_GENERAL_REGS 0xffffffffu | 154 | -#endif |
66 | +#define ALL_VECTOR_REGS 0xffffffff00000000ull | ||
67 | + | ||
68 | +#ifdef CONFIG_SOFTMMU | ||
69 | +#define ALL_QLOAD_REGS \ | ||
70 | + (ALL_GENERAL_REGS & \ | ||
71 | + ~((1 << TCG_REG_R3) | (1 << TCG_REG_R4) | (1 << TCG_REG_R5))) | ||
72 | +#define ALL_QSTORE_REGS \ | ||
73 | + (ALL_GENERAL_REGS & ~((1 << TCG_REG_R3) | (1 << TCG_REG_R4) | \ | ||
74 | + (1 << TCG_REG_R5) | (1 << TCG_REG_R6))) | ||
75 | +#else | ||
76 | +#define ALL_QLOAD_REGS (ALL_GENERAL_REGS & ~(1 << TCG_REG_R3)) | ||
77 | +#define ALL_QSTORE_REGS ALL_QLOAD_REGS | ||
78 | +#endif | 155 | +#endif |
79 | + | 156 | |
80 | TCGPowerISA have_isa; | 157 | #ifdef _CALL_SYSV |
81 | static bool have_isel; | 158 | # define TCG_TARGET_CALL_ALIGN_ARGS 1 |
82 | bool have_altivec; | ||
83 | @@ -XXX,XX +XXX,XX @@ static bool reloc_pc14(tcg_insn_unit *src_rw, const tcg_insn_unit *target) | ||
84 | return false; | ||
85 | } | ||
86 | |||
87 | -/* parse target specific constraints */ | ||
88 | -static const char *target_parse_constraint(TCGArgConstraint *ct, | ||
89 | - const char *ct_str, TCGType type) | ||
90 | -{ | ||
91 | - switch (*ct_str++) { | ||
92 | - case 'A': case 'B': case 'C': case 'D': | ||
93 | - tcg_regset_set_reg(ct->regs, 3 + ct_str[0] - 'A'); | ||
94 | - break; | ||
95 | - case 'r': | ||
96 | - ct->regs = 0xffffffff; | ||
97 | - break; | ||
98 | - case 'v': | ||
99 | - ct->regs = 0xffffffff00000000ull; | ||
100 | - break; | ||
101 | - case 'L': /* qemu_ld constraint */ | ||
102 | - ct->regs = 0xffffffff; | ||
103 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R3); | ||
104 | -#ifdef CONFIG_SOFTMMU | ||
105 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R4); | ||
106 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R5); | ||
107 | -#endif | ||
108 | - break; | ||
109 | - case 'S': /* qemu_st constraint */ | ||
110 | - ct->regs = 0xffffffff; | ||
111 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R3); | ||
112 | -#ifdef CONFIG_SOFTMMU | ||
113 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R4); | ||
114 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R5); | ||
115 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R6); | ||
116 | -#endif | ||
117 | - break; | ||
118 | - case 'I': | ||
119 | - ct->ct |= TCG_CT_CONST_S16; | ||
120 | - break; | ||
121 | - case 'J': | ||
122 | - ct->ct |= TCG_CT_CONST_U16; | ||
123 | - break; | ||
124 | - case 'M': | ||
125 | - ct->ct |= TCG_CT_CONST_MONE; | ||
126 | - break; | ||
127 | - case 'T': | ||
128 | - ct->ct |= TCG_CT_CONST_S32; | ||
129 | - break; | ||
130 | - case 'U': | ||
131 | - ct->ct |= TCG_CT_CONST_U32; | ||
132 | - break; | ||
133 | - case 'W': | ||
134 | - ct->ct |= TCG_CT_CONST_WSZ; | ||
135 | - break; | ||
136 | - case 'Z': | ||
137 | - ct->ct |= TCG_CT_CONST_ZERO; | ||
138 | - break; | ||
139 | - default: | ||
140 | - return NULL; | ||
141 | - } | ||
142 | - return ct_str; | ||
143 | -} | ||
144 | - | ||
145 | /* test if a constant matches the constraint */ | ||
146 | static int tcg_target_const_match(tcg_target_long val, TCGType type, | ||
147 | const TCGArgConstraint *arg_ct) | ||
148 | -- | 159 | -- |
149 | 2.25.1 | 160 | 2.34.1 |
150 | 161 | ||
151 | 162 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Create a wrapper for locking/unlocking the iothread lock. | ||
1 | 2 | ||
3 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
4 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
5 | --- | ||
6 | include/qemu/main-loop.h | 29 +++++++++++++++++++++++++++++ | ||
7 | 1 file changed, 29 insertions(+) | ||
8 | |||
9 | diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h | ||
10 | index XXXXXXX..XXXXXXX 100644 | ||
11 | --- a/include/qemu/main-loop.h | ||
12 | +++ b/include/qemu/main-loop.h | ||
13 | @@ -XXX,XX +XXX,XX @@ void qemu_mutex_lock_iothread_impl(const char *file, int line); | ||
14 | */ | ||
15 | void qemu_mutex_unlock_iothread(void); | ||
16 | |||
17 | +/** | ||
18 | + * QEMU_IOTHREAD_LOCK_GUARD | ||
19 | + * | ||
20 | + * Wrap a block of code in a conditional qemu_mutex_{lock,unlock}_iothread. | ||
21 | + */ | ||
22 | +typedef struct IOThreadLockAuto IOThreadLockAuto; | ||
23 | + | ||
24 | +static inline IOThreadLockAuto *qemu_iothread_auto_lock(const char *file, | ||
25 | + int line) | ||
26 | +{ | ||
27 | + if (qemu_mutex_iothread_locked()) { | ||
28 | + return NULL; | ||
29 | + } | ||
30 | + qemu_mutex_lock_iothread_impl(file, line); | ||
31 | + /* Anything non-NULL causes the cleanup function to be called */ | ||
32 | + return (IOThreadLockAuto *)(uintptr_t)1; | ||
33 | +} | ||
34 | + | ||
35 | +static inline void qemu_iothread_auto_unlock(IOThreadLockAuto *l) | ||
36 | +{ | ||
37 | + qemu_mutex_unlock_iothread(); | ||
38 | +} | ||
39 | + | ||
40 | +G_DEFINE_AUTOPTR_CLEANUP_FUNC(IOThreadLockAuto, qemu_iothread_auto_unlock) | ||
41 | + | ||
42 | +#define QEMU_IOTHREAD_LOCK_GUARD() \ | ||
43 | + g_autoptr(IOThreadLockAuto) _iothread_lock_auto __attribute__((unused)) \ | ||
44 | + = qemu_iothread_auto_lock(__FILE__, __LINE__) | ||
45 | + | ||
46 | /* | ||
47 | * qemu_cond_wait_iothread: Wait on condition for the main loop mutex | ||
48 | * | ||
49 | -- | ||
50 | 2.34.1 | ||
51 | |||
52 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
3 | --- | ||
4 | hw/mips/mips_int.c | 11 +---------- | ||
5 | 1 file changed, 1 insertion(+), 10 deletions(-) | ||
1 | 6 | ||
7 | diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c | ||
8 | index XXXXXXX..XXXXXXX 100644 | ||
9 | --- a/hw/mips/mips_int.c | ||
10 | +++ b/hw/mips/mips_int.c | ||
11 | @@ -XXX,XX +XXX,XX @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) | ||
12 | MIPSCPU *cpu = opaque; | ||
13 | CPUMIPSState *env = &cpu->env; | ||
14 | CPUState *cs = CPU(cpu); | ||
15 | - bool locked = false; | ||
16 | |||
17 | if (irq < 0 || irq > 7) { | ||
18 | return; | ||
19 | } | ||
20 | |||
21 | - /* Make sure locking works even if BQL is already held by the caller */ | ||
22 | - if (!qemu_mutex_iothread_locked()) { | ||
23 | - locked = true; | ||
24 | - qemu_mutex_lock_iothread(); | ||
25 | - } | ||
26 | + QEMU_IOTHREAD_LOCK_GUARD(); | ||
27 | |||
28 | if (level) { | ||
29 | env->CP0_Cause |= 1 << (irq + CP0Ca_IP); | ||
30 | @@ -XXX,XX +XXX,XX @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) | ||
31 | } else { | ||
32 | cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); | ||
33 | } | ||
34 | - | ||
35 | - if (locked) { | ||
36 | - qemu_mutex_unlock_iothread(); | ||
37 | - } | ||
38 | } | ||
39 | |||
40 | void cpu_mips_irq_init_cpu(MIPSCPU *cpu) | ||
41 | -- | ||
42 | 2.34.1 | ||
43 | |||
44 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com> | ||
3 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
4 | --- | ||
5 | target/ppc/excp_helper.c | 11 +---------- | ||
6 | 1 file changed, 1 insertion(+), 10 deletions(-) | ||
1 | 7 | ||
8 | diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/target/ppc/excp_helper.c | ||
11 | +++ b/target/ppc/excp_helper.c | ||
12 | @@ -XXX,XX +XXX,XX @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env) | ||
13 | void ppc_maybe_interrupt(CPUPPCState *env) | ||
14 | { | ||
15 | CPUState *cs = env_cpu(env); | ||
16 | - bool locked = false; | ||
17 | - | ||
18 | - if (!qemu_mutex_iothread_locked()) { | ||
19 | - locked = true; | ||
20 | - qemu_mutex_lock_iothread(); | ||
21 | - } | ||
22 | + QEMU_IOTHREAD_LOCK_GUARD(); | ||
23 | |||
24 | if (ppc_next_unmasked_interrupt(env)) { | ||
25 | cpu_interrupt(cs, CPU_INTERRUPT_HARD); | ||
26 | } else { | ||
27 | cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); | ||
28 | } | ||
29 | - | ||
30 | - if (locked) { | ||
31 | - qemu_mutex_unlock_iothread(); | ||
32 | - } | ||
33 | } | ||
34 | |||
35 | #if defined(TARGET_PPC64) | ||
36 | -- | ||
37 | 2.34.1 | ||
38 | |||
39 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | In addition, use tcg_enabled instead of !kvm_enabled. | ||
1 | 2 | ||
3 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
4 | Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com> | ||
5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | --- | ||
7 | target/ppc/helper_regs.c | 14 ++++---------- | ||
8 | 1 file changed, 4 insertions(+), 10 deletions(-) | ||
9 | |||
10 | diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/target/ppc/helper_regs.c | ||
13 | +++ b/target/ppc/helper_regs.c | ||
14 | @@ -XXX,XX +XXX,XX @@ | ||
15 | #include "qemu/main-loop.h" | ||
16 | #include "exec/exec-all.h" | ||
17 | #include "sysemu/kvm.h" | ||
18 | +#include "sysemu/tcg.h" | ||
19 | #include "helper_regs.h" | ||
20 | #include "power8-pmu.h" | ||
21 | #include "cpu-models.h" | ||
22 | @@ -XXX,XX +XXX,XX @@ void cpu_interrupt_exittb(CPUState *cs) | ||
23 | { | ||
24 | /* | ||
25 | * We don't need to worry about translation blocks | ||
26 | - * when running with KVM. | ||
27 | + * unless running with TCG. | ||
28 | */ | ||
29 | - if (kvm_enabled()) { | ||
30 | - return; | ||
31 | - } | ||
32 | - | ||
33 | - if (!qemu_mutex_iothread_locked()) { | ||
34 | - qemu_mutex_lock_iothread(); | ||
35 | - cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); | ||
36 | - qemu_mutex_unlock_iothread(); | ||
37 | - } else { | ||
38 | + if (tcg_enabled()) { | ||
39 | + QEMU_IOTHREAD_LOCK_GUARD(); | ||
40 | cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); | ||
41 | } | ||
42 | } | ||
43 | -- | ||
44 | 2.34.1 | ||
45 | |||
46 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
---|---|---|---|
2 | Reviewed-by: Alistair Francis <alistair.francis@wdc.com> | 2 | Reviewed-by: Alistair Francis <alistair.francis@wdc.com> |
3 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 3 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
4 | --- | 4 | --- |
5 | tcg/riscv/tcg-target-con-set.h | 30 ++++++++++++ | 5 | target/riscv/cpu_helper.c | 10 +--------- |
6 | tcg/riscv/tcg-target.h | 1 + | 6 | 1 file changed, 1 insertion(+), 9 deletions(-) |
7 | tcg/riscv/tcg-target.c.inc | 83 ++++++++++------------------------ | ||
8 | 3 files changed, 54 insertions(+), 60 deletions(-) | ||
9 | create mode 100644 tcg/riscv/tcg-target-con-set.h | ||
10 | 7 | ||
11 | diff --git a/tcg/riscv/tcg-target-con-set.h b/tcg/riscv/tcg-target-con-set.h | 8 | diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c |
12 | new file mode 100644 | ||
13 | index XXXXXXX..XXXXXXX | ||
14 | --- /dev/null | ||
15 | +++ b/tcg/riscv/tcg-target-con-set.h | ||
16 | @@ -XXX,XX +XXX,XX @@ | ||
17 | +/* SPDX-License-Identifier: MIT */ | ||
18 | +/* | ||
19 | + * Define RISC-V target-specific constraint sets. | ||
20 | + * Copyright (c) 2021 Linaro | ||
21 | + */ | ||
22 | + | ||
23 | +/* | ||
24 | + * C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs. | ||
25 | + * Each operand should be a sequence of constraint letters as defined by | ||
26 | + * tcg-target-con-str.h; the constraint combination is inclusive or. | ||
27 | + */ | ||
28 | +C_O0_I1(r) | ||
29 | +C_O0_I2(LZ, L) | ||
30 | +C_O0_I2(rZ, r) | ||
31 | +C_O0_I2(rZ, rZ) | ||
32 | +C_O0_I3(LZ, L, L) | ||
33 | +C_O0_I3(LZ, LZ, L) | ||
34 | +C_O0_I4(LZ, LZ, L, L) | ||
35 | +C_O0_I4(rZ, rZ, rZ, rZ) | ||
36 | +C_O1_I1(r, L) | ||
37 | +C_O1_I1(r, r) | ||
38 | +C_O1_I2(r, L, L) | ||
39 | +C_O1_I2(r, r, ri) | ||
40 | +C_O1_I2(r, r, rI) | ||
41 | +C_O1_I2(r, rZ, rN) | ||
42 | +C_O1_I2(r, rZ, rZ) | ||
43 | +C_O1_I4(r, rZ, rZ, rZ, rZ) | ||
44 | +C_O2_I1(r, r, L) | ||
45 | +C_O2_I2(r, r, L, L) | ||
46 | +C_O2_I4(r, r, rZ, rZ, rM, rM) | ||
47 | diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h | ||
48 | index XXXXXXX..XXXXXXX 100644 | 9 | index XXXXXXX..XXXXXXX 100644 |
49 | --- a/tcg/riscv/tcg-target.h | 10 | --- a/target/riscv/cpu_helper.c |
50 | +++ b/tcg/riscv/tcg-target.h | 11 | +++ b/target/riscv/cpu_helper.c |
51 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 12 | @@ -XXX,XX +XXX,XX @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) |
52 | #define TCG_TARGET_NEED_POOL_LABELS | 13 | CPURISCVState *env = &cpu->env; |
53 | 14 | CPUState *cs = CPU(cpu); | |
54 | #define TCG_TARGET_HAS_MEMORY_BSWAP 0 | 15 | uint64_t gein, vsgein = 0, vstip = 0, old = env->mip; |
55 | +#define TCG_TARGET_CON_SET_H | 16 | - bool locked = false; |
56 | 17 | ||
57 | #endif | 18 | if (riscv_cpu_virt_enabled(env)) { |
58 | diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc | 19 | gein = get_field(env->hstatus, HSTATUS_VGEIN); |
59 | index XXXXXXX..XXXXXXX 100644 | 20 | @@ -XXX,XX +XXX,XX @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) |
60 | --- a/tcg/riscv/tcg-target.c.inc | 21 | mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask; |
61 | +++ b/tcg/riscv/tcg-target.c.inc | 22 | vstip = env->vstime_irq ? MIP_VSTIP : 0; |
62 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, | 23 | |
24 | - if (!qemu_mutex_iothread_locked()) { | ||
25 | - locked = true; | ||
26 | - qemu_mutex_lock_iothread(); | ||
27 | - } | ||
28 | + QEMU_IOTHREAD_LOCK_GUARD(); | ||
29 | |||
30 | env->mip = (env->mip & ~mask) | (value & mask); | ||
31 | |||
32 | @@ -XXX,XX +XXX,XX @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) | ||
33 | cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); | ||
63 | } | 34 | } |
35 | |||
36 | - if (locked) { | ||
37 | - qemu_mutex_unlock_iothread(); | ||
38 | - } | ||
39 | - | ||
40 | return old; | ||
64 | } | 41 | } |
65 | 42 | ||
66 | -static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
67 | +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) | ||
68 | { | ||
69 | - static const TCGTargetOpDef r | ||
70 | - = { .args_ct_str = { "r" } }; | ||
71 | - static const TCGTargetOpDef r_r | ||
72 | - = { .args_ct_str = { "r", "r" } }; | ||
73 | - static const TCGTargetOpDef rZ_r | ||
74 | - = { .args_ct_str = { "rZ", "r" } }; | ||
75 | - static const TCGTargetOpDef rZ_rZ | ||
76 | - = { .args_ct_str = { "rZ", "rZ" } }; | ||
77 | - static const TCGTargetOpDef rZ_rZ_rZ_rZ | ||
78 | - = { .args_ct_str = { "rZ", "rZ", "rZ", "rZ" } }; | ||
79 | - static const TCGTargetOpDef r_r_ri | ||
80 | - = { .args_ct_str = { "r", "r", "ri" } }; | ||
81 | - static const TCGTargetOpDef r_r_rI | ||
82 | - = { .args_ct_str = { "r", "r", "rI" } }; | ||
83 | - static const TCGTargetOpDef r_rZ_rN | ||
84 | - = { .args_ct_str = { "r", "rZ", "rN" } }; | ||
85 | - static const TCGTargetOpDef r_rZ_rZ | ||
86 | - = { .args_ct_str = { "r", "rZ", "rZ" } }; | ||
87 | - static const TCGTargetOpDef r_rZ_rZ_rZ_rZ | ||
88 | - = { .args_ct_str = { "r", "rZ", "rZ", "rZ", "rZ" } }; | ||
89 | - static const TCGTargetOpDef r_L | ||
90 | - = { .args_ct_str = { "r", "L" } }; | ||
91 | - static const TCGTargetOpDef r_r_L | ||
92 | - = { .args_ct_str = { "r", "r", "L" } }; | ||
93 | - static const TCGTargetOpDef r_L_L | ||
94 | - = { .args_ct_str = { "r", "L", "L" } }; | ||
95 | - static const TCGTargetOpDef r_r_L_L | ||
96 | - = { .args_ct_str = { "r", "r", "L", "L" } }; | ||
97 | - static const TCGTargetOpDef LZ_L | ||
98 | - = { .args_ct_str = { "LZ", "L" } }; | ||
99 | - static const TCGTargetOpDef LZ_L_L | ||
100 | - = { .args_ct_str = { "LZ", "L", "L" } }; | ||
101 | - static const TCGTargetOpDef LZ_LZ_L | ||
102 | - = { .args_ct_str = { "LZ", "LZ", "L" } }; | ||
103 | - static const TCGTargetOpDef LZ_LZ_L_L | ||
104 | - = { .args_ct_str = { "LZ", "LZ", "L", "L" } }; | ||
105 | - static const TCGTargetOpDef r_r_rZ_rZ_rM_rM | ||
106 | - = { .args_ct_str = { "r", "r", "rZ", "rZ", "rM", "rM" } }; | ||
107 | - | ||
108 | switch (op) { | ||
109 | case INDEX_op_goto_ptr: | ||
110 | - return &r; | ||
111 | + return C_O0_I1(r); | ||
112 | |||
113 | case INDEX_op_ld8u_i32: | ||
114 | case INDEX_op_ld8s_i32: | ||
115 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
116 | case INDEX_op_extrl_i64_i32: | ||
117 | case INDEX_op_extrh_i64_i32: | ||
118 | case INDEX_op_ext_i32_i64: | ||
119 | - return &r_r; | ||
120 | + return C_O1_I1(r, r); | ||
121 | |||
122 | case INDEX_op_st8_i32: | ||
123 | case INDEX_op_st16_i32: | ||
124 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
125 | case INDEX_op_st16_i64: | ||
126 | case INDEX_op_st32_i64: | ||
127 | case INDEX_op_st_i64: | ||
128 | - return &rZ_r; | ||
129 | + return C_O0_I2(rZ, r); | ||
130 | |||
131 | case INDEX_op_add_i32: | ||
132 | case INDEX_op_and_i32: | ||
133 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
134 | case INDEX_op_and_i64: | ||
135 | case INDEX_op_or_i64: | ||
136 | case INDEX_op_xor_i64: | ||
137 | - return &r_r_rI; | ||
138 | + return C_O1_I2(r, r, rI); | ||
139 | |||
140 | case INDEX_op_sub_i32: | ||
141 | case INDEX_op_sub_i64: | ||
142 | - return &r_rZ_rN; | ||
143 | + return C_O1_I2(r, rZ, rN); | ||
144 | |||
145 | case INDEX_op_mul_i32: | ||
146 | case INDEX_op_mulsh_i32: | ||
147 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
148 | case INDEX_op_rem_i64: | ||
149 | case INDEX_op_remu_i64: | ||
150 | case INDEX_op_setcond_i64: | ||
151 | - return &r_rZ_rZ; | ||
152 | + return C_O1_I2(r, rZ, rZ); | ||
153 | |||
154 | case INDEX_op_shl_i32: | ||
155 | case INDEX_op_shr_i32: | ||
156 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
157 | case INDEX_op_shl_i64: | ||
158 | case INDEX_op_shr_i64: | ||
159 | case INDEX_op_sar_i64: | ||
160 | - return &r_r_ri; | ||
161 | + return C_O1_I2(r, r, ri); | ||
162 | |||
163 | case INDEX_op_brcond_i32: | ||
164 | case INDEX_op_brcond_i64: | ||
165 | - return &rZ_rZ; | ||
166 | + return C_O0_I2(rZ, rZ); | ||
167 | |||
168 | case INDEX_op_add2_i32: | ||
169 | case INDEX_op_add2_i64: | ||
170 | case INDEX_op_sub2_i32: | ||
171 | case INDEX_op_sub2_i64: | ||
172 | - return &r_r_rZ_rZ_rM_rM; | ||
173 | + return C_O2_I4(r, r, rZ, rZ, rM, rM); | ||
174 | |||
175 | case INDEX_op_brcond2_i32: | ||
176 | - return &rZ_rZ_rZ_rZ; | ||
177 | + return C_O0_I4(rZ, rZ, rZ, rZ); | ||
178 | |||
179 | case INDEX_op_setcond2_i32: | ||
180 | - return &r_rZ_rZ_rZ_rZ; | ||
181 | + return C_O1_I4(r, rZ, rZ, rZ, rZ); | ||
182 | |||
183 | case INDEX_op_qemu_ld_i32: | ||
184 | - return TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &r_L : &r_L_L; | ||
185 | + return (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS | ||
186 | + ? C_O1_I1(r, L) : C_O1_I2(r, L, L)); | ||
187 | case INDEX_op_qemu_st_i32: | ||
188 | - return TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &LZ_L : &LZ_L_L; | ||
189 | + return (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS | ||
190 | + ? C_O0_I2(LZ, L) : C_O0_I3(LZ, L, L)); | ||
191 | case INDEX_op_qemu_ld_i64: | ||
192 | - return TCG_TARGET_REG_BITS == 64 ? &r_L | ||
193 | - : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &r_r_L | ||
194 | - : &r_r_L_L; | ||
195 | + return (TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, L) | ||
196 | + : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? C_O2_I1(r, r, L) | ||
197 | + : C_O2_I2(r, r, L, L)); | ||
198 | case INDEX_op_qemu_st_i64: | ||
199 | - return TCG_TARGET_REG_BITS == 64 ? &LZ_L | ||
200 | - : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &LZ_LZ_L | ||
201 | - : &LZ_LZ_L_L; | ||
202 | + return (TCG_TARGET_REG_BITS == 64 ? C_O0_I2(LZ, L) | ||
203 | + : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? C_O0_I3(LZ, LZ, L) | ||
204 | + : C_O0_I4(LZ, LZ, L, L)); | ||
205 | |||
206 | default: | ||
207 | - return NULL; | ||
208 | + g_assert_not_reached(); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | -- | 43 | -- |
213 | 2.25.1 | 44 | 2.34.1 |
214 | 45 | ||
215 | 46 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com> | ||
3 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
4 | --- | ||
5 | hw/ppc/ppc.c | 10 +--------- | ||
6 | 1 file changed, 1 insertion(+), 9 deletions(-) | ||
1 | 7 | ||
8 | diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/hw/ppc/ppc.c | ||
11 | +++ b/hw/ppc/ppc.c | ||
12 | @@ -XXX,XX +XXX,XX @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level) | ||
13 | { | ||
14 | CPUPPCState *env = &cpu->env; | ||
15 | unsigned int old_pending; | ||
16 | - bool locked = false; | ||
17 | |||
18 | /* We may already have the BQL if coming from the reset path */ | ||
19 | - if (!qemu_mutex_iothread_locked()) { | ||
20 | - locked = true; | ||
21 | - qemu_mutex_lock_iothread(); | ||
22 | - } | ||
23 | + QEMU_IOTHREAD_LOCK_GUARD(); | ||
24 | |||
25 | old_pending = env->pending_interrupts; | ||
26 | |||
27 | @@ -XXX,XX +XXX,XX @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level) | ||
28 | |||
29 | trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts, | ||
30 | CPU(cpu)->interrupt_request); | ||
31 | - | ||
32 | - if (locked) { | ||
33 | - qemu_mutex_unlock_iothread(); | ||
34 | - } | ||
35 | } | ||
36 | |||
37 | /* PowerPC 6xx / 7xx internal IRQ controller */ | ||
38 | -- | ||
39 | 2.34.1 | ||
40 | |||
41 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | Narrow the scope of the lock to the actual read/write, |
---|---|---|---|
2 | moving the cpu_transation_failed call outside the lock. | ||
3 | |||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 6 | --- |
4 | tcg/s390/tcg-target-con-set.h | 29 ++++++++ | 7 | accel/tcg/cputlb.c | 25 ++++++++----------------- |
5 | tcg/s390/tcg-target.h | 1 + | 8 | 1 file changed, 8 insertions(+), 17 deletions(-) |
6 | tcg/s390/tcg-target.c.inc | 121 ++++++++++++++-------------------- | ||
7 | 3 files changed, 81 insertions(+), 70 deletions(-) | ||
8 | create mode 100644 tcg/s390/tcg-target-con-set.h | ||
9 | 9 | ||
10 | diff --git a/tcg/s390/tcg-target-con-set.h b/tcg/s390/tcg-target-con-set.h | 10 | diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c |
11 | new file mode 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
12 | index XXXXXXX..XXXXXXX | 12 | --- a/accel/tcg/cputlb.c |
13 | --- /dev/null | 13 | +++ b/accel/tcg/cputlb.c |
14 | +++ b/tcg/s390/tcg-target-con-set.h | 14 | @@ -XXX,XX +XXX,XX @@ static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full, |
15 | @@ -XXX,XX +XXX,XX @@ | 15 | MemoryRegionSection *section; |
16 | +/* SPDX-License-Identifier: MIT */ | 16 | MemoryRegion *mr; |
17 | +/* | 17 | uint64_t val; |
18 | + * Define S390 target-specific constraint sets. | 18 | - bool locked = false; |
19 | + * Copyright (c) 2021 Linaro | 19 | MemTxResult r; |
20 | + */ | 20 | |
21 | section = iotlb_to_section(cpu, full->xlat_section, full->attrs); | ||
22 | @@ -XXX,XX +XXX,XX @@ static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full, | ||
23 | cpu_io_recompile(cpu, retaddr); | ||
24 | } | ||
25 | |||
26 | - if (!qemu_mutex_iothread_locked()) { | ||
27 | - qemu_mutex_lock_iothread(); | ||
28 | - locked = true; | ||
29 | + { | ||
30 | + QEMU_IOTHREAD_LOCK_GUARD(); | ||
31 | + r = memory_region_dispatch_read(mr, mr_offset, &val, op, full->attrs); | ||
32 | } | ||
33 | - r = memory_region_dispatch_read(mr, mr_offset, &val, op, full->attrs); | ||
21 | + | 34 | + |
22 | +/* | 35 | if (r != MEMTX_OK) { |
23 | + * C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs. | 36 | hwaddr physaddr = mr_offset + |
24 | + * Each operand should be a sequence of constraint letters as defined by | 37 | section->offset_within_address_space - |
25 | + * tcg-target-con-str.h; the constraint combination is inclusive or. | 38 | @@ -XXX,XX +XXX,XX @@ static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full, |
26 | + */ | 39 | cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), access_type, |
27 | +C_O0_I1(r) | 40 | mmu_idx, full->attrs, r, retaddr); |
28 | +C_O0_I2(L, L) | ||
29 | +C_O0_I2(r, r) | ||
30 | +C_O0_I2(r, ri) | ||
31 | +C_O1_I1(r, L) | ||
32 | +C_O1_I1(r, r) | ||
33 | +C_O1_I2(r, 0, ri) | ||
34 | +C_O1_I2(r, 0, rI) | ||
35 | +C_O1_I2(r, 0, rJ) | ||
36 | +C_O1_I2(r, r, ri) | ||
37 | +C_O1_I2(r, rZ, r) | ||
38 | +C_O1_I4(r, r, ri, r, 0) | ||
39 | +C_O1_I4(r, r, ri, rI, 0) | ||
40 | +C_O2_I2(b, a, 0, r) | ||
41 | +C_O2_I3(b, a, 0, 1, r) | ||
42 | +C_O2_I4(r, r, 0, 1, rA, r) | ||
43 | +C_O2_I4(r, r, 0, 1, ri, r) | ||
44 | +C_O2_I4(r, r, 0, 1, r, r) | ||
45 | diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h | ||
46 | index XXXXXXX..XXXXXXX 100644 | ||
47 | --- a/tcg/s390/tcg-target.h | ||
48 | +++ b/tcg/s390/tcg-target.h | ||
49 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | ||
50 | #define TCG_TARGET_NEED_LDST_LABELS | ||
51 | #endif | ||
52 | #define TCG_TARGET_NEED_POOL_LABELS | ||
53 | +#define TCG_TARGET_CON_SET_H | ||
54 | |||
55 | #endif | ||
56 | diff --git a/tcg/s390/tcg-target.c.inc b/tcg/s390/tcg-target.c.inc | ||
57 | index XXXXXXX..XXXXXXX 100644 | ||
58 | --- a/tcg/s390/tcg-target.c.inc | ||
59 | +++ b/tcg/s390/tcg-target.c.inc | ||
60 | @@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, | ||
61 | } | 41 | } |
42 | - if (locked) { | ||
43 | - qemu_mutex_unlock_iothread(); | ||
44 | - } | ||
45 | - | ||
46 | return val; | ||
62 | } | 47 | } |
63 | 48 | ||
64 | -static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | 49 | @@ -XXX,XX +XXX,XX @@ static void io_writex(CPUArchState *env, CPUTLBEntryFull *full, |
65 | +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) | 50 | hwaddr mr_offset; |
66 | { | 51 | MemoryRegionSection *section; |
67 | - static const TCGTargetOpDef r = { .args_ct_str = { "r" } }; | 52 | MemoryRegion *mr; |
68 | - static const TCGTargetOpDef r_r = { .args_ct_str = { "r", "r" } }; | 53 | - bool locked = false; |
69 | - static const TCGTargetOpDef r_L = { .args_ct_str = { "r", "L" } }; | 54 | MemTxResult r; |
70 | - static const TCGTargetOpDef L_L = { .args_ct_str = { "L", "L" } }; | 55 | |
71 | - static const TCGTargetOpDef r_ri = { .args_ct_str = { "r", "ri" } }; | 56 | section = iotlb_to_section(cpu, full->xlat_section, full->attrs); |
72 | - static const TCGTargetOpDef r_r_ri = { .args_ct_str = { "r", "r", "ri" } }; | 57 | @@ -XXX,XX +XXX,XX @@ static void io_writex(CPUArchState *env, CPUTLBEntryFull *full, |
73 | - static const TCGTargetOpDef r_0_ri = { .args_ct_str = { "r", "0", "ri" } }; | 58 | */ |
74 | - static const TCGTargetOpDef r_0_rI = { .args_ct_str = { "r", "0", "rI" } }; | 59 | save_iotlb_data(cpu, section, mr_offset); |
75 | - static const TCGTargetOpDef r_0_rJ = { .args_ct_str = { "r", "0", "rJ" } }; | 60 | |
76 | - static const TCGTargetOpDef a2_r | 61 | - if (!qemu_mutex_iothread_locked()) { |
77 | - = { .args_ct_str = { "r", "r", "0", "1", "r", "r" } }; | 62 | - qemu_mutex_lock_iothread(); |
78 | - static const TCGTargetOpDef a2_ri | 63 | - locked = true; |
79 | - = { .args_ct_str = { "r", "r", "0", "1", "ri", "r" } }; | 64 | + { |
80 | - static const TCGTargetOpDef a2_rA | 65 | + QEMU_IOTHREAD_LOCK_GUARD(); |
81 | - = { .args_ct_str = { "r", "r", "0", "1", "rA", "r" } }; | 66 | + r = memory_region_dispatch_write(mr, mr_offset, val, op, full->attrs); |
82 | - | 67 | } |
83 | switch (op) { | 68 | - r = memory_region_dispatch_write(mr, mr_offset, val, op, full->attrs); |
84 | case INDEX_op_goto_ptr: | ||
85 | - return &r; | ||
86 | + return C_O0_I1(r); | ||
87 | |||
88 | case INDEX_op_ld8u_i32: | ||
89 | case INDEX_op_ld8u_i64: | ||
90 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
91 | case INDEX_op_ld32u_i64: | ||
92 | case INDEX_op_ld32s_i64: | ||
93 | case INDEX_op_ld_i64: | ||
94 | + return C_O1_I1(r, r); | ||
95 | + | 69 | + |
96 | case INDEX_op_st8_i32: | 70 | if (r != MEMTX_OK) { |
97 | case INDEX_op_st8_i64: | 71 | hwaddr physaddr = mr_offset + |
98 | case INDEX_op_st16_i32: | 72 | section->offset_within_address_space - |
99 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | 73 | @@ -XXX,XX +XXX,XX @@ static void io_writex(CPUArchState *env, CPUTLBEntryFull *full, |
100 | case INDEX_op_st_i32: | 74 | MMU_DATA_STORE, mmu_idx, full->attrs, r, |
101 | case INDEX_op_st32_i64: | 75 | retaddr); |
102 | case INDEX_op_st_i64: | ||
103 | - return &r_r; | ||
104 | + return C_O0_I2(r, r); | ||
105 | |||
106 | case INDEX_op_add_i32: | ||
107 | case INDEX_op_add_i64: | ||
108 | - return &r_r_ri; | ||
109 | + case INDEX_op_shl_i64: | ||
110 | + case INDEX_op_shr_i64: | ||
111 | + case INDEX_op_sar_i64: | ||
112 | + case INDEX_op_rotl_i32: | ||
113 | + case INDEX_op_rotl_i64: | ||
114 | + case INDEX_op_rotr_i32: | ||
115 | + case INDEX_op_rotr_i64: | ||
116 | + case INDEX_op_clz_i64: | ||
117 | + case INDEX_op_setcond_i32: | ||
118 | + case INDEX_op_setcond_i64: | ||
119 | + return C_O1_I2(r, r, ri); | ||
120 | + | ||
121 | case INDEX_op_sub_i32: | ||
122 | case INDEX_op_sub_i64: | ||
123 | case INDEX_op_and_i32: | ||
124 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
125 | case INDEX_op_or_i64: | ||
126 | case INDEX_op_xor_i32: | ||
127 | case INDEX_op_xor_i64: | ||
128 | - return (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_ri : &r_0_ri); | ||
129 | + return (s390_facilities & FACILITY_DISTINCT_OPS | ||
130 | + ? C_O1_I2(r, r, ri) | ||
131 | + : C_O1_I2(r, 0, ri)); | ||
132 | |||
133 | case INDEX_op_mul_i32: | ||
134 | /* If we have the general-instruction-extensions, then we have | ||
135 | MULTIPLY SINGLE IMMEDIATE with a signed 32-bit, otherwise we | ||
136 | have only MULTIPLY HALFWORD IMMEDIATE, with a signed 16-bit. */ | ||
137 | - return (s390_facilities & FACILITY_GEN_INST_EXT ? &r_0_ri : &r_0_rI); | ||
138 | + return (s390_facilities & FACILITY_GEN_INST_EXT | ||
139 | + ? C_O1_I2(r, 0, ri) | ||
140 | + : C_O1_I2(r, 0, rI)); | ||
141 | + | ||
142 | case INDEX_op_mul_i64: | ||
143 | - return (s390_facilities & FACILITY_GEN_INST_EXT ? &r_0_rJ : &r_0_rI); | ||
144 | + return (s390_facilities & FACILITY_GEN_INST_EXT | ||
145 | + ? C_O1_I2(r, 0, rJ) | ||
146 | + : C_O1_I2(r, 0, rI)); | ||
147 | |||
148 | case INDEX_op_shl_i32: | ||
149 | case INDEX_op_shr_i32: | ||
150 | case INDEX_op_sar_i32: | ||
151 | - return (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_ri : &r_0_ri); | ||
152 | - | ||
153 | - case INDEX_op_shl_i64: | ||
154 | - case INDEX_op_shr_i64: | ||
155 | - case INDEX_op_sar_i64: | ||
156 | - return &r_r_ri; | ||
157 | - | ||
158 | - case INDEX_op_rotl_i32: | ||
159 | - case INDEX_op_rotl_i64: | ||
160 | - case INDEX_op_rotr_i32: | ||
161 | - case INDEX_op_rotr_i64: | ||
162 | - return &r_r_ri; | ||
163 | + return (s390_facilities & FACILITY_DISTINCT_OPS | ||
164 | + ? C_O1_I2(r, r, ri) | ||
165 | + : C_O1_I2(r, 0, ri)); | ||
166 | |||
167 | case INDEX_op_brcond_i32: | ||
168 | case INDEX_op_brcond_i64: | ||
169 | - return &r_ri; | ||
170 | + return C_O0_I2(r, ri); | ||
171 | |||
172 | case INDEX_op_bswap16_i32: | ||
173 | case INDEX_op_bswap16_i64: | ||
174 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
175 | case INDEX_op_extu_i32_i64: | ||
176 | case INDEX_op_extract_i32: | ||
177 | case INDEX_op_extract_i64: | ||
178 | - return &r_r; | ||
179 | - | ||
180 | - case INDEX_op_clz_i64: | ||
181 | - case INDEX_op_setcond_i32: | ||
182 | - case INDEX_op_setcond_i64: | ||
183 | - return &r_r_ri; | ||
184 | + return C_O1_I1(r, r); | ||
185 | |||
186 | case INDEX_op_qemu_ld_i32: | ||
187 | case INDEX_op_qemu_ld_i64: | ||
188 | - return &r_L; | ||
189 | + return C_O1_I1(r, L); | ||
190 | case INDEX_op_qemu_st_i64: | ||
191 | case INDEX_op_qemu_st_i32: | ||
192 | - return &L_L; | ||
193 | + return C_O0_I2(L, L); | ||
194 | |||
195 | case INDEX_op_deposit_i32: | ||
196 | case INDEX_op_deposit_i64: | ||
197 | - { | ||
198 | - static const TCGTargetOpDef dep | ||
199 | - = { .args_ct_str = { "r", "rZ", "r" } }; | ||
200 | - return &dep; | ||
201 | - } | ||
202 | + return C_O1_I2(r, rZ, r); | ||
203 | + | ||
204 | case INDEX_op_movcond_i32: | ||
205 | case INDEX_op_movcond_i64: | ||
206 | - { | ||
207 | - static const TCGTargetOpDef movc | ||
208 | - = { .args_ct_str = { "r", "r", "ri", "r", "0" } }; | ||
209 | - static const TCGTargetOpDef movc_l | ||
210 | - = { .args_ct_str = { "r", "r", "ri", "rI", "0" } }; | ||
211 | - return (s390_facilities & FACILITY_LOAD_ON_COND2 ? &movc_l : &movc); | ||
212 | - } | ||
213 | + return (s390_facilities & FACILITY_LOAD_ON_COND2 | ||
214 | + ? C_O1_I4(r, r, ri, rI, 0) | ||
215 | + : C_O1_I4(r, r, ri, r, 0)); | ||
216 | + | ||
217 | case INDEX_op_div2_i32: | ||
218 | case INDEX_op_div2_i64: | ||
219 | case INDEX_op_divu2_i32: | ||
220 | case INDEX_op_divu2_i64: | ||
221 | - { | ||
222 | - static const TCGTargetOpDef div2 | ||
223 | - = { .args_ct_str = { "b", "a", "0", "1", "r" } }; | ||
224 | - return &div2; | ||
225 | - } | ||
226 | + return C_O2_I3(b, a, 0, 1, r); | ||
227 | + | ||
228 | case INDEX_op_mulu2_i64: | ||
229 | - { | ||
230 | - static const TCGTargetOpDef mul2 | ||
231 | - = { .args_ct_str = { "b", "a", "0", "r" } }; | ||
232 | - return &mul2; | ||
233 | - } | ||
234 | + return C_O2_I2(b, a, 0, r); | ||
235 | |||
236 | case INDEX_op_add2_i32: | ||
237 | case INDEX_op_sub2_i32: | ||
238 | - return (s390_facilities & FACILITY_EXT_IMM ? &a2_ri : &a2_r); | ||
239 | + return (s390_facilities & FACILITY_EXT_IMM | ||
240 | + ? C_O2_I4(r, r, 0, 1, ri, r) | ||
241 | + : C_O2_I4(r, r, 0, 1, r, r)); | ||
242 | + | ||
243 | case INDEX_op_add2_i64: | ||
244 | case INDEX_op_sub2_i64: | ||
245 | - return (s390_facilities & FACILITY_EXT_IMM ? &a2_rA : &a2_r); | ||
246 | + return (s390_facilities & FACILITY_EXT_IMM | ||
247 | + ? C_O2_I4(r, r, 0, 1, rA, r) | ||
248 | + : C_O2_I4(r, r, 0, 1, r, r)); | ||
249 | |||
250 | default: | ||
251 | - break; | ||
252 | + g_assert_not_reached(); | ||
253 | } | 76 | } |
254 | - return NULL; | 77 | - if (locked) { |
78 | - qemu_mutex_unlock_iothread(); | ||
79 | - } | ||
255 | } | 80 | } |
256 | 81 | ||
257 | static void query_s390_facilities(void) | 82 | static inline target_ulong tlb_read_ofs(CPUTLBEntry *entry, size_t ofs) |
258 | -- | 83 | -- |
259 | 2.25.1 | 84 | 2.34.1 |
260 | 85 | ||
261 | 86 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Replace goto allocate_in_reg with a boolean. | ||
2 | Remove o_preferred_regs which isn't used, except to copy. | ||
1 | 3 | ||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | --- | ||
7 | tcg/tcg.c | 45 +++++++++++++++++++++------------------------ | ||
8 | 1 file changed, 21 insertions(+), 24 deletions(-) | ||
9 | |||
10 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/tcg/tcg.c | ||
13 | +++ b/tcg/tcg.c | ||
14 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
15 | |||
16 | /* satisfy input constraints */ | ||
17 | for (k = 0; k < nb_iargs; k++) { | ||
18 | - TCGRegSet i_preferred_regs, o_preferred_regs; | ||
19 | + TCGRegSet i_preferred_regs; | ||
20 | + bool allocate_new_reg; | ||
21 | |||
22 | i = def->args_ct[nb_oargs + k].sort_index; | ||
23 | arg = op->args[i]; | ||
24 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
25 | continue; | ||
26 | } | ||
27 | |||
28 | - i_preferred_regs = o_preferred_regs = 0; | ||
29 | + reg = ts->reg; | ||
30 | + i_preferred_regs = 0; | ||
31 | + allocate_new_reg = false; | ||
32 | + | ||
33 | if (arg_ct->ialias) { | ||
34 | - o_preferred_regs = op->output_pref[arg_ct->alias_index]; | ||
35 | + i_preferred_regs = op->output_pref[arg_ct->alias_index]; | ||
36 | |||
37 | /* | ||
38 | * If the input is readonly, then it cannot also be an | ||
39 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
40 | * register and move it. | ||
41 | */ | ||
42 | if (temp_readonly(ts) || !IS_DEAD_ARG(i)) { | ||
43 | - goto allocate_in_reg; | ||
44 | + allocate_new_reg = true; | ||
45 | + } else if (ts->val_type == TEMP_VAL_REG) { | ||
46 | + /* | ||
47 | + * Check if the current register has already been | ||
48 | + * allocated for another input. | ||
49 | + */ | ||
50 | + allocate_new_reg = tcg_regset_test_reg(i_allocated_regs, reg); | ||
51 | } | ||
52 | - | ||
53 | - /* | ||
54 | - * Check if the current register has already been allocated | ||
55 | - * for another input aliased to an output. | ||
56 | - */ | ||
57 | - if (ts->val_type == TEMP_VAL_REG) { | ||
58 | - reg = ts->reg; | ||
59 | - for (int k2 = 0; k2 < k; k2++) { | ||
60 | - int i2 = def->args_ct[nb_oargs + k2].sort_index; | ||
61 | - if (def->args_ct[i2].ialias && reg == new_args[i2]) { | ||
62 | - goto allocate_in_reg; | ||
63 | - } | ||
64 | - } | ||
65 | - } | ||
66 | - i_preferred_regs = o_preferred_regs; | ||
67 | } | ||
68 | |||
69 | - temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs); | ||
70 | - reg = ts->reg; | ||
71 | + if (!allocate_new_reg) { | ||
72 | + temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs); | ||
73 | + reg = ts->reg; | ||
74 | + allocate_new_reg = !tcg_regset_test_reg(arg_ct->regs, reg); | ||
75 | + } | ||
76 | |||
77 | - if (!tcg_regset_test_reg(arg_ct->regs, reg)) { | ||
78 | - allocate_in_reg: | ||
79 | + if (allocate_new_reg) { | ||
80 | /* | ||
81 | * Allocate a new register matching the constraint | ||
82 | * and move the temporary register into it. | ||
83 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
84 | temp_load(s, ts, tcg_target_available_regs[ts->type], | ||
85 | i_allocated_regs, 0); | ||
86 | reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs, | ||
87 | - o_preferred_regs, ts->indirect_base); | ||
88 | + i_preferred_regs, ts->indirect_base); | ||
89 | if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { | ||
90 | /* | ||
91 | * Cross register class move not supported. Sync the | ||
92 | -- | ||
93 | 2.34.1 | ||
94 | |||
95 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | The hppa host code has been removed since 2013; this |
---|---|---|---|
2 | should have been deleted at the same time. | ||
3 | |||
4 | Fixes: 802b5081233a ("tcg-hppa: Remove tcg backend") | ||
5 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 7 | --- |
4 | tcg/aarch64/tcg-target-con-set.h | 36 +++++++++++++ | 8 | tcg/aarch64/tcg-target.h | 1 - |
5 | tcg/aarch64/tcg-target.h | 1 + | 9 | tcg/arm/tcg-target.h | 1 - |
6 | tcg/aarch64/tcg-target.c.inc | 86 +++++++++++--------------------- | 10 | tcg/tcg.c | 32 ++------------------------------ |
7 | 3 files changed, 65 insertions(+), 58 deletions(-) | 11 | 3 files changed, 2 insertions(+), 32 deletions(-) |
8 | create mode 100644 tcg/aarch64/tcg-target-con-set.h | ||
9 | 12 | ||
10 | diff --git a/tcg/aarch64/tcg-target-con-set.h b/tcg/aarch64/tcg-target-con-set.h | ||
11 | new file mode 100644 | ||
12 | index XXXXXXX..XXXXXXX | ||
13 | --- /dev/null | ||
14 | +++ b/tcg/aarch64/tcg-target-con-set.h | ||
15 | @@ -XXX,XX +XXX,XX @@ | ||
16 | +/* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
17 | +/* | ||
18 | + * Define AArch64 target-specific constraint sets. | ||
19 | + * Copyright (c) 2021 Linaro | ||
20 | + */ | ||
21 | + | ||
22 | +/* | ||
23 | + * C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs. | ||
24 | + * Each operand should be a sequence of constraint letters as defined by | ||
25 | + * tcg-target-con-str.h; the constraint combination is inclusive or. | ||
26 | + */ | ||
27 | +C_O0_I1(r) | ||
28 | +C_O0_I2(lZ, l) | ||
29 | +C_O0_I2(r, rA) | ||
30 | +C_O0_I2(rZ, r) | ||
31 | +C_O0_I2(w, r) | ||
32 | +C_O1_I1(r, l) | ||
33 | +C_O1_I1(r, r) | ||
34 | +C_O1_I1(w, r) | ||
35 | +C_O1_I1(w, w) | ||
36 | +C_O1_I1(w, wr) | ||
37 | +C_O1_I2(r, 0, rZ) | ||
38 | +C_O1_I2(r, r, r) | ||
39 | +C_O1_I2(r, r, rA) | ||
40 | +C_O1_I2(r, r, rAL) | ||
41 | +C_O1_I2(r, r, ri) | ||
42 | +C_O1_I2(r, r, rL) | ||
43 | +C_O1_I2(r, rZ, rZ) | ||
44 | +C_O1_I2(w, 0, w) | ||
45 | +C_O1_I2(w, w, w) | ||
46 | +C_O1_I2(w, w, wN) | ||
47 | +C_O1_I2(w, w, wO) | ||
48 | +C_O1_I2(w, w, wZ) | ||
49 | +C_O1_I3(w, w, w, w) | ||
50 | +C_O1_I4(r, r, rA, rZ, rZ) | ||
51 | +C_O2_I4(r, r, rZ, rZ, rA, rMZ) | ||
52 | diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h | 13 | diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h |
53 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
54 | --- a/tcg/aarch64/tcg-target.h | 15 | --- a/tcg/aarch64/tcg-target.h |
55 | +++ b/tcg/aarch64/tcg-target.h | 16 | +++ b/tcg/aarch64/tcg-target.h |
56 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 17 | @@ -XXX,XX +XXX,XX @@ |
57 | #define TCG_TARGET_NEED_LDST_LABELS | 18 | #define TCG_TARGET_INSN_UNIT_SIZE 4 |
58 | #endif | 19 | #define TCG_TARGET_TLB_DISPLACEMENT_BITS 24 |
59 | #define TCG_TARGET_NEED_POOL_LABELS | 20 | #define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB) |
60 | +#define TCG_TARGET_CON_SET_H | 21 | -#undef TCG_TARGET_STACK_GROWSUP |
61 | 22 | ||
62 | #endif /* AARCH64_TCG_TARGET_H */ | 23 | typedef enum { |
63 | diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc | 24 | TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, |
25 | diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h | ||
64 | index XXXXXXX..XXXXXXX 100644 | 26 | index XXXXXXX..XXXXXXX 100644 |
65 | --- a/tcg/aarch64/tcg-target.c.inc | 27 | --- a/tcg/arm/tcg-target.h |
66 | +++ b/tcg/aarch64/tcg-target.c.inc | 28 | +++ b/tcg/arm/tcg-target.h |
67 | @@ -XXX,XX +XXX,XX @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece, | 29 | @@ -XXX,XX +XXX,XX @@ extern int arm_arch; |
68 | va_end(va); | 30 | |
31 | #define use_armv7_instructions (__ARM_ARCH >= 7 || arm_arch >= 7) | ||
32 | |||
33 | -#undef TCG_TARGET_STACK_GROWSUP | ||
34 | #define TCG_TARGET_INSN_UNIT_SIZE 4 | ||
35 | #define TCG_TARGET_TLB_DISPLACEMENT_BITS 16 | ||
36 | #define MAX_CODE_GEN_BUFFER_SIZE UINT32_MAX | ||
37 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/tcg/tcg.c | ||
40 | +++ b/tcg/tcg.c | ||
41 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
42 | } | ||
43 | |||
44 | if (TCG_TARGET_REG_BITS < 64 && is_64bit) { | ||
45 | - /* | ||
46 | - * If stack grows up, then we will be placing successive | ||
47 | - * arguments at lower addresses, which means we need to | ||
48 | - * reverse the order compared to how we would normally | ||
49 | - * treat either big or little-endian. For those arguments | ||
50 | - * that will wind up in registers, this still works for | ||
51 | - * HPPA (the only current STACK_GROWSUP target) since the | ||
52 | - * argument registers are *also* allocated in decreasing | ||
53 | - * order. If another such target is added, this logic may | ||
54 | - * have to get more complicated to differentiate between | ||
55 | - * stack arguments and register arguments. | ||
56 | - */ | ||
57 | -#if HOST_BIG_ENDIAN != defined(TCG_TARGET_STACK_GROWSUP) | ||
58 | - op->args[pi++] = temp_arg(args[i] + 1); | ||
59 | - op->args[pi++] = temp_arg(args[i]); | ||
60 | -#else | ||
61 | - op->args[pi++] = temp_arg(args[i]); | ||
62 | - op->args[pi++] = temp_arg(args[i] + 1); | ||
63 | -#endif | ||
64 | + op->args[pi++] = temp_arg(args[i] + HOST_BIG_ENDIAN); | ||
65 | + op->args[pi++] = temp_arg(args[i] + !HOST_BIG_ENDIAN); | ||
66 | real_args += 2; | ||
67 | continue; | ||
68 | } | ||
69 | @@ -XXX,XX +XXX,XX @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) | ||
70 | return true; | ||
69 | } | 71 | } |
70 | 72 | ||
71 | -static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | 73 | -#ifdef TCG_TARGET_STACK_GROWSUP |
72 | +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) | 74 | -#define STACK_DIR(x) (-(x)) |
75 | -#else | ||
76 | -#define STACK_DIR(x) (x) | ||
77 | -#endif | ||
78 | - | ||
79 | static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) | ||
73 | { | 80 | { |
74 | - static const TCGTargetOpDef r = { .args_ct_str = { "r" } }; | 81 | const int nb_oargs = TCGOP_CALLO(op); |
75 | - static const TCGTargetOpDef r_r = { .args_ct_str = { "r", "r" } }; | 82 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) |
76 | - static const TCGTargetOpDef w_w = { .args_ct_str = { "w", "w" } }; | 83 | stack_offset = TCG_TARGET_CALL_STACK_OFFSET; |
77 | - static const TCGTargetOpDef w_r = { .args_ct_str = { "w", "r" } }; | 84 | for (i = nb_regs; i < nb_iargs; i++) { |
78 | - static const TCGTargetOpDef w_wr = { .args_ct_str = { "w", "wr" } }; | 85 | arg = op->args[nb_oargs + i]; |
79 | - static const TCGTargetOpDef r_l = { .args_ct_str = { "r", "l" } }; | 86 | -#ifdef TCG_TARGET_STACK_GROWSUP |
80 | - static const TCGTargetOpDef r_rA = { .args_ct_str = { "r", "rA" } }; | 87 | - stack_offset -= sizeof(tcg_target_long); |
81 | - static const TCGTargetOpDef rZ_r = { .args_ct_str = { "rZ", "r" } }; | 88 | -#endif |
82 | - static const TCGTargetOpDef lZ_l = { .args_ct_str = { "lZ", "l" } }; | 89 | if (arg != TCG_CALL_DUMMY_ARG) { |
83 | - static const TCGTargetOpDef r_r_r = { .args_ct_str = { "r", "r", "r" } }; | 90 | ts = arg_temp(arg); |
84 | - static const TCGTargetOpDef w_w_w = { .args_ct_str = { "w", "w", "w" } }; | 91 | temp_load(s, ts, tcg_target_available_regs[ts->type], |
85 | - static const TCGTargetOpDef w_0_w = { .args_ct_str = { "w", "0", "w" } }; | 92 | s->reserved_regs, 0); |
86 | - static const TCGTargetOpDef w_w_wO = { .args_ct_str = { "w", "w", "wO" } }; | 93 | tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); |
87 | - static const TCGTargetOpDef w_w_wN = { .args_ct_str = { "w", "w", "wN" } }; | 94 | } |
88 | - static const TCGTargetOpDef w_w_wZ = { .args_ct_str = { "w", "w", "wZ" } }; | 95 | -#ifndef TCG_TARGET_STACK_GROWSUP |
89 | - static const TCGTargetOpDef r_r_ri = { .args_ct_str = { "r", "r", "ri" } }; | 96 | stack_offset += sizeof(tcg_target_long); |
90 | - static const TCGTargetOpDef r_r_rA = { .args_ct_str = { "r", "r", "rA" } }; | 97 | -#endif |
91 | - static const TCGTargetOpDef r_r_rL = { .args_ct_str = { "r", "r", "rL" } }; | ||
92 | - static const TCGTargetOpDef r_r_rAL | ||
93 | - = { .args_ct_str = { "r", "r", "rAL" } }; | ||
94 | - static const TCGTargetOpDef dep | ||
95 | - = { .args_ct_str = { "r", "0", "rZ" } }; | ||
96 | - static const TCGTargetOpDef ext2 | ||
97 | - = { .args_ct_str = { "r", "rZ", "rZ" } }; | ||
98 | - static const TCGTargetOpDef movc | ||
99 | - = { .args_ct_str = { "r", "r", "rA", "rZ", "rZ" } }; | ||
100 | - static const TCGTargetOpDef add2 | ||
101 | - = { .args_ct_str = { "r", "r", "rZ", "rZ", "rA", "rMZ" } }; | ||
102 | - static const TCGTargetOpDef w_w_w_w | ||
103 | - = { .args_ct_str = { "w", "w", "w", "w" } }; | ||
104 | - | ||
105 | switch (op) { | ||
106 | case INDEX_op_goto_ptr: | ||
107 | - return &r; | ||
108 | + return C_O0_I1(r); | ||
109 | |||
110 | case INDEX_op_ld8u_i32: | ||
111 | case INDEX_op_ld8s_i32: | ||
112 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
113 | case INDEX_op_extract_i64: | ||
114 | case INDEX_op_sextract_i32: | ||
115 | case INDEX_op_sextract_i64: | ||
116 | - return &r_r; | ||
117 | + return C_O1_I1(r, r); | ||
118 | |||
119 | case INDEX_op_st8_i32: | ||
120 | case INDEX_op_st16_i32: | ||
121 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
122 | case INDEX_op_st16_i64: | ||
123 | case INDEX_op_st32_i64: | ||
124 | case INDEX_op_st_i64: | ||
125 | - return &rZ_r; | ||
126 | + return C_O0_I2(rZ, r); | ||
127 | |||
128 | case INDEX_op_add_i32: | ||
129 | case INDEX_op_add_i64: | ||
130 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
131 | case INDEX_op_sub_i64: | ||
132 | case INDEX_op_setcond_i32: | ||
133 | case INDEX_op_setcond_i64: | ||
134 | - return &r_r_rA; | ||
135 | + return C_O1_I2(r, r, rA); | ||
136 | |||
137 | case INDEX_op_mul_i32: | ||
138 | case INDEX_op_mul_i64: | ||
139 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
140 | case INDEX_op_remu_i64: | ||
141 | case INDEX_op_muluh_i64: | ||
142 | case INDEX_op_mulsh_i64: | ||
143 | - return &r_r_r; | ||
144 | + return C_O1_I2(r, r, r); | ||
145 | |||
146 | case INDEX_op_and_i32: | ||
147 | case INDEX_op_and_i64: | ||
148 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
149 | case INDEX_op_orc_i64: | ||
150 | case INDEX_op_eqv_i32: | ||
151 | case INDEX_op_eqv_i64: | ||
152 | - return &r_r_rL; | ||
153 | + return C_O1_I2(r, r, rL); | ||
154 | |||
155 | case INDEX_op_shl_i32: | ||
156 | case INDEX_op_shr_i32: | ||
157 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
158 | case INDEX_op_sar_i64: | ||
159 | case INDEX_op_rotl_i64: | ||
160 | case INDEX_op_rotr_i64: | ||
161 | - return &r_r_ri; | ||
162 | + return C_O1_I2(r, r, ri); | ||
163 | |||
164 | case INDEX_op_clz_i32: | ||
165 | case INDEX_op_ctz_i32: | ||
166 | case INDEX_op_clz_i64: | ||
167 | case INDEX_op_ctz_i64: | ||
168 | - return &r_r_rAL; | ||
169 | + return C_O1_I2(r, r, rAL); | ||
170 | |||
171 | case INDEX_op_brcond_i32: | ||
172 | case INDEX_op_brcond_i64: | ||
173 | - return &r_rA; | ||
174 | + return C_O0_I2(r, rA); | ||
175 | |||
176 | case INDEX_op_movcond_i32: | ||
177 | case INDEX_op_movcond_i64: | ||
178 | - return &movc; | ||
179 | + return C_O1_I4(r, r, rA, rZ, rZ); | ||
180 | |||
181 | case INDEX_op_qemu_ld_i32: | ||
182 | case INDEX_op_qemu_ld_i64: | ||
183 | - return &r_l; | ||
184 | + return C_O1_I1(r, l); | ||
185 | case INDEX_op_qemu_st_i32: | ||
186 | case INDEX_op_qemu_st_i64: | ||
187 | - return &lZ_l; | ||
188 | + return C_O0_I2(lZ, l); | ||
189 | |||
190 | case INDEX_op_deposit_i32: | ||
191 | case INDEX_op_deposit_i64: | ||
192 | - return &dep; | ||
193 | + return C_O1_I2(r, 0, rZ); | ||
194 | |||
195 | case INDEX_op_extract2_i32: | ||
196 | case INDEX_op_extract2_i64: | ||
197 | - return &ext2; | ||
198 | + return C_O1_I2(r, rZ, rZ); | ||
199 | |||
200 | case INDEX_op_add2_i32: | ||
201 | case INDEX_op_add2_i64: | ||
202 | case INDEX_op_sub2_i32: | ||
203 | case INDEX_op_sub2_i64: | ||
204 | - return &add2; | ||
205 | + return C_O2_I4(r, r, rZ, rZ, rA, rMZ); | ||
206 | |||
207 | case INDEX_op_add_vec: | ||
208 | case INDEX_op_sub_vec: | ||
209 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
210 | case INDEX_op_shrv_vec: | ||
211 | case INDEX_op_sarv_vec: | ||
212 | case INDEX_op_aa64_sshl_vec: | ||
213 | - return &w_w_w; | ||
214 | + return C_O1_I2(w, w, w); | ||
215 | case INDEX_op_not_vec: | ||
216 | case INDEX_op_neg_vec: | ||
217 | case INDEX_op_abs_vec: | ||
218 | case INDEX_op_shli_vec: | ||
219 | case INDEX_op_shri_vec: | ||
220 | case INDEX_op_sari_vec: | ||
221 | - return &w_w; | ||
222 | + return C_O1_I1(w, w); | ||
223 | case INDEX_op_ld_vec: | ||
224 | - case INDEX_op_st_vec: | ||
225 | case INDEX_op_dupm_vec: | ||
226 | - return &w_r; | ||
227 | + return C_O1_I1(w, r); | ||
228 | + case INDEX_op_st_vec: | ||
229 | + return C_O0_I2(w, r); | ||
230 | case INDEX_op_dup_vec: | ||
231 | - return &w_wr; | ||
232 | + return C_O1_I1(w, wr); | ||
233 | case INDEX_op_or_vec: | ||
234 | case INDEX_op_andc_vec: | ||
235 | - return &w_w_wO; | ||
236 | + return C_O1_I2(w, w, wO); | ||
237 | case INDEX_op_and_vec: | ||
238 | case INDEX_op_orc_vec: | ||
239 | - return &w_w_wN; | ||
240 | + return C_O1_I2(w, w, wN); | ||
241 | case INDEX_op_cmp_vec: | ||
242 | - return &w_w_wZ; | ||
243 | + return C_O1_I2(w, w, wZ); | ||
244 | case INDEX_op_bitsel_vec: | ||
245 | - return &w_w_w_w; | ||
246 | + return C_O1_I3(w, w, w, w); | ||
247 | case INDEX_op_aa64_sli_vec: | ||
248 | - return &w_0_w; | ||
249 | + return C_O1_I2(w, 0, w); | ||
250 | |||
251 | default: | ||
252 | - return NULL; | ||
253 | + g_assert_not_reached(); | ||
254 | } | 98 | } |
255 | } | 99 | |
256 | 100 | /* assign input registers */ | |
257 | -- | 101 | -- |
258 | 2.25.1 | 102 | 2.34.1 |
259 | 103 | ||
260 | 104 | diff view generated by jsdifflib |
1 | The opcodes always exist, regardless of whether or not they | 1 | Unused since commit 7b7d8b2d9a ("tcg/tci: Use ffi for calls"). |
---|---|---|---|
2 | are enabled. Remove the unnecessary ifdefs. | ||
3 | 2 | ||
3 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
4 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
5 | --- | 5 | --- |
6 | tcg/tci/tcg-target.c.inc | 82 ---------------------------------------- | 6 | tcg/tci.c | 1 - |
7 | 1 file changed, 82 deletions(-) | 7 | tcg/tci/tcg-target.c.inc | 4 ---- |
8 | 2 files changed, 5 deletions(-) | ||
8 | 9 | ||
10 | diff --git a/tcg/tci.c b/tcg/tci.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/tcg/tci.c | ||
13 | +++ b/tcg/tci.c | ||
14 | @@ -XXX,XX +XXX,XX @@ | ||
15 | */ | ||
16 | |||
17 | #include "qemu/osdep.h" | ||
18 | -#include "tcg/tcg.h" /* MAX_OPC_PARAM_IARGS */ | ||
19 | #include "exec/cpu_ldst.h" | ||
20 | #include "tcg/tcg-op.h" | ||
21 | #include "tcg/tcg-ldst.h" | ||
9 | diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc | 22 | diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc |
10 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
11 | --- a/tcg/tci/tcg-target.c.inc | 24 | --- a/tcg/tci/tcg-target.c.inc |
12 | +++ b/tcg/tci/tcg-target.c.inc | 25 | +++ b/tcg/tci/tcg-target.c.inc |
13 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef tcg_target_op_defs[] = { | 26 | @@ -XXX,XX +XXX,XX @@ static const int tcg_target_reg_alloc_order[] = { |
14 | { INDEX_op_add_i32, { R, RI, RI } }, | 27 | TCG_REG_R0, |
15 | { INDEX_op_sub_i32, { R, RI, RI } }, | 28 | }; |
16 | { INDEX_op_mul_i32, { R, RI, RI } }, | 29 | |
17 | -#if TCG_TARGET_HAS_div_i32 | 30 | -#if MAX_OPC_PARAM_IARGS != 7 |
18 | { INDEX_op_div_i32, { R, R, R } }, | 31 | -# error Fix needed, number of supported input arguments changed! |
19 | { INDEX_op_divu_i32, { R, R, R } }, | ||
20 | { INDEX_op_rem_i32, { R, R, R } }, | ||
21 | { INDEX_op_remu_i32, { R, R, R } }, | ||
22 | -#elif TCG_TARGET_HAS_div2_i32 | ||
23 | - { INDEX_op_div2_i32, { R, R, "0", "1", R } }, | ||
24 | - { INDEX_op_divu2_i32, { R, R, "0", "1", R } }, | ||
25 | -#endif | 32 | -#endif |
26 | /* TODO: Does R, RI, RI result in faster code than R, R, RI? | 33 | - |
27 | If both operands are constants, we can optimize. */ | 34 | /* No call arguments via registers. All will be stored on the "stack". */ |
28 | { INDEX_op_and_i32, { R, RI, RI } }, | 35 | static const int tcg_target_call_iarg_regs[] = { }; |
29 | -#if TCG_TARGET_HAS_andc_i32 | 36 | |
30 | { INDEX_op_andc_i32, { R, RI, RI } }, | ||
31 | -#endif | ||
32 | -#if TCG_TARGET_HAS_eqv_i32 | ||
33 | { INDEX_op_eqv_i32, { R, RI, RI } }, | ||
34 | -#endif | ||
35 | -#if TCG_TARGET_HAS_nand_i32 | ||
36 | { INDEX_op_nand_i32, { R, RI, RI } }, | ||
37 | -#endif | ||
38 | -#if TCG_TARGET_HAS_nor_i32 | ||
39 | { INDEX_op_nor_i32, { R, RI, RI } }, | ||
40 | -#endif | ||
41 | { INDEX_op_or_i32, { R, RI, RI } }, | ||
42 | -#if TCG_TARGET_HAS_orc_i32 | ||
43 | { INDEX_op_orc_i32, { R, RI, RI } }, | ||
44 | -#endif | ||
45 | { INDEX_op_xor_i32, { R, RI, RI } }, | ||
46 | { INDEX_op_shl_i32, { R, RI, RI } }, | ||
47 | { INDEX_op_shr_i32, { R, RI, RI } }, | ||
48 | { INDEX_op_sar_i32, { R, RI, RI } }, | ||
49 | -#if TCG_TARGET_HAS_rot_i32 | ||
50 | { INDEX_op_rotl_i32, { R, RI, RI } }, | ||
51 | { INDEX_op_rotr_i32, { R, RI, RI } }, | ||
52 | -#endif | ||
53 | -#if TCG_TARGET_HAS_deposit_i32 | ||
54 | { INDEX_op_deposit_i32, { R, "0", R } }, | ||
55 | -#endif | ||
56 | |||
57 | { INDEX_op_brcond_i32, { R, RI } }, | ||
58 | |||
59 | { INDEX_op_setcond_i32, { R, R, RI } }, | ||
60 | -#if TCG_TARGET_REG_BITS == 64 | ||
61 | { INDEX_op_setcond_i64, { R, R, RI } }, | ||
62 | -#endif /* TCG_TARGET_REG_BITS == 64 */ | ||
63 | |||
64 | -#if TCG_TARGET_REG_BITS == 32 | ||
65 | /* TODO: Support R, R, R, R, RI, RI? Will it be faster? */ | ||
66 | { INDEX_op_add2_i32, { R, R, R, R, R, R } }, | ||
67 | { INDEX_op_sub2_i32, { R, R, R, R, R, R } }, | ||
68 | { INDEX_op_brcond2_i32, { R, R, RI, RI } }, | ||
69 | { INDEX_op_mulu2_i32, { R, R, R, R } }, | ||
70 | { INDEX_op_setcond2_i32, { R, R, R, RI, RI } }, | ||
71 | -#endif | ||
72 | |||
73 | -#if TCG_TARGET_HAS_not_i32 | ||
74 | { INDEX_op_not_i32, { R, R } }, | ||
75 | -#endif | ||
76 | -#if TCG_TARGET_HAS_neg_i32 | ||
77 | { INDEX_op_neg_i32, { R, R } }, | ||
78 | -#endif | ||
79 | |||
80 | -#if TCG_TARGET_REG_BITS == 64 | ||
81 | { INDEX_op_ld8u_i64, { R, R } }, | ||
82 | { INDEX_op_ld8s_i64, { R, R } }, | ||
83 | { INDEX_op_ld16u_i64, { R, R } }, | ||
84 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef tcg_target_op_defs[] = { | ||
85 | { INDEX_op_add_i64, { R, RI, RI } }, | ||
86 | { INDEX_op_sub_i64, { R, RI, RI } }, | ||
87 | { INDEX_op_mul_i64, { R, RI, RI } }, | ||
88 | -#if TCG_TARGET_HAS_div_i64 | ||
89 | { INDEX_op_div_i64, { R, R, R } }, | ||
90 | { INDEX_op_divu_i64, { R, R, R } }, | ||
91 | { INDEX_op_rem_i64, { R, R, R } }, | ||
92 | { INDEX_op_remu_i64, { R, R, R } }, | ||
93 | -#elif TCG_TARGET_HAS_div2_i64 | ||
94 | - { INDEX_op_div2_i64, { R, R, "0", "1", R } }, | ||
95 | - { INDEX_op_divu2_i64, { R, R, "0", "1", R } }, | ||
96 | -#endif | ||
97 | { INDEX_op_and_i64, { R, RI, RI } }, | ||
98 | -#if TCG_TARGET_HAS_andc_i64 | ||
99 | { INDEX_op_andc_i64, { R, RI, RI } }, | ||
100 | -#endif | ||
101 | -#if TCG_TARGET_HAS_eqv_i64 | ||
102 | { INDEX_op_eqv_i64, { R, RI, RI } }, | ||
103 | -#endif | ||
104 | -#if TCG_TARGET_HAS_nand_i64 | ||
105 | { INDEX_op_nand_i64, { R, RI, RI } }, | ||
106 | -#endif | ||
107 | -#if TCG_TARGET_HAS_nor_i64 | ||
108 | { INDEX_op_nor_i64, { R, RI, RI } }, | ||
109 | -#endif | ||
110 | { INDEX_op_or_i64, { R, RI, RI } }, | ||
111 | -#if TCG_TARGET_HAS_orc_i64 | ||
112 | { INDEX_op_orc_i64, { R, RI, RI } }, | ||
113 | -#endif | ||
114 | { INDEX_op_xor_i64, { R, RI, RI } }, | ||
115 | { INDEX_op_shl_i64, { R, RI, RI } }, | ||
116 | { INDEX_op_shr_i64, { R, RI, RI } }, | ||
117 | { INDEX_op_sar_i64, { R, RI, RI } }, | ||
118 | -#if TCG_TARGET_HAS_rot_i64 | ||
119 | { INDEX_op_rotl_i64, { R, RI, RI } }, | ||
120 | { INDEX_op_rotr_i64, { R, RI, RI } }, | ||
121 | -#endif | ||
122 | -#if TCG_TARGET_HAS_deposit_i64 | ||
123 | { INDEX_op_deposit_i64, { R, "0", R } }, | ||
124 | -#endif | ||
125 | { INDEX_op_brcond_i64, { R, RI } }, | ||
126 | |||
127 | -#if TCG_TARGET_HAS_ext8s_i64 | ||
128 | { INDEX_op_ext8s_i64, { R, R } }, | ||
129 | -#endif | ||
130 | -#if TCG_TARGET_HAS_ext16s_i64 | ||
131 | { INDEX_op_ext16s_i64, { R, R } }, | ||
132 | -#endif | ||
133 | -#if TCG_TARGET_HAS_ext32s_i64 | ||
134 | { INDEX_op_ext32s_i64, { R, R } }, | ||
135 | -#endif | ||
136 | -#if TCG_TARGET_HAS_ext8u_i64 | ||
137 | { INDEX_op_ext8u_i64, { R, R } }, | ||
138 | -#endif | ||
139 | -#if TCG_TARGET_HAS_ext16u_i64 | ||
140 | { INDEX_op_ext16u_i64, { R, R } }, | ||
141 | -#endif | ||
142 | -#if TCG_TARGET_HAS_ext32u_i64 | ||
143 | { INDEX_op_ext32u_i64, { R, R } }, | ||
144 | -#endif | ||
145 | { INDEX_op_ext_i32_i64, { R, R } }, | ||
146 | { INDEX_op_extu_i32_i64, { R, R } }, | ||
147 | -#if TCG_TARGET_HAS_bswap16_i64 | ||
148 | { INDEX_op_bswap16_i64, { R, R } }, | ||
149 | -#endif | ||
150 | -#if TCG_TARGET_HAS_bswap32_i64 | ||
151 | { INDEX_op_bswap32_i64, { R, R } }, | ||
152 | -#endif | ||
153 | -#if TCG_TARGET_HAS_bswap64_i64 | ||
154 | { INDEX_op_bswap64_i64, { R, R } }, | ||
155 | -#endif | ||
156 | -#if TCG_TARGET_HAS_not_i64 | ||
157 | { INDEX_op_not_i64, { R, R } }, | ||
158 | -#endif | ||
159 | -#if TCG_TARGET_HAS_neg_i64 | ||
160 | { INDEX_op_neg_i64, { R, R } }, | ||
161 | -#endif | ||
162 | -#endif /* TCG_TARGET_REG_BITS == 64 */ | ||
163 | |||
164 | { INDEX_op_qemu_ld_i32, { R, L } }, | ||
165 | { INDEX_op_qemu_ld_i64, { R64, L } }, | ||
166 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef tcg_target_op_defs[] = { | ||
167 | { INDEX_op_qemu_st_i32, { R, S } }, | ||
168 | { INDEX_op_qemu_st_i64, { R64, S } }, | ||
169 | |||
170 | -#if TCG_TARGET_HAS_ext8s_i32 | ||
171 | { INDEX_op_ext8s_i32, { R, R } }, | ||
172 | -#endif | ||
173 | -#if TCG_TARGET_HAS_ext16s_i32 | ||
174 | { INDEX_op_ext16s_i32, { R, R } }, | ||
175 | -#endif | ||
176 | -#if TCG_TARGET_HAS_ext8u_i32 | ||
177 | { INDEX_op_ext8u_i32, { R, R } }, | ||
178 | -#endif | ||
179 | -#if TCG_TARGET_HAS_ext16u_i32 | ||
180 | { INDEX_op_ext16u_i32, { R, R } }, | ||
181 | -#endif | ||
182 | |||
183 | -#if TCG_TARGET_HAS_bswap16_i32 | ||
184 | { INDEX_op_bswap16_i32, { R, R } }, | ||
185 | -#endif | ||
186 | -#if TCG_TARGET_HAS_bswap32_i32 | ||
187 | { INDEX_op_bswap32_i32, { R, R } }, | ||
188 | -#endif | ||
189 | |||
190 | { INDEX_op_mb, { } }, | ||
191 | { -1 }, | ||
192 | -- | 37 | -- |
193 | 2.25.1 | 38 | 2.34.1 |
194 | 39 | ||
195 | 40 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The assignment to mem_coherent should be done with any | ||
2 | modification, not simply with a newly allocated register. | ||
1 | 3 | ||
4 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
5 | --- | ||
6 | tcg/tcg.c | 4 ++-- | ||
7 | 1 file changed, 2 insertions(+), 2 deletions(-) | ||
8 | |||
9 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
10 | index XXXXXXX..XXXXXXX 100644 | ||
11 | --- a/tcg/tcg.c | ||
12 | +++ b/tcg/tcg.c | ||
13 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) | ||
14 | ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, | ||
15 | op->output_pref[0], ots->indirect_base); | ||
16 | ots->val_type = TEMP_VAL_REG; | ||
17 | - ots->mem_coherent = 0; | ||
18 | s->reg_to_temp[ots->reg] = ots; | ||
19 | } | ||
20 | |||
21 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) | ||
22 | tcg_debug_assert(ok); | ||
23 | |||
24 | done: | ||
25 | + ots->mem_coherent = 0; | ||
26 | if (IS_DEAD_ARG(1)) { | ||
27 | temp_dead(s, its); | ||
28 | } | ||
29 | @@ -XXX,XX +XXX,XX @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) | ||
30 | ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, | ||
31 | op->output_pref[0], ots->indirect_base); | ||
32 | ots->val_type = TEMP_VAL_REG; | ||
33 | - ots->mem_coherent = 0; | ||
34 | s->reg_to_temp[ots->reg] = ots; | ||
35 | } | ||
36 | |||
37 | @@ -XXX,XX +XXX,XX @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) | ||
38 | return false; | ||
39 | |||
40 | done: | ||
41 | + ots->mem_coherent = 0; | ||
42 | if (IS_DEAD_ARG(1)) { | ||
43 | temp_dead(s, itsl); | ||
44 | } | ||
45 | -- | ||
46 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | Create two new functions, set_temp_val_{reg,nonreg}. | |
2 | Assert that the reg_to_temp mapping is correct before | ||
3 | any changes are made. | ||
4 | |||
5 | Reviewed-by: Alex Bennée <alex.bennee@linaro.org> | ||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | --- | ||
8 | tcg/tcg.c | 159 +++++++++++++++++++++++++++++------------------------- | ||
9 | 1 file changed, 85 insertions(+), 74 deletions(-) | ||
10 | |||
11 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/tcg/tcg.c | ||
14 | +++ b/tcg/tcg.c | ||
15 | @@ -XXX,XX +XXX,XX @@ static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) | ||
16 | ts->mem_allocated = 1; | ||
17 | } | ||
18 | |||
19 | +/* Assign @reg to @ts, and update reg_to_temp[]. */ | ||
20 | +static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg) | ||
21 | +{ | ||
22 | + if (ts->val_type == TEMP_VAL_REG) { | ||
23 | + TCGReg old = ts->reg; | ||
24 | + tcg_debug_assert(s->reg_to_temp[old] == ts); | ||
25 | + if (old == reg) { | ||
26 | + return; | ||
27 | + } | ||
28 | + s->reg_to_temp[old] = NULL; | ||
29 | + } | ||
30 | + tcg_debug_assert(s->reg_to_temp[reg] == NULL); | ||
31 | + s->reg_to_temp[reg] = ts; | ||
32 | + ts->val_type = TEMP_VAL_REG; | ||
33 | + ts->reg = reg; | ||
34 | +} | ||
35 | + | ||
36 | +/* Assign a non-register value type to @ts, and update reg_to_temp[]. */ | ||
37 | +static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type) | ||
38 | +{ | ||
39 | + tcg_debug_assert(type != TEMP_VAL_REG); | ||
40 | + if (ts->val_type == TEMP_VAL_REG) { | ||
41 | + TCGReg reg = ts->reg; | ||
42 | + tcg_debug_assert(s->reg_to_temp[reg] == ts); | ||
43 | + s->reg_to_temp[reg] = NULL; | ||
44 | + } | ||
45 | + ts->val_type = type; | ||
46 | +} | ||
47 | + | ||
48 | static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); | ||
49 | |||
50 | /* Mark a temporary as free or dead. If 'free_or_dead' is negative, | ||
51 | @@ -XXX,XX +XXX,XX @@ static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) | ||
52 | default: | ||
53 | g_assert_not_reached(); | ||
54 | } | ||
55 | - if (ts->val_type == TEMP_VAL_REG) { | ||
56 | - s->reg_to_temp[ts->reg] = NULL; | ||
57 | - } | ||
58 | - ts->val_type = new_type; | ||
59 | + set_temp_val_nonreg(s, ts, new_type); | ||
60 | } | ||
61 | |||
62 | /* Mark a temporary as dead. */ | ||
63 | @@ -XXX,XX +XXX,XX @@ static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, | ||
64 | default: | ||
65 | tcg_abort(); | ||
66 | } | ||
67 | - ts->reg = reg; | ||
68 | - ts->val_type = TEMP_VAL_REG; | ||
69 | - s->reg_to_temp[reg] = ts; | ||
70 | + set_temp_val_reg(s, ts, reg); | ||
71 | } | ||
72 | |||
73 | /* Save a temporary to memory. 'allocated_regs' is used in case a | ||
74 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, | ||
75 | tcg_debug_assert(!temp_readonly(ots)); | ||
76 | |||
77 | /* The movi is not explicitly generated here. */ | ||
78 | - if (ots->val_type == TEMP_VAL_REG) { | ||
79 | - s->reg_to_temp[ots->reg] = NULL; | ||
80 | - } | ||
81 | - ots->val_type = TEMP_VAL_CONST; | ||
82 | + set_temp_val_nonreg(s, ots, TEMP_VAL_CONST); | ||
83 | ots->val = val; | ||
84 | ots->mem_coherent = 0; | ||
85 | if (NEED_SYNC_ARG(0)) { | ||
86 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) | ||
87 | TCGRegSet allocated_regs, preferred_regs; | ||
88 | TCGTemp *ts, *ots; | ||
89 | TCGType otype, itype; | ||
90 | + TCGReg oreg, ireg; | ||
91 | |||
92 | allocated_regs = s->reserved_regs; | ||
93 | preferred_regs = op->output_pref[0]; | ||
94 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) | ||
95 | temp_load(s, ts, tcg_target_available_regs[itype], | ||
96 | allocated_regs, preferred_regs); | ||
97 | } | ||
98 | - | ||
99 | tcg_debug_assert(ts->val_type == TEMP_VAL_REG); | ||
100 | + ireg = ts->reg; | ||
101 | + | ||
102 | if (IS_DEAD_ARG(0)) { | ||
103 | /* mov to a non-saved dead register makes no sense (even with | ||
104 | liveness analysis disabled). */ | ||
105 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) | ||
106 | if (!ots->mem_allocated) { | ||
107 | temp_allocate_frame(s, ots); | ||
108 | } | ||
109 | - tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); | ||
110 | + tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset); | ||
111 | if (IS_DEAD_ARG(1)) { | ||
112 | temp_dead(s, ts); | ||
113 | } | ||
114 | temp_dead(s, ots); | ||
115 | + return; | ||
116 | + } | ||
117 | + | ||
118 | + if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { | ||
119 | + /* | ||
120 | + * The mov can be suppressed. Kill input first, so that it | ||
121 | + * is unlinked from reg_to_temp, then set the output to the | ||
122 | + * reg that we saved from the input. | ||
123 | + */ | ||
124 | + temp_dead(s, ts); | ||
125 | + oreg = ireg; | ||
126 | } else { | ||
127 | - if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) { | ||
128 | - /* the mov can be suppressed */ | ||
129 | - if (ots->val_type == TEMP_VAL_REG) { | ||
130 | - s->reg_to_temp[ots->reg] = NULL; | ||
131 | - } | ||
132 | - ots->reg = ts->reg; | ||
133 | - temp_dead(s, ts); | ||
134 | + if (ots->val_type == TEMP_VAL_REG) { | ||
135 | + oreg = ots->reg; | ||
136 | } else { | ||
137 | - if (ots->val_type != TEMP_VAL_REG) { | ||
138 | - /* When allocating a new register, make sure to not spill the | ||
139 | - input one. */ | ||
140 | - tcg_regset_set_reg(allocated_regs, ts->reg); | ||
141 | - ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], | ||
142 | - allocated_regs, preferred_regs, | ||
143 | - ots->indirect_base); | ||
144 | - } | ||
145 | - if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) { | ||
146 | - /* | ||
147 | - * Cross register class move not supported. | ||
148 | - * Store the source register into the destination slot | ||
149 | - * and leave the destination temp as TEMP_VAL_MEM. | ||
150 | - */ | ||
151 | - assert(!temp_readonly(ots)); | ||
152 | - if (!ts->mem_allocated) { | ||
153 | - temp_allocate_frame(s, ots); | ||
154 | - } | ||
155 | - tcg_out_st(s, ts->type, ts->reg, | ||
156 | - ots->mem_base->reg, ots->mem_offset); | ||
157 | - ots->mem_coherent = 1; | ||
158 | - temp_free_or_dead(s, ots, -1); | ||
159 | - return; | ||
160 | - } | ||
161 | + /* Make sure to not spill the input register during allocation. */ | ||
162 | + oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype], | ||
163 | + allocated_regs | ((TCGRegSet)1 << ireg), | ||
164 | + preferred_regs, ots->indirect_base); | ||
165 | } | ||
166 | - ots->val_type = TEMP_VAL_REG; | ||
167 | - ots->mem_coherent = 0; | ||
168 | - s->reg_to_temp[ots->reg] = ots; | ||
169 | - if (NEED_SYNC_ARG(0)) { | ||
170 | - temp_sync(s, ots, allocated_regs, 0, 0); | ||
171 | + if (!tcg_out_mov(s, otype, oreg, ireg)) { | ||
172 | + /* | ||
173 | + * Cross register class move not supported. | ||
174 | + * Store the source register into the destination slot | ||
175 | + * and leave the destination temp as TEMP_VAL_MEM. | ||
176 | + */ | ||
177 | + assert(!temp_readonly(ots)); | ||
178 | + if (!ts->mem_allocated) { | ||
179 | + temp_allocate_frame(s, ots); | ||
180 | + } | ||
181 | + tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset); | ||
182 | + set_temp_val_nonreg(s, ts, TEMP_VAL_MEM); | ||
183 | + ots->mem_coherent = 1; | ||
184 | + return; | ||
185 | } | ||
186 | } | ||
187 | + set_temp_val_reg(s, ots, oreg); | ||
188 | + ots->mem_coherent = 0; | ||
189 | + | ||
190 | + if (NEED_SYNC_ARG(0)) { | ||
191 | + temp_sync(s, ots, allocated_regs, 0, 0); | ||
192 | + } | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) | ||
197 | /* Allocate the output register now. */ | ||
198 | if (ots->val_type != TEMP_VAL_REG) { | ||
199 | TCGRegSet allocated_regs = s->reserved_regs; | ||
200 | + TCGReg oreg; | ||
201 | |||
202 | if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { | ||
203 | /* Make sure to not spill the input register. */ | ||
204 | tcg_regset_set_reg(allocated_regs, its->reg); | ||
205 | } | ||
206 | - ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, | ||
207 | - op->output_pref[0], ots->indirect_base); | ||
208 | - ots->val_type = TEMP_VAL_REG; | ||
209 | - s->reg_to_temp[ots->reg] = ots; | ||
210 | + oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, | ||
211 | + op->output_pref[0], ots->indirect_base); | ||
212 | + set_temp_val_reg(s, ots, oreg); | ||
213 | } | ||
214 | |||
215 | switch (its->val_type) { | ||
216 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) | ||
217 | #else | ||
218 | endian_fixup = 0; | ||
219 | #endif | ||
220 | + /* Attempt to dup directly from the input memory slot. */ | ||
221 | if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, | ||
222 | its->mem_offset + endian_fixup)) { | ||
223 | goto done; | ||
224 | } | ||
225 | + /* Load the input into the destination vector register. */ | ||
226 | tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); | ||
227 | break; | ||
228 | |||
229 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
230 | op->output_pref[k], ts->indirect_base); | ||
231 | } | ||
232 | tcg_regset_set_reg(o_allocated_regs, reg); | ||
233 | - if (ts->val_type == TEMP_VAL_REG) { | ||
234 | - s->reg_to_temp[ts->reg] = NULL; | ||
235 | - } | ||
236 | - ts->val_type = TEMP_VAL_REG; | ||
237 | - ts->reg = reg; | ||
238 | - /* | ||
239 | - * Temp value is modified, so the value kept in memory is | ||
240 | - * potentially not the same. | ||
241 | - */ | ||
242 | + set_temp_val_reg(s, ts, reg); | ||
243 | ts->mem_coherent = 0; | ||
244 | - s->reg_to_temp[reg] = ts; | ||
245 | new_args[i] = reg; | ||
246 | } | ||
247 | } | ||
248 | @@ -XXX,XX +XXX,XX @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) | ||
249 | TCGRegSet allocated_regs = s->reserved_regs; | ||
250 | TCGRegSet dup_out_regs = | ||
251 | tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; | ||
252 | + TCGReg oreg; | ||
253 | |||
254 | /* Make sure to not spill the input registers. */ | ||
255 | if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) { | ||
256 | @@ -XXX,XX +XXX,XX @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) | ||
257 | tcg_regset_set_reg(allocated_regs, itsh->reg); | ||
258 | } | ||
259 | |||
260 | - ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, | ||
261 | - op->output_pref[0], ots->indirect_base); | ||
262 | - ots->val_type = TEMP_VAL_REG; | ||
263 | - s->reg_to_temp[ots->reg] = ots; | ||
264 | + oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, | ||
265 | + op->output_pref[0], ots->indirect_base); | ||
266 | + set_temp_val_reg(s, ots, oreg); | ||
267 | } | ||
268 | |||
269 | /* Promote dup2 of immediates to dupi_vec. */ | ||
270 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) | ||
271 | tcg_debug_assert(!temp_readonly(ts)); | ||
272 | |||
273 | reg = tcg_target_call_oarg_regs[i]; | ||
274 | - tcg_debug_assert(s->reg_to_temp[reg] == NULL); | ||
275 | - if (ts->val_type == TEMP_VAL_REG) { | ||
276 | - s->reg_to_temp[ts->reg] = NULL; | ||
277 | - } | ||
278 | - ts->val_type = TEMP_VAL_REG; | ||
279 | - ts->reg = reg; | ||
280 | + set_temp_val_reg(s, ts, reg); | ||
281 | ts->mem_coherent = 0; | ||
282 | - s->reg_to_temp[reg] = ts; | ||
283 | if (NEED_SYNC_ARG(i)) { | ||
284 | temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i)); | ||
285 | } else if (IS_DEAD_ARG(i)) { | ||
286 | -- | ||
287 | 2.34.1 | ||
288 | |||
289 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | We now check the consistency of reg_to_temp[] with each update, |
---|---|---|---|
2 | so the utility of checking consistency at the end of each | ||
3 | opcode is minimal. In addition, the form of this check is | ||
4 | quite expensive, consuming 10% of a checking-enabled build. | ||
5 | |||
6 | Reviewed-by: Alex Bennée <alex.bennee@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 7 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 8 | --- |
4 | tcg/riscv/tcg-target-con-str.h | 21 ++++++++++++++ | 9 | tcg/tcg.c | 76 ------------------------------------------------------- |
5 | tcg/riscv/tcg-target.h | 1 + | 10 | 1 file changed, 76 deletions(-) |
6 | tcg/riscv/tcg-target.c.inc | 52 +++++++++------------------------- | ||
7 | 3 files changed, 35 insertions(+), 39 deletions(-) | ||
8 | create mode 100644 tcg/riscv/tcg-target-con-str.h | ||
9 | 11 | ||
10 | diff --git a/tcg/riscv/tcg-target-con-str.h b/tcg/riscv/tcg-target-con-str.h | 12 | diff --git a/tcg/tcg.c b/tcg/tcg.c |
11 | new file mode 100644 | ||
12 | index XXXXXXX..XXXXXXX | ||
13 | --- /dev/null | ||
14 | +++ b/tcg/riscv/tcg-target-con-str.h | ||
15 | @@ -XXX,XX +XXX,XX @@ | ||
16 | +/* SPDX-License-Identifier: MIT */ | ||
17 | +/* | ||
18 | + * Define RISC-V target-specific operand constraints. | ||
19 | + * Copyright (c) 2021 Linaro | ||
20 | + */ | ||
21 | + | ||
22 | +/* | ||
23 | + * Define constraint letters for register sets: | ||
24 | + * REGS(letter, register_mask) | ||
25 | + */ | ||
26 | +REGS('r', ALL_GENERAL_REGS) | ||
27 | +REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) | ||
28 | + | ||
29 | +/* | ||
30 | + * Define constraint letters for constants: | ||
31 | + * CONST(letter, TCG_CT_CONST_* bit set) | ||
32 | + */ | ||
33 | +CONST('I', TCG_CT_CONST_S12) | ||
34 | +CONST('N', TCG_CT_CONST_N12) | ||
35 | +CONST('M', TCG_CT_CONST_M12) | ||
36 | +CONST('Z', TCG_CT_CONST_ZERO) | ||
37 | diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h | ||
38 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
39 | --- a/tcg/riscv/tcg-target.h | 14 | --- a/tcg/tcg.c |
40 | +++ b/tcg/riscv/tcg-target.h | 15 | +++ b/tcg/tcg.c |
41 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 16 | @@ -XXX,XX +XXX,XX @@ static bool liveness_pass_2(TCGContext *s) |
42 | #define TCG_TARGET_NEED_POOL_LABELS | 17 | return changes; |
43 | |||
44 | #define TCG_TARGET_HAS_MEMORY_BSWAP 0 | ||
45 | +#define TCG_TARGET_CON_STR_H | ||
46 | |||
47 | #endif | ||
48 | diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc | ||
49 | index XXXXXXX..XXXXXXX 100644 | ||
50 | --- a/tcg/riscv/tcg-target.c.inc | ||
51 | +++ b/tcg/riscv/tcg-target.c.inc | ||
52 | @@ -XXX,XX +XXX,XX @@ static const int tcg_target_call_oarg_regs[] = { | ||
53 | #define TCG_CT_CONST_N12 0x400 | ||
54 | #define TCG_CT_CONST_M12 0x800 | ||
55 | |||
56 | +#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32) | ||
57 | +/* | ||
58 | + * For softmmu, we need to avoid conflicts with the first 5 | ||
59 | + * argument registers to call the helper. Some of these are | ||
60 | + * also used for the tlb lookup. | ||
61 | + */ | ||
62 | +#ifdef CONFIG_SOFTMMU | ||
63 | +#define SOFTMMU_RESERVE_REGS MAKE_64BIT_MASK(TCG_REG_A0, 5) | ||
64 | +#else | ||
65 | +#define SOFTMMU_RESERVE_REGS 0 | ||
66 | +#endif | ||
67 | + | ||
68 | + | ||
69 | static inline tcg_target_long sextreg(tcg_target_long val, int pos, int len) | ||
70 | { | ||
71 | if (TCG_TARGET_REG_BITS == 32) { | ||
72 | @@ -XXX,XX +XXX,XX @@ static inline tcg_target_long sextreg(tcg_target_long val, int pos, int len) | ||
73 | } | ||
74 | } | 18 | } |
75 | 19 | ||
76 | -/* parse target specific constraints */ | 20 | -#ifdef CONFIG_DEBUG_TCG |
77 | -static const char *target_parse_constraint(TCGArgConstraint *ct, | 21 | -static void dump_regs(TCGContext *s) |
78 | - const char *ct_str, TCGType type) | ||
79 | -{ | 22 | -{ |
80 | - switch (*ct_str++) { | 23 | - TCGTemp *ts; |
81 | - case 'r': | 24 | - int i; |
82 | - ct->regs = 0xffffffff; | 25 | - char buf[64]; |
83 | - break; | 26 | - |
84 | - case 'L': | 27 | - for(i = 0; i < s->nb_temps; i++) { |
85 | - /* qemu_ld/qemu_st constraint */ | 28 | - ts = &s->temps[i]; |
86 | - ct->regs = 0xffffffff; | 29 | - printf(" %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); |
87 | - /* qemu_ld/qemu_st uses TCG_REG_TMP0 */ | 30 | - switch(ts->val_type) { |
88 | -#if defined(CONFIG_SOFTMMU) | 31 | - case TEMP_VAL_REG: |
89 | - tcg_regset_reset_reg(ct->regs, tcg_target_call_iarg_regs[0]); | 32 | - printf("%s", tcg_target_reg_names[ts->reg]); |
90 | - tcg_regset_reset_reg(ct->regs, tcg_target_call_iarg_regs[1]); | 33 | - break; |
91 | - tcg_regset_reset_reg(ct->regs, tcg_target_call_iarg_regs[2]); | 34 | - case TEMP_VAL_MEM: |
92 | - tcg_regset_reset_reg(ct->regs, tcg_target_call_iarg_regs[3]); | 35 | - printf("%d(%s)", (int)ts->mem_offset, |
93 | - tcg_regset_reset_reg(ct->regs, tcg_target_call_iarg_regs[4]); | 36 | - tcg_target_reg_names[ts->mem_base->reg]); |
94 | -#endif | 37 | - break; |
95 | - break; | 38 | - case TEMP_VAL_CONST: |
96 | - case 'I': | 39 | - printf("$0x%" PRIx64, ts->val); |
97 | - ct->ct |= TCG_CT_CONST_S12; | 40 | - break; |
98 | - break; | 41 | - case TEMP_VAL_DEAD: |
99 | - case 'N': | 42 | - printf("D"); |
100 | - ct->ct |= TCG_CT_CONST_N12; | 43 | - break; |
101 | - break; | 44 | - default: |
102 | - case 'M': | 45 | - printf("???"); |
103 | - ct->ct |= TCG_CT_CONST_M12; | 46 | - break; |
104 | - break; | 47 | - } |
105 | - case 'Z': | 48 | - printf("\n"); |
106 | - /* we can use a zero immediate as a zero register argument. */ | ||
107 | - ct->ct |= TCG_CT_CONST_ZERO; | ||
108 | - break; | ||
109 | - default: | ||
110 | - return NULL; | ||
111 | - } | 49 | - } |
112 | - return ct_str; | 50 | - |
51 | - for(i = 0; i < TCG_TARGET_NB_REGS; i++) { | ||
52 | - if (s->reg_to_temp[i] != NULL) { | ||
53 | - printf("%s: %s\n", | ||
54 | - tcg_target_reg_names[i], | ||
55 | - tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); | ||
56 | - } | ||
57 | - } | ||
113 | -} | 58 | -} |
114 | - | 59 | - |
115 | /* test if a constant matches the constraint */ | 60 | -static void check_regs(TCGContext *s) |
116 | static int tcg_target_const_match(tcg_target_long val, TCGType type, | 61 | -{ |
117 | const TCGArgConstraint *arg_ct) | 62 | - int reg; |
63 | - int k; | ||
64 | - TCGTemp *ts; | ||
65 | - char buf[64]; | ||
66 | - | ||
67 | - for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { | ||
68 | - ts = s->reg_to_temp[reg]; | ||
69 | - if (ts != NULL) { | ||
70 | - if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { | ||
71 | - printf("Inconsistency for register %s:\n", | ||
72 | - tcg_target_reg_names[reg]); | ||
73 | - goto fail; | ||
74 | - } | ||
75 | - } | ||
76 | - } | ||
77 | - for (k = 0; k < s->nb_temps; k++) { | ||
78 | - ts = &s->temps[k]; | ||
79 | - if (ts->val_type == TEMP_VAL_REG | ||
80 | - && ts->kind != TEMP_FIXED | ||
81 | - && s->reg_to_temp[ts->reg] != ts) { | ||
82 | - printf("Inconsistency for temp %s:\n", | ||
83 | - tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); | ||
84 | - fail: | ||
85 | - printf("reg state:\n"); | ||
86 | - dump_regs(s); | ||
87 | - tcg_abort(); | ||
88 | - } | ||
89 | - } | ||
90 | -} | ||
91 | -#endif | ||
92 | - | ||
93 | static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) | ||
94 | { | ||
95 | intptr_t off, size, align; | ||
96 | @@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) | ||
97 | tcg_reg_alloc_op(s, op); | ||
98 | break; | ||
99 | } | ||
100 | -#ifdef CONFIG_DEBUG_TCG | ||
101 | - check_regs(s); | ||
102 | -#endif | ||
103 | /* Test for (pending) buffer overflow. The assumption is that any | ||
104 | one operation beginning below the high water mark cannot overrun | ||
105 | the buffer completely. Thus we can test for overflow after | ||
118 | -- | 106 | -- |
119 | 2.25.1 | 107 | 2.34.1 |
120 | 108 | ||
121 | 109 | diff view generated by jsdifflib |
1 | This eliminates the target-specific function target_parse_constraint | 1 | From: Philippe Mathieu-Daudé <philmd@linaro.org> |
---|---|---|---|
2 | and folds it into the single caller, process_op_defs. Since this is | ||
3 | done directly into the switch statement, duplicates are compilation | ||
4 | errors rather than silently ignored at runtime. | ||
5 | 2 | ||
6 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 3 | In preparation of introducing paired registers, |
4 | massage a bit process_op_defs()'s switch case. | ||
5 | |||
7 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
7 | [PMD: Split from bigger patch, 1/3] | ||
8 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
9 | Message-Id: <20221219220925.79218-2-philmd@linaro.org> | ||
8 | --- | 10 | --- |
9 | tcg/i386/tcg-target-con-str.h | 33 +++++++++++++++++ | 11 | tcg/tcg.c | 61 +++++++++++++++++++++++++++++++------------------------ |
10 | tcg/i386/tcg-target.h | 1 + | 12 | 1 file changed, 34 insertions(+), 27 deletions(-) |
11 | tcg/tcg.c | 33 ++++++++++++++--- | ||
12 | tcg/i386/tcg-target.c.inc | 69 ----------------------------------- | ||
13 | 4 files changed, 62 insertions(+), 74 deletions(-) | ||
14 | create mode 100644 tcg/i386/tcg-target-con-str.h | ||
15 | 13 | ||
16 | diff --git a/tcg/i386/tcg-target-con-str.h b/tcg/i386/tcg-target-con-str.h | ||
17 | new file mode 100644 | ||
18 | index XXXXXXX..XXXXXXX | ||
19 | --- /dev/null | ||
20 | +++ b/tcg/i386/tcg-target-con-str.h | ||
21 | @@ -XXX,XX +XXX,XX @@ | ||
22 | +/* SPDX-License-Identifier: MIT */ | ||
23 | +/* | ||
24 | + * Define i386 target-specific operand constraints. | ||
25 | + * Copyright (c) 2021 Linaro | ||
26 | + * | ||
27 | + */ | ||
28 | + | ||
29 | +/* | ||
30 | + * Define constraint letters for register sets: | ||
31 | + * REGS(letter, register_mask) | ||
32 | + */ | ||
33 | +REGS('a', 1u << TCG_REG_EAX) | ||
34 | +REGS('b', 1u << TCG_REG_EBX) | ||
35 | +REGS('c', 1u << TCG_REG_ECX) | ||
36 | +REGS('d', 1u << TCG_REG_EDX) | ||
37 | +REGS('S', 1u << TCG_REG_ESI) | ||
38 | +REGS('D', 1u << TCG_REG_EDI) | ||
39 | + | ||
40 | +REGS('r', ALL_GENERAL_REGS) | ||
41 | +REGS('x', ALL_VECTOR_REGS) | ||
42 | +REGS('q', ALL_BYTEL_REGS) /* regs that can be used as a byte operand */ | ||
43 | +REGS('Q', ALL_BYTEH_REGS) /* regs with a second byte (e.g. %ah) */ | ||
44 | +REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_ld/st */ | ||
45 | +REGS('s', ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_st8_i32 data */ | ||
46 | + | ||
47 | +/* | ||
48 | + * Define constraint letters for constants: | ||
49 | + * CONST(letter, TCG_CT_CONST_* bit set) | ||
50 | + */ | ||
51 | +CONST('e', TCG_CT_CONST_S32) | ||
52 | +CONST('I', TCG_CT_CONST_I32) | ||
53 | +CONST('W', TCG_CT_CONST_WSZ) | ||
54 | +CONST('Z', TCG_CT_CONST_U32) | ||
55 | diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h | ||
56 | index XXXXXXX..XXXXXXX 100644 | ||
57 | --- a/tcg/i386/tcg-target.h | ||
58 | +++ b/tcg/i386/tcg-target.h | ||
59 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | ||
60 | #define TCG_TARGET_NEED_LDST_LABELS | ||
61 | #endif | ||
62 | #define TCG_TARGET_NEED_POOL_LABELS | ||
63 | +#define TCG_TARGET_CON_STR_H | ||
64 | |||
65 | #endif | ||
66 | diff --git a/tcg/tcg.c b/tcg/tcg.c | 14 | diff --git a/tcg/tcg.c b/tcg/tcg.c |
67 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
68 | --- a/tcg/tcg.c | 16 | --- a/tcg/tcg.c |
69 | +++ b/tcg/tcg.c | 17 | +++ b/tcg/tcg.c |
70 | @@ -XXX,XX +XXX,XX @@ static void tcg_register_jit_int(const void *buf, size_t size, | ||
71 | __attribute__((unused)); | ||
72 | |||
73 | /* Forward declarations for functions declared and used in tcg-target.c.inc. */ | ||
74 | +#ifndef TCG_TARGET_CON_STR_H | ||
75 | static const char *target_parse_constraint(TCGArgConstraint *ct, | ||
76 | const char *ct_str, TCGType type); | ||
77 | +#endif | ||
78 | static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, | ||
79 | intptr_t arg2); | ||
80 | static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); | ||
81 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | 18 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) |
82 | for (op = 0; op < NB_OPS; op++) { | 19 | for (op = 0; op < NB_OPS; op++) { |
83 | TCGOpDef *def = &tcg_op_defs[op]; | 20 | TCGOpDef *def = &tcg_op_defs[op]; |
84 | const TCGTargetOpDef *tdefs; | 21 | const TCGTargetOpDef *tdefs; |
85 | - TCGType type; | 22 | - int i, nb_args; |
86 | int i, nb_args; | 23 | + int i, o, nb_args; |
87 | 24 | ||
88 | if (def->flags & TCG_OPF_NOT_PRESENT) { | 25 | if (def->flags & TCG_OPF_NOT_PRESENT) { |
26 | continue; | ||
89 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | 27 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) |
90 | /* Missing TCGTargetOpDef entry. */ | 28 | |
91 | tcg_debug_assert(tdefs != NULL); | ||
92 | |||
93 | - type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32); | ||
94 | for (i = 0; i < nb_args; i++) { | 29 | for (i = 0; i < nb_args; i++) { |
95 | const char *ct_str = tdefs->args_ct_str[i]; | 30 | const char *ct_str = tdefs->args_ct_str[i]; |
31 | + bool input_p = i >= def->nb_oargs; | ||
32 | + | ||
96 | /* Incomplete TCGTargetOpDef entry. */ | 33 | /* Incomplete TCGTargetOpDef entry. */ |
97 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | 34 | tcg_debug_assert(ct_str != NULL); |
35 | |||
36 | - while (*ct_str != '\0') { | ||
37 | - switch(*ct_str) { | ||
38 | - case '0' ... '9': | ||
39 | - { | ||
40 | - int oarg = *ct_str - '0'; | ||
41 | - tcg_debug_assert(ct_str == tdefs->args_ct_str[i]); | ||
42 | - tcg_debug_assert(oarg < def->nb_oargs); | ||
43 | - tcg_debug_assert(def->args_ct[oarg].regs != 0); | ||
44 | - def->args_ct[i] = def->args_ct[oarg]; | ||
45 | - /* The output sets oalias. */ | ||
46 | - def->args_ct[oarg].oalias = true; | ||
47 | - def->args_ct[oarg].alias_index = i; | ||
48 | - /* The input sets ialias. */ | ||
49 | - def->args_ct[i].ialias = true; | ||
50 | - def->args_ct[i].alias_index = oarg; | ||
51 | - } | ||
52 | - ct_str++; | ||
53 | - break; | ||
54 | - case '&': | ||
55 | - def->args_ct[i].newreg = true; | ||
56 | - ct_str++; | ||
57 | - break; | ||
58 | + switch (*ct_str) { | ||
59 | + case '0' ... '9': | ||
60 | + o = *ct_str - '0'; | ||
61 | + tcg_debug_assert(input_p); | ||
62 | + tcg_debug_assert(o < def->nb_oargs); | ||
63 | + tcg_debug_assert(def->args_ct[o].regs != 0); | ||
64 | + tcg_debug_assert(!def->args_ct[o].oalias); | ||
65 | + def->args_ct[i] = def->args_ct[o]; | ||
66 | + /* The output sets oalias. */ | ||
67 | + def->args_ct[o].oalias = 1; | ||
68 | + def->args_ct[o].alias_index = i; | ||
69 | + /* The input sets ialias. */ | ||
70 | + def->args_ct[i].ialias = 1; | ||
71 | + def->args_ct[i].alias_index = o; | ||
72 | + tcg_debug_assert(ct_str[1] == '\0'); | ||
73 | + continue; | ||
74 | + | ||
75 | + case '&': | ||
76 | + tcg_debug_assert(!input_p); | ||
77 | + def->args_ct[i].newreg = true; | ||
78 | + ct_str++; | ||
79 | + break; | ||
80 | + } | ||
81 | + | ||
82 | + do { | ||
83 | + switch (*ct_str) { | ||
84 | case 'i': | ||
98 | def->args_ct[i].ct |= TCG_CT_CONST; | 85 | def->args_ct[i].ct |= TCG_CT_CONST; |
99 | ct_str++; | 86 | - ct_str++; |
100 | break; | 87 | break; |
101 | + | 88 | |
102 | +#ifdef TCG_TARGET_CON_STR_H | 89 | /* Include all of the target-specific constraints. */ |
103 | + /* Include all of the target-specific constraints. */ | 90 | |
104 | + | 91 | #undef CONST |
105 | +#undef CONST | 92 | #define CONST(CASE, MASK) \ |
106 | +#define CONST(CASE, MASK) \ | 93 | - case CASE: def->args_ct[i].ct |= MASK; ct_str++; break; |
107 | + case CASE: def->args_ct[i].ct |= MASK; ct_str++; break; | 94 | + case CASE: def->args_ct[i].ct |= MASK; break; |
108 | +#define REGS(CASE, MASK) \ | 95 | #define REGS(CASE, MASK) \ |
109 | + case CASE: def->args_ct[i].regs |= MASK; ct_str++; break; | 96 | - case CASE: def->args_ct[i].regs |= MASK; ct_str++; break; |
110 | + | 97 | + case CASE: def->args_ct[i].regs |= MASK; break; |
111 | +#include "tcg-target-con-str.h" | 98 | |
112 | + | 99 | #include "tcg-target-con-str.h" |
113 | +#undef REGS | 100 | |
114 | +#undef CONST | 101 | #undef REGS |
102 | #undef CONST | ||
115 | default: | 103 | default: |
116 | - ct_str = target_parse_constraint(&def->args_ct[i], | 104 | + case '0' ... '9': |
117 | - ct_str, type); | 105 | + case '&': |
118 | /* Typo in TCGTargetOpDef constraint. */ | 106 | /* Typo in TCGTargetOpDef constraint. */ |
119 | - tcg_debug_assert(ct_str != NULL); | 107 | g_assert_not_reached(); |
120 | + g_assert_not_reached(); | ||
121 | +#else | ||
122 | + default: | ||
123 | + { | ||
124 | + TCGType type = (def->flags & TCG_OPF_64BIT | ||
125 | + ? TCG_TYPE_I64 : TCG_TYPE_I32); | ||
126 | + ct_str = target_parse_constraint(&def->args_ct[i], | ||
127 | + ct_str, type); | ||
128 | + /* Typo in TCGTargetOpDef constraint. */ | ||
129 | + tcg_debug_assert(ct_str != NULL); | ||
130 | + } | ||
131 | +#endif | ||
132 | } | 108 | } |
133 | } | 109 | - } |
110 | + } while (*++ct_str != '\0'); | ||
134 | } | 111 | } |
135 | diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc | 112 | |
136 | index XXXXXXX..XXXXXXX 100644 | 113 | /* TCGTargetOpDef entry with too much information? */ |
137 | --- a/tcg/i386/tcg-target.c.inc | ||
138 | +++ b/tcg/i386/tcg-target.c.inc | ||
139 | @@ -XXX,XX +XXX,XX @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, | ||
140 | return true; | ||
141 | } | ||
142 | |||
143 | -/* parse target specific constraints */ | ||
144 | -static const char *target_parse_constraint(TCGArgConstraint *ct, | ||
145 | - const char *ct_str, TCGType type) | ||
146 | -{ | ||
147 | - switch(*ct_str++) { | ||
148 | - case 'a': | ||
149 | - tcg_regset_set_reg(ct->regs, TCG_REG_EAX); | ||
150 | - break; | ||
151 | - case 'b': | ||
152 | - tcg_regset_set_reg(ct->regs, TCG_REG_EBX); | ||
153 | - break; | ||
154 | - case 'c': | ||
155 | - tcg_regset_set_reg(ct->regs, TCG_REG_ECX); | ||
156 | - break; | ||
157 | - case 'd': | ||
158 | - tcg_regset_set_reg(ct->regs, TCG_REG_EDX); | ||
159 | - break; | ||
160 | - case 'S': | ||
161 | - tcg_regset_set_reg(ct->regs, TCG_REG_ESI); | ||
162 | - break; | ||
163 | - case 'D': | ||
164 | - tcg_regset_set_reg(ct->regs, TCG_REG_EDI); | ||
165 | - break; | ||
166 | - case 'q': | ||
167 | - /* A register that can be used as a byte operand. */ | ||
168 | - ct->regs |= ALL_BYTEL_REGS; | ||
169 | - break; | ||
170 | - case 'Q': | ||
171 | - /* A register with an addressable second byte (e.g. %ah). */ | ||
172 | - ct->regs |= ALL_BYTEH_REGS; | ||
173 | - break; | ||
174 | - case 'r': | ||
175 | - /* A general register. */ | ||
176 | - ct->regs |= ALL_GENERAL_REGS; | ||
177 | - break; | ||
178 | - case 'W': | ||
179 | - /* With TZCNT/LZCNT, we can have operand-size as an input. */ | ||
180 | - ct->ct |= TCG_CT_CONST_WSZ; | ||
181 | - break; | ||
182 | - case 'x': | ||
183 | - /* A vector register. */ | ||
184 | - ct->regs |= ALL_VECTOR_REGS; | ||
185 | - break; | ||
186 | - | ||
187 | - case 'L': | ||
188 | - /* qemu_ld/st data+address constraint */ | ||
189 | - ct->regs |= ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS; | ||
190 | - break; | ||
191 | - case 's': | ||
192 | - /* qemu_st8_i32 data constraint */ | ||
193 | - ct->regs |= ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS; | ||
194 | - break; | ||
195 | - | ||
196 | - case 'e': | ||
197 | - ct->ct |= TCG_CT_CONST_S32; | ||
198 | - break; | ||
199 | - case 'Z': | ||
200 | - ct->ct |= TCG_CT_CONST_U32; | ||
201 | - break; | ||
202 | - case 'I': | ||
203 | - ct->ct |= TCG_CT_CONST_I32; | ||
204 | - break; | ||
205 | - | ||
206 | - default: | ||
207 | - return NULL; | ||
208 | - } | ||
209 | - return ct_str; | ||
210 | -} | ||
211 | - | ||
212 | /* test if a constant matches the constraint */ | ||
213 | static inline int tcg_target_const_match(tcg_target_long val, TCGType type, | ||
214 | const TCGArgConstraint *arg_ct) | ||
215 | -- | 114 | -- |
216 | 2.25.1 | 115 | 2.34.1 |
217 | 116 | ||
218 | 117 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | There are several instances where we need to be able to | ||
2 | allocate a pair of registers to related inputs/outputs. | ||
3 | Add 'p' and 'm' register constraints for this, in order to | ||
4 | be able to allocate the even/odd register first or second. | ||
1 | 5 | ||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | --- | ||
8 | include/tcg/tcg.h | 2 + | ||
9 | tcg/tcg.c | 419 ++++++++++++++++++++++++++++++++++++++++------ | ||
10 | 2 files changed, 373 insertions(+), 48 deletions(-) | ||
11 | |||
12 | diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/include/tcg/tcg.h | ||
15 | +++ b/include/tcg/tcg.h | ||
16 | @@ -XXX,XX +XXX,XX @@ typedef struct TCGArgConstraint { | ||
17 | unsigned ct : 16; | ||
18 | unsigned alias_index : 4; | ||
19 | unsigned sort_index : 4; | ||
20 | + unsigned pair_index : 4; | ||
21 | + unsigned pair : 2; /* 0: none, 1: first, 2: second, 3: second alias */ | ||
22 | bool oalias : 1; | ||
23 | bool ialias : 1; | ||
24 | bool newreg : 1; | ||
25 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/tcg/tcg.c | ||
28 | +++ b/tcg/tcg.c | ||
29 | @@ -XXX,XX +XXX,XX @@ static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) | ||
30 | static int get_constraint_priority(const TCGOpDef *def, int k) | ||
31 | { | ||
32 | const TCGArgConstraint *arg_ct = &def->args_ct[k]; | ||
33 | - int n; | ||
34 | + int n = ctpop64(arg_ct->regs); | ||
35 | |||
36 | - if (arg_ct->oalias) { | ||
37 | - /* an alias is equivalent to a single register */ | ||
38 | - n = 1; | ||
39 | - } else { | ||
40 | - n = ctpop64(arg_ct->regs); | ||
41 | + /* | ||
42 | + * Sort constraints of a single register first, which includes output | ||
43 | + * aliases (which must exactly match the input already allocated). | ||
44 | + */ | ||
45 | + if (n == 1 || arg_ct->oalias) { | ||
46 | + return INT_MAX; | ||
47 | } | ||
48 | - return TCG_TARGET_NB_REGS - n + 1; | ||
49 | + | ||
50 | + /* | ||
51 | + * Sort register pairs next, first then second immediately after. | ||
52 | + * Arbitrarily sort multiple pairs by the index of the first reg; | ||
53 | + * there shouldn't be many pairs. | ||
54 | + */ | ||
55 | + switch (arg_ct->pair) { | ||
56 | + case 1: | ||
57 | + case 3: | ||
58 | + return (k + 1) * 2; | ||
59 | + case 2: | ||
60 | + return (arg_ct->pair_index + 1) * 2 - 1; | ||
61 | + } | ||
62 | + | ||
63 | + /* Finally, sort by decreasing register count. */ | ||
64 | + assert(n > 1); | ||
65 | + return -n; | ||
66 | } | ||
67 | |||
68 | /* sort from highest priority to lowest */ | ||
69 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | ||
70 | for (op = 0; op < NB_OPS; op++) { | ||
71 | TCGOpDef *def = &tcg_op_defs[op]; | ||
72 | const TCGTargetOpDef *tdefs; | ||
73 | - int i, o, nb_args; | ||
74 | + bool saw_alias_pair = false; | ||
75 | + int i, o, i2, o2, nb_args; | ||
76 | |||
77 | if (def->flags & TCG_OPF_NOT_PRESENT) { | ||
78 | continue; | ||
79 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | ||
80 | /* The input sets ialias. */ | ||
81 | def->args_ct[i].ialias = 1; | ||
82 | def->args_ct[i].alias_index = o; | ||
83 | + if (def->args_ct[i].pair) { | ||
84 | + saw_alias_pair = true; | ||
85 | + } | ||
86 | tcg_debug_assert(ct_str[1] == '\0'); | ||
87 | continue; | ||
88 | |||
89 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | ||
90 | def->args_ct[i].newreg = true; | ||
91 | ct_str++; | ||
92 | break; | ||
93 | + | ||
94 | + case 'p': /* plus */ | ||
95 | + /* Allocate to the register after the previous. */ | ||
96 | + tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); | ||
97 | + o = i - 1; | ||
98 | + tcg_debug_assert(!def->args_ct[o].pair); | ||
99 | + tcg_debug_assert(!def->args_ct[o].ct); | ||
100 | + def->args_ct[i] = (TCGArgConstraint){ | ||
101 | + .pair = 2, | ||
102 | + .pair_index = o, | ||
103 | + .regs = def->args_ct[o].regs << 1, | ||
104 | + }; | ||
105 | + def->args_ct[o].pair = 1; | ||
106 | + def->args_ct[o].pair_index = i; | ||
107 | + tcg_debug_assert(ct_str[1] == '\0'); | ||
108 | + continue; | ||
109 | + | ||
110 | + case 'm': /* minus */ | ||
111 | + /* Allocate to the register before the previous. */ | ||
112 | + tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); | ||
113 | + o = i - 1; | ||
114 | + tcg_debug_assert(!def->args_ct[o].pair); | ||
115 | + tcg_debug_assert(!def->args_ct[o].ct); | ||
116 | + def->args_ct[i] = (TCGArgConstraint){ | ||
117 | + .pair = 1, | ||
118 | + .pair_index = o, | ||
119 | + .regs = def->args_ct[o].regs >> 1, | ||
120 | + }; | ||
121 | + def->args_ct[o].pair = 2; | ||
122 | + def->args_ct[o].pair_index = i; | ||
123 | + tcg_debug_assert(ct_str[1] == '\0'); | ||
124 | + continue; | ||
125 | } | ||
126 | |||
127 | do { | ||
128 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | ||
129 | default: | ||
130 | case '0' ... '9': | ||
131 | case '&': | ||
132 | + case 'p': | ||
133 | + case 'm': | ||
134 | /* Typo in TCGTargetOpDef constraint. */ | ||
135 | g_assert_not_reached(); | ||
136 | } | ||
137 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | ||
138 | /* TCGTargetOpDef entry with too much information? */ | ||
139 | tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); | ||
140 | |||
141 | + /* | ||
142 | + * Fix up output pairs that are aliased with inputs. | ||
143 | + * When we created the alias, we copied pair from the output. | ||
144 | + * There are three cases: | ||
145 | + * (1a) Pairs of inputs alias pairs of outputs. | ||
146 | + * (1b) One input aliases the first of a pair of outputs. | ||
147 | + * (2) One input aliases the second of a pair of outputs. | ||
148 | + * | ||
149 | + * Case 1a is handled by making sure that the pair_index'es are | ||
150 | + * properly updated so that they appear the same as a pair of inputs. | ||
151 | + * | ||
152 | + * Case 1b is handled by setting the pair_index of the input to | ||
153 | + * itself, simply so it doesn't point to an unrelated argument. | ||
154 | + * Since we don't encounter the "second" during the input allocation | ||
155 | + * phase, nothing happens with the second half of the input pair. | ||
156 | + * | ||
157 | + * Case 2 is handled by setting the second input to pair=3, the | ||
158 | + * first output to pair=3, and the pair_index'es to match. | ||
159 | + */ | ||
160 | + if (saw_alias_pair) { | ||
161 | + for (i = def->nb_oargs; i < nb_args; i++) { | ||
162 | + /* | ||
163 | + * Since [0-9pm] must be alone in the constraint string, | ||
164 | + * the only way they can both be set is if the pair comes | ||
165 | + * from the output alias. | ||
166 | + */ | ||
167 | + if (!def->args_ct[i].ialias) { | ||
168 | + continue; | ||
169 | + } | ||
170 | + switch (def->args_ct[i].pair) { | ||
171 | + case 0: | ||
172 | + break; | ||
173 | + case 1: | ||
174 | + o = def->args_ct[i].alias_index; | ||
175 | + o2 = def->args_ct[o].pair_index; | ||
176 | + tcg_debug_assert(def->args_ct[o].pair == 1); | ||
177 | + tcg_debug_assert(def->args_ct[o2].pair == 2); | ||
178 | + if (def->args_ct[o2].oalias) { | ||
179 | + /* Case 1a */ | ||
180 | + i2 = def->args_ct[o2].alias_index; | ||
181 | + tcg_debug_assert(def->args_ct[i2].pair == 2); | ||
182 | + def->args_ct[i2].pair_index = i; | ||
183 | + def->args_ct[i].pair_index = i2; | ||
184 | + } else { | ||
185 | + /* Case 1b */ | ||
186 | + def->args_ct[i].pair_index = i; | ||
187 | + } | ||
188 | + break; | ||
189 | + case 2: | ||
190 | + o = def->args_ct[i].alias_index; | ||
191 | + o2 = def->args_ct[o].pair_index; | ||
192 | + tcg_debug_assert(def->args_ct[o].pair == 2); | ||
193 | + tcg_debug_assert(def->args_ct[o2].pair == 1); | ||
194 | + if (def->args_ct[o2].oalias) { | ||
195 | + /* Case 1a */ | ||
196 | + i2 = def->args_ct[o2].alias_index; | ||
197 | + tcg_debug_assert(def->args_ct[i2].pair == 1); | ||
198 | + def->args_ct[i2].pair_index = i; | ||
199 | + def->args_ct[i].pair_index = i2; | ||
200 | + } else { | ||
201 | + /* Case 2 */ | ||
202 | + def->args_ct[i].pair = 3; | ||
203 | + def->args_ct[o2].pair = 3; | ||
204 | + def->args_ct[i].pair_index = o2; | ||
205 | + def->args_ct[o2].pair_index = i; | ||
206 | + } | ||
207 | + break; | ||
208 | + default: | ||
209 | + g_assert_not_reached(); | ||
210 | + } | ||
211 | + } | ||
212 | + } | ||
213 | + | ||
214 | /* sort the constraints (XXX: this is just an heuristic) */ | ||
215 | sort_constraints(def, 0, def->nb_oargs); | ||
216 | sort_constraints(def, def->nb_oargs, def->nb_iargs); | ||
217 | @@ -XXX,XX +XXX,XX @@ static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, | ||
218 | tcg_abort(); | ||
219 | } | ||
220 | |||
221 | +static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs, | ||
222 | + TCGRegSet allocated_regs, | ||
223 | + TCGRegSet preferred_regs, bool rev) | ||
224 | +{ | ||
225 | + int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order); | ||
226 | + TCGRegSet reg_ct[2]; | ||
227 | + const int *order; | ||
228 | + | ||
229 | + /* Ensure that if I is not in allocated_regs, I+1 is not either. */ | ||
230 | + reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1)); | ||
231 | + tcg_debug_assert(reg_ct[1] != 0); | ||
232 | + reg_ct[0] = reg_ct[1] & preferred_regs; | ||
233 | + | ||
234 | + order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; | ||
235 | + | ||
236 | + /* | ||
237 | + * Skip the preferred_regs option if it cannot be satisfied, | ||
238 | + * or if the preference made no difference. | ||
239 | + */ | ||
240 | + k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; | ||
241 | + | ||
242 | + /* | ||
243 | + * Minimize the number of flushes by looking for 2 free registers first, | ||
244 | + * then a single flush, then two flushes. | ||
245 | + */ | ||
246 | + for (fmin = 2; fmin >= 0; fmin--) { | ||
247 | + for (j = k; j < 2; j++) { | ||
248 | + TCGRegSet set = reg_ct[j]; | ||
249 | + | ||
250 | + for (i = 0; i < n; i++) { | ||
251 | + TCGReg reg = order[i]; | ||
252 | + | ||
253 | + if (tcg_regset_test_reg(set, reg)) { | ||
254 | + int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1]; | ||
255 | + if (f >= fmin) { | ||
256 | + tcg_reg_free(s, reg, allocated_regs); | ||
257 | + tcg_reg_free(s, reg + 1, allocated_regs); | ||
258 | + return reg; | ||
259 | + } | ||
260 | + } | ||
261 | + } | ||
262 | + } | ||
263 | + } | ||
264 | + tcg_abort(); | ||
265 | +} | ||
266 | + | ||
267 | /* Make sure the temporary is in a register. If needed, allocate the register | ||
268 | from DESIRED while avoiding ALLOCATED. */ | ||
269 | static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, | ||
270 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
271 | |||
272 | /* satisfy input constraints */ | ||
273 | for (k = 0; k < nb_iargs; k++) { | ||
274 | - TCGRegSet i_preferred_regs; | ||
275 | - bool allocate_new_reg; | ||
276 | + TCGRegSet i_preferred_regs, i_required_regs; | ||
277 | + bool allocate_new_reg, copyto_new_reg; | ||
278 | + TCGTemp *ts2; | ||
279 | + int i1, i2; | ||
280 | |||
281 | i = def->args_ct[nb_oargs + k].sort_index; | ||
282 | arg = op->args[i]; | ||
283 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
284 | |||
285 | reg = ts->reg; | ||
286 | i_preferred_regs = 0; | ||
287 | + i_required_regs = arg_ct->regs; | ||
288 | allocate_new_reg = false; | ||
289 | + copyto_new_reg = false; | ||
290 | |||
291 | - if (arg_ct->ialias) { | ||
292 | + switch (arg_ct->pair) { | ||
293 | + case 0: /* not paired */ | ||
294 | + if (arg_ct->ialias) { | ||
295 | + i_preferred_regs = op->output_pref[arg_ct->alias_index]; | ||
296 | + | ||
297 | + /* | ||
298 | + * If the input is not dead after the instruction, | ||
299 | + * we must allocate a new register and move it. | ||
300 | + */ | ||
301 | + if (!IS_DEAD_ARG(i)) { | ||
302 | + allocate_new_reg = true; | ||
303 | + } else if (ts->val_type == TEMP_VAL_REG) { | ||
304 | + /* | ||
305 | + * Check if the current register has already been | ||
306 | + * allocated for another input. | ||
307 | + */ | ||
308 | + allocate_new_reg = | ||
309 | + tcg_regset_test_reg(i_allocated_regs, reg); | ||
310 | + } | ||
311 | + } | ||
312 | + if (!allocate_new_reg) { | ||
313 | + temp_load(s, ts, i_required_regs, i_allocated_regs, | ||
314 | + i_preferred_regs); | ||
315 | + reg = ts->reg; | ||
316 | + allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg); | ||
317 | + } | ||
318 | + if (allocate_new_reg) { | ||
319 | + /* | ||
320 | + * Allocate a new register matching the constraint | ||
321 | + * and move the temporary register into it. | ||
322 | + */ | ||
323 | + temp_load(s, ts, tcg_target_available_regs[ts->type], | ||
324 | + i_allocated_regs, 0); | ||
325 | + reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs, | ||
326 | + i_preferred_regs, ts->indirect_base); | ||
327 | + copyto_new_reg = true; | ||
328 | + } | ||
329 | + break; | ||
330 | + | ||
331 | + case 1: | ||
332 | + /* First of an input pair; if i1 == i2, the second is an output. */ | ||
333 | + i1 = i; | ||
334 | + i2 = arg_ct->pair_index; | ||
335 | + ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL; | ||
336 | + | ||
337 | + /* | ||
338 | + * It is easier to default to allocating a new pair | ||
339 | + * and to identify a few cases where it's not required. | ||
340 | + */ | ||
341 | + if (arg_ct->ialias) { | ||
342 | + i_preferred_regs = op->output_pref[arg_ct->alias_index]; | ||
343 | + if (IS_DEAD_ARG(i1) && | ||
344 | + IS_DEAD_ARG(i2) && | ||
345 | + ts->val_type == TEMP_VAL_REG && | ||
346 | + ts->reg < TCG_TARGET_NB_REGS - 1 && | ||
347 | + tcg_regset_test_reg(i_required_regs, reg) && | ||
348 | + !tcg_regset_test_reg(i_allocated_regs, reg) && | ||
349 | + !tcg_regset_test_reg(i_allocated_regs, reg + 1) && | ||
350 | + (ts2 | ||
351 | + ? ts2->val_type == TEMP_VAL_REG && | ||
352 | + ts2->reg == reg + 1 | ||
353 | + : s->reg_to_temp[reg + 1] == NULL)) { | ||
354 | + break; | ||
355 | + } | ||
356 | + } else { | ||
357 | + /* Without aliasing, the pair must also be an input. */ | ||
358 | + tcg_debug_assert(ts2); | ||
359 | + if (ts->val_type == TEMP_VAL_REG && | ||
360 | + ts2->val_type == TEMP_VAL_REG && | ||
361 | + ts2->reg == reg + 1 && | ||
362 | + tcg_regset_test_reg(i_required_regs, reg)) { | ||
363 | + break; | ||
364 | + } | ||
365 | + } | ||
366 | + reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs, | ||
367 | + 0, ts->indirect_base); | ||
368 | + goto do_pair; | ||
369 | + | ||
370 | + case 2: /* pair second */ | ||
371 | + reg = new_args[arg_ct->pair_index] + 1; | ||
372 | + goto do_pair; | ||
373 | + | ||
374 | + case 3: /* ialias with second output, no first input */ | ||
375 | + tcg_debug_assert(arg_ct->ialias); | ||
376 | i_preferred_regs = op->output_pref[arg_ct->alias_index]; | ||
377 | |||
378 | - /* | ||
379 | - * If the input is readonly, then it cannot also be an | ||
380 | - * output and aliased to itself. If the input is not | ||
381 | - * dead after the instruction, we must allocate a new | ||
382 | - * register and move it. | ||
383 | - */ | ||
384 | - if (temp_readonly(ts) || !IS_DEAD_ARG(i)) { | ||
385 | - allocate_new_reg = true; | ||
386 | - } else if (ts->val_type == TEMP_VAL_REG) { | ||
387 | - /* | ||
388 | - * Check if the current register has already been | ||
389 | - * allocated for another input. | ||
390 | - */ | ||
391 | - allocate_new_reg = tcg_regset_test_reg(i_allocated_regs, reg); | ||
392 | + if (IS_DEAD_ARG(i) && | ||
393 | + ts->val_type == TEMP_VAL_REG && | ||
394 | + reg > 0 && | ||
395 | + s->reg_to_temp[reg - 1] == NULL && | ||
396 | + tcg_regset_test_reg(i_required_regs, reg) && | ||
397 | + !tcg_regset_test_reg(i_allocated_regs, reg) && | ||
398 | + !tcg_regset_test_reg(i_allocated_regs, reg - 1)) { | ||
399 | + tcg_regset_set_reg(i_allocated_regs, reg - 1); | ||
400 | + break; | ||
401 | } | ||
402 | - } | ||
403 | + reg = tcg_reg_alloc_pair(s, i_required_regs >> 1, | ||
404 | + i_allocated_regs, 0, | ||
405 | + ts->indirect_base); | ||
406 | + tcg_regset_set_reg(i_allocated_regs, reg); | ||
407 | + reg += 1; | ||
408 | + goto do_pair; | ||
409 | |||
410 | - if (!allocate_new_reg) { | ||
411 | - temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs); | ||
412 | - reg = ts->reg; | ||
413 | - allocate_new_reg = !tcg_regset_test_reg(arg_ct->regs, reg); | ||
414 | - } | ||
415 | - | ||
416 | - if (allocate_new_reg) { | ||
417 | + do_pair: | ||
418 | /* | ||
419 | - * Allocate a new register matching the constraint | ||
420 | - * and move the temporary register into it. | ||
421 | + * If an aliased input is not dead after the instruction, | ||
422 | + * we must allocate a new register and move it. | ||
423 | */ | ||
424 | - temp_load(s, ts, tcg_target_available_regs[ts->type], | ||
425 | - i_allocated_regs, 0); | ||
426 | - reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs, | ||
427 | - i_preferred_regs, ts->indirect_base); | ||
428 | + if (arg_ct->ialias && !IS_DEAD_ARG(i)) { | ||
429 | + TCGRegSet t_allocated_regs = i_allocated_regs; | ||
430 | + | ||
431 | + /* | ||
432 | + * Because of the alias, and the continued life, make sure | ||
433 | + * that the temp is somewhere *other* than the reg pair, | ||
434 | + * and we get a copy in reg. | ||
435 | + */ | ||
436 | + tcg_regset_set_reg(t_allocated_regs, reg); | ||
437 | + tcg_regset_set_reg(t_allocated_regs, reg + 1); | ||
438 | + if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) { | ||
439 | + /* If ts was already in reg, copy it somewhere else. */ | ||
440 | + TCGReg nr; | ||
441 | + bool ok; | ||
442 | + | ||
443 | + tcg_debug_assert(ts->kind != TEMP_FIXED); | ||
444 | + nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], | ||
445 | + t_allocated_regs, 0, ts->indirect_base); | ||
446 | + ok = tcg_out_mov(s, ts->type, nr, reg); | ||
447 | + tcg_debug_assert(ok); | ||
448 | + | ||
449 | + set_temp_val_reg(s, ts, nr); | ||
450 | + } else { | ||
451 | + temp_load(s, ts, tcg_target_available_regs[ts->type], | ||
452 | + t_allocated_regs, 0); | ||
453 | + copyto_new_reg = true; | ||
454 | + } | ||
455 | + } else { | ||
456 | + /* Preferably allocate to reg, otherwise copy. */ | ||
457 | + i_required_regs = (TCGRegSet)1 << reg; | ||
458 | + temp_load(s, ts, i_required_regs, i_allocated_regs, | ||
459 | + i_preferred_regs); | ||
460 | + copyto_new_reg = ts->reg != reg; | ||
461 | + } | ||
462 | + break; | ||
463 | + | ||
464 | + default: | ||
465 | + g_assert_not_reached(); | ||
466 | + } | ||
467 | + | ||
468 | + if (copyto_new_reg) { | ||
469 | if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { | ||
470 | /* | ||
471 | * Cross register class move not supported. Sync the | ||
472 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
473 | /* ENV should not be modified. */ | ||
474 | tcg_debug_assert(!temp_readonly(ts)); | ||
475 | |||
476 | - if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { | ||
477 | - reg = new_args[arg_ct->alias_index]; | ||
478 | - } else if (arg_ct->newreg) { | ||
479 | - reg = tcg_reg_alloc(s, arg_ct->regs, | ||
480 | - i_allocated_regs | o_allocated_regs, | ||
481 | - op->output_pref[k], ts->indirect_base); | ||
482 | - } else { | ||
483 | - reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, | ||
484 | - op->output_pref[k], ts->indirect_base); | ||
485 | + switch (arg_ct->pair) { | ||
486 | + case 0: /* not paired */ | ||
487 | + if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { | ||
488 | + reg = new_args[arg_ct->alias_index]; | ||
489 | + } else if (arg_ct->newreg) { | ||
490 | + reg = tcg_reg_alloc(s, arg_ct->regs, | ||
491 | + i_allocated_regs | o_allocated_regs, | ||
492 | + op->output_pref[k], ts->indirect_base); | ||
493 | + } else { | ||
494 | + reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, | ||
495 | + op->output_pref[k], ts->indirect_base); | ||
496 | + } | ||
497 | + break; | ||
498 | + | ||
499 | + case 1: /* first of pair */ | ||
500 | + tcg_debug_assert(!arg_ct->newreg); | ||
501 | + if (arg_ct->oalias) { | ||
502 | + reg = new_args[arg_ct->alias_index]; | ||
503 | + break; | ||
504 | + } | ||
505 | + reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, | ||
506 | + op->output_pref[k], ts->indirect_base); | ||
507 | + break; | ||
508 | + | ||
509 | + case 2: /* second of pair */ | ||
510 | + tcg_debug_assert(!arg_ct->newreg); | ||
511 | + if (arg_ct->oalias) { | ||
512 | + reg = new_args[arg_ct->alias_index]; | ||
513 | + } else { | ||
514 | + reg = new_args[arg_ct->pair_index] + 1; | ||
515 | + } | ||
516 | + break; | ||
517 | + | ||
518 | + case 3: /* first of pair, aliasing with a second input */ | ||
519 | + tcg_debug_assert(!arg_ct->newreg); | ||
520 | + reg = new_args[arg_ct->pair_index] - 1; | ||
521 | + break; | ||
522 | + | ||
523 | + default: | ||
524 | + g_assert_not_reached(); | ||
525 | } | ||
526 | tcg_regset_set_reg(o_allocated_regs, reg); | ||
527 | set_temp_val_reg(s, ts, reg); | ||
528 | -- | ||
529 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | While we initialize this value in cpu_common_reset, that | ||
2 | isn't called during startup, so set it as well in init. | ||
3 | This fixes -singlestep versus the very first TB. | ||
1 | 4 | ||
5 | Fixes: 04f5b647ed07 ("accel/tcg: Handle -singlestep in curr_cflags") | ||
6 | Reviewed-by: Alex Bennée <alex.bennee@linaro.org> | ||
7 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
8 | --- | ||
9 | hw/core/cpu-common.c | 1 + | ||
10 | 1 file changed, 1 insertion(+) | ||
11 | |||
12 | diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/hw/core/cpu-common.c | ||
15 | +++ b/hw/core/cpu-common.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static void cpu_common_initfn(Object *obj) | ||
17 | /* the default value is changed by qemu_init_vcpu() for softmmu */ | ||
18 | cpu->nr_cores = 1; | ||
19 | cpu->nr_threads = 1; | ||
20 | + cpu->cflags_next_tb = -1; | ||
21 | |||
22 | qemu_mutex_init(&cpu->work_mutex); | ||
23 | QSIMPLEQ_INIT(&cpu->work_list); | ||
24 | -- | ||
25 | 2.34.1 | ||
26 | |||
27 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | Use the official extend/extract functions instead of routines |
---|---|---|---|
2 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | 2 | that will shortly be internal to tcg. |
3 | |||
4 | Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> | ||
5 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
3 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
4 | --- | 7 | --- |
5 | tcg/tci/tcg-target-con-str.h | 11 +++++++++++ | 8 | target/sparc/translate.c | 21 ++++----------------- |
6 | tcg/tci/tcg-target.h | 2 ++ | 9 | 1 file changed, 4 insertions(+), 17 deletions(-) |
7 | tcg/tci/tcg-target.c.inc | 14 -------------- | ||
8 | 3 files changed, 13 insertions(+), 14 deletions(-) | ||
9 | create mode 100644 tcg/tci/tcg-target-con-str.h | ||
10 | 10 | ||
11 | diff --git a/tcg/tci/tcg-target-con-str.h b/tcg/tci/tcg-target-con-str.h | 11 | diff --git a/target/sparc/translate.c b/target/sparc/translate.c |
12 | new file mode 100644 | 12 | index XXXXXXX..XXXXXXX 100644 |
13 | index XXXXXXX..XXXXXXX | 13 | --- a/target/sparc/translate.c |
14 | --- /dev/null | 14 | +++ b/target/sparc/translate.c |
15 | +++ b/tcg/tci/tcg-target-con-str.h | 15 | @@ -XXX,XX +XXX,XX @@ static inline void gen_update_fprs_dirty(DisasContext *dc, int rd) |
16 | @@ -XXX,XX +XXX,XX @@ | 16 | /* floating point registers moves */ |
17 | +/* SPDX-License-Identifier: MIT */ | 17 | static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src) |
18 | +/* | 18 | { |
19 | + * Define TCI target-specific operand constraints. | 19 | -#if TCG_TARGET_REG_BITS == 32 |
20 | + * Copyright (c) 2021 Linaro | 20 | - if (src & 1) { |
21 | + */ | 21 | - return TCGV_LOW(cpu_fpr[src / 2]); |
22 | - } else { | ||
23 | - return TCGV_HIGH(cpu_fpr[src / 2]); | ||
24 | - } | ||
25 | -#else | ||
26 | TCGv_i32 ret = get_temp_i32(dc); | ||
27 | if (src & 1) { | ||
28 | tcg_gen_extrl_i64_i32(ret, cpu_fpr[src / 2]); | ||
29 | @@ -XXX,XX +XXX,XX @@ static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src) | ||
30 | tcg_gen_extrh_i64_i32(ret, cpu_fpr[src / 2]); | ||
31 | } | ||
32 | return ret; | ||
33 | -#endif | ||
34 | } | ||
35 | |||
36 | static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v) | ||
37 | { | ||
38 | -#if TCG_TARGET_REG_BITS == 32 | ||
39 | - if (dst & 1) { | ||
40 | - tcg_gen_mov_i32(TCGV_LOW(cpu_fpr[dst / 2]), v); | ||
41 | - } else { | ||
42 | - tcg_gen_mov_i32(TCGV_HIGH(cpu_fpr[dst / 2]), v); | ||
43 | - } | ||
44 | -#else | ||
45 | - TCGv_i64 t = (TCGv_i64)v; | ||
46 | + TCGv_i64 t = tcg_temp_new_i64(); | ||
22 | + | 47 | + |
23 | +/* | 48 | + tcg_gen_extu_i32_i64(t, v); |
24 | + * Define constraint letters for register sets: | 49 | tcg_gen_deposit_i64(cpu_fpr[dst / 2], cpu_fpr[dst / 2], t, |
25 | + * REGS(letter, register_mask) | 50 | (dst & 1 ? 0 : 32), 32); |
26 | + */ | 51 | -#endif |
27 | +REGS('r', MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) | 52 | + tcg_temp_free_i64(t); |
28 | diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h | 53 | gen_update_fprs_dirty(dc, dst); |
29 | index XXXXXXX..XXXXXXX 100644 | ||
30 | --- a/tcg/tci/tcg-target.h | ||
31 | +++ b/tcg/tci/tcg-target.h | ||
32 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | ||
33 | /* no need to flush icache explicitly */ | ||
34 | } | 54 | } |
35 | 55 | ||
36 | +#define TCG_TARGET_CON_STR_H | ||
37 | + | ||
38 | #endif /* TCG_TARGET_H */ | ||
39 | diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc | ||
40 | index XXXXXXX..XXXXXXX 100644 | ||
41 | --- a/tcg/tci/tcg-target.c.inc | ||
42 | +++ b/tcg/tci/tcg-target.c.inc | ||
43 | @@ -XXX,XX +XXX,XX @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, | ||
44 | return true; | ||
45 | } | ||
46 | |||
47 | -/* Parse target specific constraints. */ | ||
48 | -static const char *target_parse_constraint(TCGArgConstraint *ct, | ||
49 | - const char *ct_str, TCGType type) | ||
50 | -{ | ||
51 | - switch (*ct_str++) { | ||
52 | - case 'r': | ||
53 | - ct->regs = BIT(TCG_TARGET_NB_REGS) - 1; | ||
54 | - break; | ||
55 | - default: | ||
56 | - return NULL; | ||
57 | - } | ||
58 | - return ct_str; | ||
59 | -} | ||
60 | - | ||
61 | #if defined(CONFIG_DEBUG_TCG_INTERPRETER) | ||
62 | /* Show current bytecode. Used by tcg interpreter. */ | ||
63 | void tci_disas(uint8_t opc) | ||
64 | -- | 56 | -- |
65 | 2.25.1 | 57 | 2.34.1 |
66 | 58 | ||
67 | 59 | diff view generated by jsdifflib |
1 | Create symbolic constants for all low-byte-addressable | 1 | Move the error-generating fallback from tcg-op.c, and |
---|---|---|---|
2 | and second-byte-addressable registers. Create a symbol | 2 | replace "_link_error" with modern QEMU_ERROR markup. |
3 | for the registers that need reserving for softmmu. | ||
4 | 3 | ||
5 | There is no functional change for 's', as this letter is | 4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
6 | only used for i386. The BYTEL name is correct for the | ||
7 | action we wish from the constraint. | ||
8 | |||
9 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
10 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
11 | --- | 6 | --- |
12 | tcg/i386/tcg-target.c.inc | 40 +++++++++++++++++++-------------------- | 7 | include/tcg/tcg-op.h | 33 +++++---------------------------- |
13 | 1 file changed, 20 insertions(+), 20 deletions(-) | 8 | include/tcg/tcg.h | 12 ------------ |
9 | tcg/tcg-internal.h | 14 ++++++++++++++ | ||
10 | tcg/tcg-op-vec.c | 2 ++ | ||
11 | tcg/tcg-op.c | 37 ++++++++++++++++++++++++++++--------- | ||
12 | 5 files changed, 49 insertions(+), 49 deletions(-) | ||
14 | 13 | ||
15 | diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc | 14 | diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h |
16 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/tcg/i386/tcg-target.c.inc | 16 | --- a/include/tcg/tcg-op.h |
18 | +++ b/tcg/i386/tcg-target.c.inc | 17 | +++ b/include/tcg/tcg-op.h |
19 | @@ -XXX,XX +XXX,XX @@ static const int tcg_target_call_oarg_regs[] = { | 18 | @@ -XXX,XX +XXX,XX @@ static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) |
20 | # define TCG_REG_L1 TCG_REG_EDX | 19 | tcg_gen_op3_i64(INDEX_op_mul_i64, ret, arg1, arg2); |
21 | #endif | 20 | } |
22 | 21 | #else /* TCG_TARGET_REG_BITS == 32 */ | |
23 | +#define ALL_BYTEH_REGS 0x0000000fu | 22 | -static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, |
24 | +#if TCG_TARGET_REG_BITS == 64 | 23 | - tcg_target_long offset) |
25 | +# define ALL_GENERAL_REGS 0x0000ffffu | 24 | -{ |
26 | +# define ALL_VECTOR_REGS 0xffff0000u | 25 | - tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset); |
27 | +# define ALL_BYTEL_REGS ALL_GENERAL_REGS | 26 | -} |
27 | +void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset); | ||
28 | +void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset); | ||
29 | +void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset); | ||
30 | |||
31 | -static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, | ||
32 | - tcg_target_long offset) | ||
33 | -{ | ||
34 | - tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset); | ||
35 | -} | ||
36 | - | ||
37 | -static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, | ||
38 | - tcg_target_long offset) | ||
39 | -{ | ||
40 | - tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); | ||
41 | -} | ||
42 | - | ||
43 | -static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) | ||
44 | -{ | ||
45 | - tcg_gen_add2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), | ||
46 | - TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); | ||
47 | -} | ||
48 | - | ||
49 | -static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) | ||
50 | -{ | ||
51 | - tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), | ||
52 | - TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); | ||
53 | -} | ||
54 | +void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2); | ||
55 | +void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2); | ||
56 | |||
57 | void tcg_gen_discard_i64(TCGv_i64 arg); | ||
58 | void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg); | ||
59 | diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h | ||
60 | index XXXXXXX..XXXXXXX 100644 | ||
61 | --- a/include/tcg/tcg.h | ||
62 | +++ b/include/tcg/tcg.h | ||
63 | @@ -XXX,XX +XXX,XX @@ static inline TCGv_vec temp_tcgv_vec(TCGTemp *t) | ||
64 | return (TCGv_vec)temp_tcgv_i32(t); | ||
65 | } | ||
66 | |||
67 | -#if TCG_TARGET_REG_BITS == 32 | ||
68 | -static inline TCGv_i32 TCGV_LOW(TCGv_i64 t) | ||
69 | -{ | ||
70 | - return temp_tcgv_i32(tcgv_i64_temp(t)); | ||
71 | -} | ||
72 | - | ||
73 | -static inline TCGv_i32 TCGV_HIGH(TCGv_i64 t) | ||
74 | -{ | ||
75 | - return temp_tcgv_i32(tcgv_i64_temp(t) + 1); | ||
76 | -} | ||
77 | -#endif | ||
78 | - | ||
79 | static inline TCGArg tcg_get_insn_param(TCGOp *op, int arg) | ||
80 | { | ||
81 | return op->args[arg]; | ||
82 | diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h | ||
83 | index XXXXXXX..XXXXXXX 100644 | ||
84 | --- a/tcg/tcg-internal.h | ||
85 | +++ b/tcg/tcg-internal.h | ||
86 | @@ -XXX,XX +XXX,XX @@ static inline unsigned tcg_call_flags(TCGOp *op) | ||
87 | return tcg_call_info(op)->flags; | ||
88 | } | ||
89 | |||
90 | +#if TCG_TARGET_REG_BITS == 32 | ||
91 | +static inline TCGv_i32 TCGV_LOW(TCGv_i64 t) | ||
92 | +{ | ||
93 | + return temp_tcgv_i32(tcgv_i64_temp(t)); | ||
94 | +} | ||
95 | +static inline TCGv_i32 TCGV_HIGH(TCGv_i64 t) | ||
96 | +{ | ||
97 | + return temp_tcgv_i32(tcgv_i64_temp(t) + 1); | ||
98 | +} | ||
28 | +#else | 99 | +#else |
29 | +# define ALL_GENERAL_REGS 0x000000ffu | 100 | +extern TCGv_i32 TCGV_LOW(TCGv_i64) QEMU_ERROR("32-bit code path is reachable"); |
30 | +# define ALL_VECTOR_REGS 0x00ff0000u | 101 | +extern TCGv_i32 TCGV_HIGH(TCGv_i64) QEMU_ERROR("32-bit code path is reachable"); |
31 | +# define ALL_BYTEL_REGS ALL_BYTEH_REGS | ||
32 | +#endif | ||
33 | +#ifdef CONFIG_SOFTMMU | ||
34 | +# define SOFTMMU_RESERVE_REGS ((1 << TCG_REG_L0) | (1 << TCG_REG_L1)) | ||
35 | +#else | ||
36 | +# define SOFTMMU_RESERVE_REGS 0 | ||
37 | +#endif | 102 | +#endif |
38 | + | 103 | + |
39 | /* The host compiler should supply <cpuid.h> to enable runtime features | 104 | #endif /* TCG_INTERNAL_H */ |
40 | detection, as we're not going to go so far as our own inline assembly. | 105 | diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c |
41 | If not available, default values will be assumed. */ | 106 | index XXXXXXX..XXXXXXX 100644 |
42 | @@ -XXX,XX +XXX,XX @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, | 107 | --- a/tcg/tcg-op-vec.c |
43 | return true; | 108 | +++ b/tcg/tcg-op-vec.c |
109 | @@ -XXX,XX +XXX,XX @@ | ||
110 | #include "tcg/tcg.h" | ||
111 | #include "tcg/tcg-op.h" | ||
112 | #include "tcg/tcg-mo.h" | ||
113 | +#include "tcg-internal.h" | ||
114 | + | ||
115 | |||
116 | /* Reduce the number of ifdefs below. This assumes that all uses of | ||
117 | TCGV_HIGH and TCGV_LOW are properly protected by a conditional that | ||
118 | diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c | ||
119 | index XXXXXXX..XXXXXXX 100644 | ||
120 | --- a/tcg/tcg-op.c | ||
121 | +++ b/tcg/tcg-op.c | ||
122 | @@ -XXX,XX +XXX,XX @@ | ||
123 | #include "tcg/tcg-op.h" | ||
124 | #include "tcg/tcg-mo.h" | ||
125 | #include "exec/plugin-gen.h" | ||
126 | +#include "tcg-internal.h" | ||
127 | |||
128 | -/* Reduce the number of ifdefs below. This assumes that all uses of | ||
129 | - TCGV_HIGH and TCGV_LOW are properly protected by a conditional that | ||
130 | - the compiler can eliminate. */ | ||
131 | -#if TCG_TARGET_REG_BITS == 64 | ||
132 | -extern TCGv_i32 TCGV_LOW_link_error(TCGv_i64); | ||
133 | -extern TCGv_i32 TCGV_HIGH_link_error(TCGv_i64); | ||
134 | -#define TCGV_LOW TCGV_LOW_link_error | ||
135 | -#define TCGV_HIGH TCGV_HIGH_link_error | ||
136 | -#endif | ||
137 | |||
138 | void tcg_gen_op1(TCGOpcode opc, TCGArg a1) | ||
139 | { | ||
140 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) | ||
141 | #endif | ||
44 | } | 142 | } |
45 | 143 | ||
46 | -#if TCG_TARGET_REG_BITS == 64 | 144 | +void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) |
47 | -#define ALL_GENERAL_REGS 0x0000ffffu | 145 | +{ |
48 | -#define ALL_VECTOR_REGS 0xffff0000u | 146 | + tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset); |
49 | -#else | 147 | +} |
50 | -#define ALL_GENERAL_REGS 0x000000ffu | 148 | + |
51 | -#define ALL_VECTOR_REGS 0x00ff0000u | 149 | +void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) |
52 | -#endif | 150 | +{ |
53 | - | 151 | + tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset); |
54 | /* parse target specific constraints */ | 152 | +} |
55 | static const char *target_parse_constraint(TCGArgConstraint *ct, | 153 | + |
56 | const char *ct_str, TCGType type) | 154 | +void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) |
57 | @@ -XXX,XX +XXX,XX @@ static const char *target_parse_constraint(TCGArgConstraint *ct, | 155 | +{ |
58 | break; | 156 | + tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); |
59 | case 'q': | 157 | +} |
60 | /* A register that can be used as a byte operand. */ | 158 | + |
61 | - ct->regs = TCG_TARGET_REG_BITS == 64 ? 0xffff : 0xf; | 159 | void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) |
62 | + ct->regs |= ALL_BYTEL_REGS; | 160 | { |
63 | break; | 161 | #if HOST_BIG_ENDIAN |
64 | case 'Q': | 162 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) |
65 | /* A register with an addressable second byte (e.g. %ah). */ | 163 | #endif |
66 | - ct->regs = 0xf; | 164 | } |
67 | + ct->regs |= ALL_BYTEH_REGS; | 165 | |
68 | break; | 166 | +void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) |
69 | case 'r': | 167 | +{ |
70 | /* A general register. */ | 168 | + tcg_gen_add2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), |
71 | @@ -XXX,XX +XXX,XX @@ static const char *target_parse_constraint(TCGArgConstraint *ct, | 169 | + TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); |
72 | 170 | +} | |
73 | case 'L': | 171 | + |
74 | /* qemu_ld/st data+address constraint */ | 172 | +void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) |
75 | - ct->regs = TCG_TARGET_REG_BITS == 64 ? 0xffff : 0xff; | 173 | +{ |
76 | -#ifdef CONFIG_SOFTMMU | 174 | + tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), |
77 | - tcg_regset_reset_reg(ct->regs, TCG_REG_L0); | 175 | + TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); |
78 | - tcg_regset_reset_reg(ct->regs, TCG_REG_L1); | 176 | +} |
79 | -#endif | 177 | + |
80 | + ct->regs |= ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS; | 178 | void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) |
81 | break; | 179 | { |
82 | case 's': | 180 | tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); |
83 | /* qemu_st8_i32 data constraint */ | ||
84 | - ct->regs = 0xf; | ||
85 | -#ifdef CONFIG_SOFTMMU | ||
86 | - tcg_regset_reset_reg(ct->regs, TCG_REG_L0); | ||
87 | - tcg_regset_reset_reg(ct->regs, TCG_REG_L1); | ||
88 | -#endif | ||
89 | + ct->regs |= ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS; | ||
90 | break; | ||
91 | |||
92 | case 'e': | ||
93 | -- | 181 | -- |
94 | 2.25.1 | 182 | 2.34.1 |
95 | 183 | ||
96 | 184 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Record the location of a TCGTemp within a larger object. | ||
1 | 2 | ||
3 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
4 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
5 | --- | ||
6 | include/tcg/tcg.h | 1 + | ||
7 | tcg/tcg.c | 3 +++ | ||
8 | 2 files changed, 4 insertions(+) | ||
9 | |||
10 | diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/include/tcg/tcg.h | ||
13 | +++ b/include/tcg/tcg.h | ||
14 | @@ -XXX,XX +XXX,XX @@ typedef struct TCGTemp { | ||
15 | unsigned int mem_coherent:1; | ||
16 | unsigned int mem_allocated:1; | ||
17 | unsigned int temp_allocated:1; | ||
18 | + unsigned int temp_subindex:1; | ||
19 | |||
20 | int64_t val; | ||
21 | struct TCGTemp *mem_base; | ||
22 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
23 | index XXXXXXX..XXXXXXX 100644 | ||
24 | --- a/tcg/tcg.c | ||
25 | +++ b/tcg/tcg.c | ||
26 | @@ -XXX,XX +XXX,XX @@ TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, | ||
27 | ts2->mem_allocated = 1; | ||
28 | ts2->mem_base = base_ts; | ||
29 | ts2->mem_offset = offset + (1 - bigendian) * 4; | ||
30 | + ts2->temp_subindex = 1; | ||
31 | pstrcpy(buf, sizeof(buf), name); | ||
32 | pstrcat(buf, sizeof(buf), "_1"); | ||
33 | ts2->name = strdup(buf); | ||
34 | @@ -XXX,XX +XXX,XX @@ TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) | ||
35 | ts2->base_type = TCG_TYPE_I64; | ||
36 | ts2->type = TCG_TYPE_I32; | ||
37 | ts2->temp_allocated = 1; | ||
38 | + ts2->temp_subindex = 1; | ||
39 | ts2->kind = kind; | ||
40 | } else { | ||
41 | ts->base_type = type; | ||
42 | @@ -XXX,XX +XXX,XX @@ TCGTemp *tcg_constant_internal(TCGType type, int64_t val) | ||
43 | ts2->type = TCG_TYPE_I32; | ||
44 | ts2->kind = TEMP_CONST; | ||
45 | ts2->temp_allocated = 1; | ||
46 | + ts2->temp_subindex = 1; | ||
47 | ts2->val = val >> 32; | ||
48 | } else { | ||
49 | ts->base_type = type; | ||
50 | -- | ||
51 | 2.34.1 | ||
52 | |||
53 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The first thing that temp_sync does is check mem_coherent, | ||
2 | so there's no need for the caller to do so. | ||
1 | 3 | ||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | --- | ||
7 | tcg/tcg.c | 8 ++------ | ||
8 | 1 file changed, 2 insertions(+), 6 deletions(-) | ||
9 | |||
10 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/tcg/tcg.c | ||
13 | +++ b/tcg/tcg.c | ||
14 | @@ -XXX,XX +XXX,XX @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) | ||
15 | |||
16 | /* If the two inputs form one 64-bit value, try dupm_vec. */ | ||
17 | if (itsl + 1 == itsh && itsl->base_type == TCG_TYPE_I64) { | ||
18 | - if (!itsl->mem_coherent) { | ||
19 | - temp_sync(s, itsl, s->reserved_regs, 0, 0); | ||
20 | - } | ||
21 | - if (!itsh->mem_coherent) { | ||
22 | - temp_sync(s, itsh, s->reserved_regs, 0, 0); | ||
23 | - } | ||
24 | + temp_sync(s, itsl, s->reserved_regs, 0, 0); | ||
25 | + temp_sync(s, itsh, s->reserved_regs, 0, 0); | ||
26 | #if HOST_BIG_ENDIAN | ||
27 | TCGTemp *its = itsh; | ||
28 | #else | ||
29 | -- | ||
30 | 2.34.1 | ||
31 | |||
32 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Allocate the first of a pair at the lower address, and the | ||
2 | second of a pair at the higher address. This will make it | ||
3 | easier to find the beginning of the larger memory block. | ||
1 | 4 | ||
5 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | --- | ||
8 | tcg/tcg-internal.h | 4 ++-- | ||
9 | tcg/tcg.c | 58 ++++++++++++++++++++++------------------------ | ||
10 | 2 files changed, 30 insertions(+), 32 deletions(-) | ||
11 | |||
12 | diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/tcg/tcg-internal.h | ||
15 | +++ b/tcg/tcg-internal.h | ||
16 | @@ -XXX,XX +XXX,XX @@ static inline unsigned tcg_call_flags(TCGOp *op) | ||
17 | #if TCG_TARGET_REG_BITS == 32 | ||
18 | static inline TCGv_i32 TCGV_LOW(TCGv_i64 t) | ||
19 | { | ||
20 | - return temp_tcgv_i32(tcgv_i64_temp(t)); | ||
21 | + return temp_tcgv_i32(tcgv_i64_temp(t) + HOST_BIG_ENDIAN); | ||
22 | } | ||
23 | static inline TCGv_i32 TCGV_HIGH(TCGv_i64 t) | ||
24 | { | ||
25 | - return temp_tcgv_i32(tcgv_i64_temp(t) + 1); | ||
26 | + return temp_tcgv_i32(tcgv_i64_temp(t) + !HOST_BIG_ENDIAN); | ||
27 | } | ||
28 | #else | ||
29 | extern TCGv_i32 TCGV_LOW(TCGv_i64) QEMU_ERROR("32-bit code path is reachable"); | ||
30 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/tcg/tcg.c | ||
33 | +++ b/tcg/tcg.c | ||
34 | @@ -XXX,XX +XXX,XX @@ TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, | ||
35 | TCGContext *s = tcg_ctx; | ||
36 | TCGTemp *base_ts = tcgv_ptr_temp(base); | ||
37 | TCGTemp *ts = tcg_global_alloc(s); | ||
38 | - int indirect_reg = 0, bigendian = 0; | ||
39 | -#if HOST_BIG_ENDIAN | ||
40 | - bigendian = 1; | ||
41 | -#endif | ||
42 | + int indirect_reg = 0; | ||
43 | |||
44 | switch (base_ts->kind) { | ||
45 | case TEMP_FIXED: | ||
46 | @@ -XXX,XX +XXX,XX @@ TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, | ||
47 | ts->indirect_reg = indirect_reg; | ||
48 | ts->mem_allocated = 1; | ||
49 | ts->mem_base = base_ts; | ||
50 | - ts->mem_offset = offset + bigendian * 4; | ||
51 | + ts->mem_offset = offset; | ||
52 | pstrcpy(buf, sizeof(buf), name); | ||
53 | pstrcat(buf, sizeof(buf), "_0"); | ||
54 | ts->name = strdup(buf); | ||
55 | @@ -XXX,XX +XXX,XX @@ TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, | ||
56 | ts2->indirect_reg = indirect_reg; | ||
57 | ts2->mem_allocated = 1; | ||
58 | ts2->mem_base = base_ts; | ||
59 | - ts2->mem_offset = offset + (1 - bigendian) * 4; | ||
60 | + ts2->mem_offset = offset + 4; | ||
61 | ts2->temp_subindex = 1; | ||
62 | pstrcpy(buf, sizeof(buf), name); | ||
63 | pstrcat(buf, sizeof(buf), "_1"); | ||
64 | @@ -XXX,XX +XXX,XX @@ TCGTemp *tcg_constant_internal(TCGType type, int64_t val) | ||
65 | |||
66 | ts = g_hash_table_lookup(h, &val); | ||
67 | if (ts == NULL) { | ||
68 | + int64_t *val_ptr; | ||
69 | + | ||
70 | ts = tcg_temp_alloc(s); | ||
71 | |||
72 | if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { | ||
73 | TCGTemp *ts2 = tcg_temp_alloc(s); | ||
74 | |||
75 | + tcg_debug_assert(ts2 == ts + 1); | ||
76 | + | ||
77 | ts->base_type = TCG_TYPE_I64; | ||
78 | ts->type = TCG_TYPE_I32; | ||
79 | ts->kind = TEMP_CONST; | ||
80 | ts->temp_allocated = 1; | ||
81 | - /* | ||
82 | - * Retain the full value of the 64-bit constant in the low | ||
83 | - * part, so that the hash table works. Actual uses will | ||
84 | - * truncate the value to the low part. | ||
85 | - */ | ||
86 | - ts->val = val; | ||
87 | |||
88 | - tcg_debug_assert(ts2 == ts + 1); | ||
89 | ts2->base_type = TCG_TYPE_I64; | ||
90 | ts2->type = TCG_TYPE_I32; | ||
91 | ts2->kind = TEMP_CONST; | ||
92 | ts2->temp_allocated = 1; | ||
93 | ts2->temp_subindex = 1; | ||
94 | - ts2->val = val >> 32; | ||
95 | + | ||
96 | + /* | ||
97 | + * Retain the full value of the 64-bit constant in the low | ||
98 | + * part, so that the hash table works. Actual uses will | ||
99 | + * truncate the value to the low part. | ||
100 | + */ | ||
101 | + ts[HOST_BIG_ENDIAN].val = val; | ||
102 | + ts[!HOST_BIG_ENDIAN].val = val >> 32; | ||
103 | + val_ptr = &ts[HOST_BIG_ENDIAN].val; | ||
104 | } else { | ||
105 | ts->base_type = type; | ||
106 | ts->type = type; | ||
107 | ts->kind = TEMP_CONST; | ||
108 | ts->temp_allocated = 1; | ||
109 | ts->val = val; | ||
110 | + val_ptr = &ts->val; | ||
111 | } | ||
112 | - g_hash_table_insert(h, &ts->val, ts); | ||
113 | + g_hash_table_insert(h, val_ptr, ts); | ||
114 | } | ||
115 | |||
116 | return ts; | ||
117 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
118 | pi = 0; | ||
119 | if (ret != NULL) { | ||
120 | if (TCG_TARGET_REG_BITS < 64 && (typemask & 6) == dh_typecode_i64) { | ||
121 | -#if HOST_BIG_ENDIAN | ||
122 | - op->args[pi++] = temp_arg(ret + 1); | ||
123 | - op->args[pi++] = temp_arg(ret); | ||
124 | -#else | ||
125 | op->args[pi++] = temp_arg(ret); | ||
126 | op->args[pi++] = temp_arg(ret + 1); | ||
127 | -#endif | ||
128 | nb_rets = 2; | ||
129 | } else { | ||
130 | op->args[pi++] = temp_arg(ret); | ||
131 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
132 | } | ||
133 | |||
134 | if (TCG_TARGET_REG_BITS < 64 && is_64bit) { | ||
135 | - op->args[pi++] = temp_arg(args[i] + HOST_BIG_ENDIAN); | ||
136 | - op->args[pi++] = temp_arg(args[i] + !HOST_BIG_ENDIAN); | ||
137 | + op->args[pi++] = temp_arg(args[i]); | ||
138 | + op->args[pi++] = temp_arg(args[i] + 1); | ||
139 | real_args += 2; | ||
140 | continue; | ||
141 | } | ||
142 | @@ -XXX,XX +XXX,XX @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) | ||
143 | } | ||
144 | |||
145 | /* If the two inputs form one 64-bit value, try dupm_vec. */ | ||
146 | - if (itsl + 1 == itsh && itsl->base_type == TCG_TYPE_I64) { | ||
147 | - temp_sync(s, itsl, s->reserved_regs, 0, 0); | ||
148 | - temp_sync(s, itsh, s->reserved_regs, 0, 0); | ||
149 | -#if HOST_BIG_ENDIAN | ||
150 | - TCGTemp *its = itsh; | ||
151 | -#else | ||
152 | - TCGTemp *its = itsl; | ||
153 | -#endif | ||
154 | + if (itsl->temp_subindex == HOST_BIG_ENDIAN && | ||
155 | + itsh->temp_subindex == !HOST_BIG_ENDIAN && | ||
156 | + itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) { | ||
157 | + TCGTemp *its = itsl - HOST_BIG_ENDIAN; | ||
158 | + | ||
159 | + temp_sync(s, its + 0, s->reserved_regs, 0, 0); | ||
160 | + temp_sync(s, its + 1, s->reserved_regs, 0, 0); | ||
161 | + | ||
162 | if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg, | ||
163 | its->mem_base->reg, its->mem_offset)) { | ||
164 | goto done; | ||
165 | -- | ||
166 | 2.34.1 | ||
167 | |||
168 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The count is not itself an enumerator. Move it outside to | ||
2 | prevent the compiler from considering it with -Wswitch-enum. | ||
1 | 3 | ||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | --- | ||
7 | include/tcg/tcg.h | 3 ++- | ||
8 | 1 file changed, 2 insertions(+), 1 deletion(-) | ||
9 | |||
10 | diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/include/tcg/tcg.h | ||
13 | +++ b/include/tcg/tcg.h | ||
14 | @@ -XXX,XX +XXX,XX @@ typedef enum TCGType { | ||
15 | TCG_TYPE_V128, | ||
16 | TCG_TYPE_V256, | ||
17 | |||
18 | - TCG_TYPE_COUNT, /* number of different types */ | ||
19 | + /* Number of different types (integer not enum) */ | ||
20 | +#define TCG_TYPE_COUNT (TCG_TYPE_V256 + 1) | ||
21 | |||
22 | /* An alias for the size of the host register. */ | ||
23 | #if TCG_TARGET_REG_BITS == 32 | ||
24 | -- | ||
25 | 2.34.1 | ||
26 | |||
27 | diff view generated by jsdifflib |
1 | These are identical to the 'r' constraint. | 1 | Add a helper function for computing the size of a type. |
---|---|---|---|
2 | 2 | ||
3 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
4 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
5 | --- | 5 | --- |
6 | tcg/tci/tcg-target.c.inc | 10 ++++------ | 6 | include/tcg/tcg.h | 16 ++++++++++++++++ |
7 | 1 file changed, 4 insertions(+), 6 deletions(-) | 7 | tcg/tcg.c | 27 ++++++++++++--------------- |
8 | 2 files changed, 28 insertions(+), 15 deletions(-) | ||
8 | 9 | ||
9 | diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc | 10 | diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h |
10 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
11 | --- a/tcg/tci/tcg-target.c.inc | 12 | --- a/include/tcg/tcg.h |
12 | +++ b/tcg/tci/tcg-target.c.inc | 13 | +++ b/include/tcg/tcg.h |
13 | @@ -XXX,XX +XXX,XX @@ | 14 | @@ -XXX,XX +XXX,XX @@ typedef enum TCGType { |
14 | # define R64 "r" | ||
15 | #endif | 15 | #endif |
16 | #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS | 16 | } TCGType; |
17 | -# define L "L", "L" | 17 | |
18 | -# define S "S", "S" | 18 | +/** |
19 | +# define L "r", "r" | 19 | + * tcg_type_size |
20 | +# define S "r", "r" | 20 | + * @t: type |
21 | #else | 21 | + * |
22 | -# define L "L" | 22 | + * Return the size of the type in bytes. |
23 | -# define S "S" | 23 | + */ |
24 | +# define L "r" | 24 | +static inline int tcg_type_size(TCGType t) |
25 | +# define S "r" | 25 | +{ |
26 | #endif | 26 | + unsigned i = t; |
27 | 27 | + if (i >= TCG_TYPE_V64) { | |
28 | /* TODO: documentation. */ | 28 | + tcg_debug_assert(i < TCG_TYPE_COUNT); |
29 | @@ -XXX,XX +XXX,XX @@ static const char *target_parse_constraint(TCGArgConstraint *ct, | 29 | + i -= TCG_TYPE_V64 - 1; |
30 | + } | ||
31 | + return 4 << i; | ||
32 | +} | ||
33 | + | ||
34 | /** | ||
35 | * get_alignment_bits | ||
36 | * @memop: MemOp value | ||
37 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/tcg/tcg.c | ||
40 | +++ b/tcg/tcg.c | ||
41 | @@ -XXX,XX +XXX,XX @@ static bool liveness_pass_2(TCGContext *s) | ||
42 | |||
43 | static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) | ||
30 | { | 44 | { |
31 | switch (*ct_str++) { | 45 | - intptr_t off, size, align; |
32 | case 'r': | 46 | + int size = tcg_type_size(ts->type); |
33 | - case 'L': /* qemu_ld constraint */ | 47 | + int align; |
34 | - case 'S': /* qemu_st constraint */ | 48 | + intptr_t off; |
35 | ct->regs = BIT(TCG_TARGET_NB_REGS) - 1; | 49 | |
50 | switch (ts->type) { | ||
51 | case TCG_TYPE_I32: | ||
52 | - size = align = 4; | ||
53 | + align = 4; | ||
54 | break; | ||
55 | case TCG_TYPE_I64: | ||
56 | case TCG_TYPE_V64: | ||
57 | - size = align = 8; | ||
58 | + align = 8; | ||
59 | break; | ||
60 | case TCG_TYPE_V128: | ||
61 | - size = align = 16; | ||
62 | - break; | ||
63 | case TCG_TYPE_V256: | ||
64 | /* Note that we do not require aligned storage for V256. */ | ||
65 | - size = 32, align = 16; | ||
66 | + align = 16; | ||
36 | break; | 67 | break; |
37 | default: | 68 | default: |
69 | g_assert_not_reached(); | ||
70 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) | ||
71 | TCGRegSet dup_out_regs, dup_in_regs; | ||
72 | TCGTemp *its, *ots; | ||
73 | TCGType itype, vtype; | ||
74 | - intptr_t endian_fixup; | ||
75 | unsigned vece; | ||
76 | + int lowpart_ofs; | ||
77 | bool ok; | ||
78 | |||
79 | ots = arg_temp(op->args[0]); | ||
80 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) | ||
81 | /* fall through */ | ||
82 | |||
83 | case TEMP_VAL_MEM: | ||
84 | -#if HOST_BIG_ENDIAN | ||
85 | - endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8; | ||
86 | - endian_fixup -= 1 << vece; | ||
87 | -#else | ||
88 | - endian_fixup = 0; | ||
89 | -#endif | ||
90 | - /* Attempt to dup directly from the input memory slot. */ | ||
91 | + lowpart_ofs = 0; | ||
92 | + if (HOST_BIG_ENDIAN) { | ||
93 | + lowpart_ofs = tcg_type_size(itype) - (1 << vece); | ||
94 | + } | ||
95 | if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, | ||
96 | - its->mem_offset + endian_fixup)) { | ||
97 | + its->mem_offset + lowpart_ofs)) { | ||
98 | goto done; | ||
99 | } | ||
100 | /* Load the input into the destination vector register. */ | ||
38 | -- | 101 | -- |
39 | 2.25.1 | 102 | 2.34.1 |
40 | 103 | ||
41 | 104 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Prepare to replace a bunch of separate ifdefs with a | ||
2 | consistent way to describe the ABI of a function call. | ||
1 | 3 | ||
4 | Reviewed-by: Alex Bennée <alex.bennee@linaro.org> | ||
5 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | --- | ||
8 | tcg/tcg-internal.h | 15 +++++++++++++++ | ||
9 | 1 file changed, 15 insertions(+) | ||
10 | |||
11 | diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/tcg/tcg-internal.h | ||
14 | +++ b/tcg/tcg-internal.h | ||
15 | @@ -XXX,XX +XXX,XX @@ | ||
16 | |||
17 | #define TCG_HIGHWATER 1024 | ||
18 | |||
19 | +/* | ||
20 | + * Describe the calling convention of a given argument type. | ||
21 | + */ | ||
22 | +typedef enum { | ||
23 | + TCG_CALL_RET_NORMAL, /* by registers */ | ||
24 | +} TCGCallReturnKind; | ||
25 | + | ||
26 | +typedef enum { | ||
27 | + TCG_CALL_ARG_NORMAL, /* by registers (continuing onto stack) */ | ||
28 | + TCG_CALL_ARG_EVEN, /* like normal, but skipping odd slots */ | ||
29 | + TCG_CALL_ARG_EXTEND, /* for i32, as a sign/zero-extended i64 */ | ||
30 | + TCG_CALL_ARG_EXTEND_U, /* ... as a zero-extended i64 */ | ||
31 | + TCG_CALL_ARG_EXTEND_S, /* ... as a sign-extended i64 */ | ||
32 | +} TCGCallArgumentKind; | ||
33 | + | ||
34 | typedef struct TCGHelperInfo { | ||
35 | void *func; | ||
36 | const char *name; | ||
37 | -- | ||
38 | 2.34.1 | ||
39 | |||
40 | diff view generated by jsdifflib |
1 | All backends have now been converted to tcg-target-con-set.h, | 1 | For 32-bit hosts when TCG_TARGET_CALL_ALIGN_ARGS was set, use |
---|---|---|---|
2 | so we can remove the fallback code. | 2 | TCG_CALL_ARG_EVEN. For 64-bit hosts, TCG_TARGET_CALL_ALIGN_ARGS |
3 | 3 | was silently ignored, so always use TCG_CALL_ARG_NORMAL. | |
4 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 4 | |
5 | Reviewed-by: Alistair Francis <alistair.francis@wdc.com> | 5 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
7 | --- | 7 | --- |
8 | tcg/aarch64/tcg-target.h | 1 - | 8 | tcg/aarch64/tcg-target.h | 2 +- |
9 | tcg/arm/tcg-target.h | 1 - | 9 | tcg/arm/tcg-target.h | 2 +- |
10 | tcg/i386/tcg-target.h | 1 - | 10 | tcg/i386/tcg-target.h | 1 + |
11 | tcg/mips/tcg-target.h | 1 - | 11 | tcg/loongarch64/tcg-target.h | 2 +- |
12 | tcg/ppc/tcg-target.h | 1 - | 12 | tcg/mips/tcg-target.h | 3 ++- |
13 | tcg/riscv/tcg-target.h | 1 - | 13 | tcg/riscv/tcg-target.h | 6 +++++- |
14 | tcg/s390/tcg-target.h | 1 - | 14 | tcg/s390x/tcg-target.h | 1 + |
15 | tcg/sparc/tcg-target.h | 1 - | 15 | tcg/sparc64/tcg-target.h | 1 + |
16 | tcg/tci/tcg-target.h | 2 -- | 16 | tcg/tci/tcg-target.h | 5 +++++ |
17 | tcg/tcg.c | 12 ------------ | 17 | tcg/tcg.c | 6 ++++-- |
18 | 10 files changed, 22 deletions(-) | 18 | tcg/ppc/tcg-target.c.inc | 21 ++++++++------------- |
19 | 11 files changed, 30 insertions(+), 20 deletions(-) | ||
19 | 20 | ||
20 | diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h | 21 | diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h |
21 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/tcg/aarch64/tcg-target.h | 23 | --- a/tcg/aarch64/tcg-target.h |
23 | +++ b/tcg/aarch64/tcg-target.h | 24 | +++ b/tcg/aarch64/tcg-target.h |
24 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 25 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
25 | #define TCG_TARGET_NEED_LDST_LABELS | 26 | /* used for function call generation */ |
26 | #endif | 27 | #define TCG_REG_CALL_STACK TCG_REG_SP |
27 | #define TCG_TARGET_NEED_POOL_LABELS | 28 | #define TCG_TARGET_STACK_ALIGN 16 |
28 | -#define TCG_TARGET_CON_SET_H | 29 | -#define TCG_TARGET_CALL_ALIGN_ARGS 1 |
29 | 30 | #define TCG_TARGET_CALL_STACK_OFFSET 0 | |
30 | #endif /* AARCH64_TCG_TARGET_H */ | 31 | +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL |
32 | |||
33 | /* optional instructions */ | ||
34 | #define TCG_TARGET_HAS_div_i32 1 | ||
31 | diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h | 35 | diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h |
32 | index XXXXXXX..XXXXXXX 100644 | 36 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/tcg/arm/tcg-target.h | 37 | --- a/tcg/arm/tcg-target.h |
34 | +++ b/tcg/arm/tcg-target.h | 38 | +++ b/tcg/arm/tcg-target.h |
35 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 39 | @@ -XXX,XX +XXX,XX @@ extern bool use_neon_instructions; |
36 | #define TCG_TARGET_NEED_LDST_LABELS | 40 | |
37 | #endif | 41 | /* used for function call generation */ |
38 | #define TCG_TARGET_NEED_POOL_LABELS | 42 | #define TCG_TARGET_STACK_ALIGN 8 |
39 | -#define TCG_TARGET_CON_SET_H | 43 | -#define TCG_TARGET_CALL_ALIGN_ARGS 1 |
40 | 44 | #define TCG_TARGET_CALL_STACK_OFFSET 0 | |
41 | #endif | 45 | +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN |
46 | |||
47 | /* optional instructions */ | ||
48 | #define TCG_TARGET_HAS_ext8s_i32 1 | ||
42 | diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h | 49 | diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h |
43 | index XXXXXXX..XXXXXXX 100644 | 50 | index XXXXXXX..XXXXXXX 100644 |
44 | --- a/tcg/i386/tcg-target.h | 51 | --- a/tcg/i386/tcg-target.h |
45 | +++ b/tcg/i386/tcg-target.h | 52 | +++ b/tcg/i386/tcg-target.h |
46 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | 53 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
47 | #define TCG_TARGET_NEED_LDST_LABELS | 54 | #else |
48 | #endif | 55 | #define TCG_TARGET_CALL_STACK_OFFSET 0 |
49 | #define TCG_TARGET_NEED_POOL_LABELS | 56 | #endif |
50 | -#define TCG_TARGET_CON_SET_H | 57 | +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL |
51 | 58 | ||
52 | #endif | 59 | extern bool have_bmi1; |
60 | extern bool have_popcnt; | ||
61 | diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h | ||
62 | index XXXXXXX..XXXXXXX 100644 | ||
63 | --- a/tcg/loongarch64/tcg-target.h | ||
64 | +++ b/tcg/loongarch64/tcg-target.h | ||
65 | @@ -XXX,XX +XXX,XX @@ typedef enum { | ||
66 | /* used for function call generation */ | ||
67 | #define TCG_REG_CALL_STACK TCG_REG_SP | ||
68 | #define TCG_TARGET_STACK_ALIGN 16 | ||
69 | -#define TCG_TARGET_CALL_ALIGN_ARGS 1 | ||
70 | #define TCG_TARGET_CALL_STACK_OFFSET 0 | ||
71 | +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL | ||
72 | |||
73 | /* optional instructions */ | ||
74 | #define TCG_TARGET_HAS_movcond_i32 0 | ||
53 | diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h | 75 | diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h |
54 | index XXXXXXX..XXXXXXX 100644 | 76 | index XXXXXXX..XXXXXXX 100644 |
55 | --- a/tcg/mips/tcg-target.h | 77 | --- a/tcg/mips/tcg-target.h |
56 | +++ b/tcg/mips/tcg-target.h | 78 | +++ b/tcg/mips/tcg-target.h |
57 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 79 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
58 | #ifdef CONFIG_SOFTMMU | 80 | #define TCG_TARGET_STACK_ALIGN 16 |
59 | #define TCG_TARGET_NEED_LDST_LABELS | 81 | #if _MIPS_SIM == _ABIO32 |
60 | #endif | 82 | # define TCG_TARGET_CALL_STACK_OFFSET 16 |
61 | -#define TCG_TARGET_CON_SET_H | 83 | +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN |
62 | 84 | #else | |
63 | #endif | 85 | # define TCG_TARGET_CALL_STACK_OFFSET 0 |
64 | diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h | 86 | +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL |
65 | index XXXXXXX..XXXXXXX 100644 | 87 | #endif |
66 | --- a/tcg/ppc/tcg-target.h | 88 | -#define TCG_TARGET_CALL_ALIGN_ARGS 1 |
67 | +++ b/tcg/ppc/tcg-target.h | 89 | |
68 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 90 | /* MOVN/MOVZ instructions detection */ |
69 | #define TCG_TARGET_NEED_LDST_LABELS | 91 | #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 1)) || \ |
70 | #endif | ||
71 | #define TCG_TARGET_NEED_POOL_LABELS | ||
72 | -#define TCG_TARGET_CON_SET_H | ||
73 | |||
74 | #endif | ||
75 | diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h | 92 | diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h |
76 | index XXXXXXX..XXXXXXX 100644 | 93 | index XXXXXXX..XXXXXXX 100644 |
77 | --- a/tcg/riscv/tcg-target.h | 94 | --- a/tcg/riscv/tcg-target.h |
78 | +++ b/tcg/riscv/tcg-target.h | 95 | +++ b/tcg/riscv/tcg-target.h |
79 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 96 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
80 | #define TCG_TARGET_NEED_POOL_LABELS | 97 | /* used for function call generation */ |
81 | 98 | #define TCG_REG_CALL_STACK TCG_REG_SP | |
82 | #define TCG_TARGET_HAS_MEMORY_BSWAP 0 | 99 | #define TCG_TARGET_STACK_ALIGN 16 |
83 | -#define TCG_TARGET_CON_SET_H | 100 | -#define TCG_TARGET_CALL_ALIGN_ARGS 1 |
84 | 101 | #define TCG_TARGET_CALL_STACK_OFFSET 0 | |
85 | #endif | 102 | +#if TCG_TARGET_REG_BITS == 32 |
86 | diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h | 103 | +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN |
87 | index XXXXXXX..XXXXXXX 100644 | 104 | +#else |
88 | --- a/tcg/s390/tcg-target.h | 105 | +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL |
89 | +++ b/tcg/s390/tcg-target.h | 106 | +#endif |
90 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | 107 | |
91 | #define TCG_TARGET_NEED_LDST_LABELS | 108 | /* optional instructions */ |
92 | #endif | 109 | #define TCG_TARGET_HAS_movcond_i32 0 |
93 | #define TCG_TARGET_NEED_POOL_LABELS | 110 | diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h |
94 | -#define TCG_TARGET_CON_SET_H | 111 | index XXXXXXX..XXXXXXX 100644 |
95 | 112 | --- a/tcg/s390x/tcg-target.h | |
96 | #endif | 113 | +++ b/tcg/s390x/tcg-target.h |
97 | diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h | 114 | @@ -XXX,XX +XXX,XX @@ extern uint64_t s390_facilities[3]; |
98 | index XXXXXXX..XXXXXXX 100644 | 115 | /* used for function call generation */ |
99 | --- a/tcg/sparc/tcg-target.h | 116 | #define TCG_TARGET_STACK_ALIGN 8 |
100 | +++ b/tcg/sparc/tcg-target.h | 117 | #define TCG_TARGET_CALL_STACK_OFFSET 160 |
101 | @@ -XXX,XX +XXX,XX @@ extern bool use_vis3_instructions; | 118 | +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL |
102 | void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 119 | |
103 | 120 | #define TCG_TARGET_EXTEND_ARGS 1 | |
104 | #define TCG_TARGET_NEED_POOL_LABELS | 121 | #define TCG_TARGET_HAS_MEMORY_BSWAP 1 |
105 | -#define TCG_TARGET_CON_SET_H | 122 | diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h |
106 | 123 | index XXXXXXX..XXXXXXX 100644 | |
107 | #endif | 124 | --- a/tcg/sparc64/tcg-target.h |
125 | +++ b/tcg/sparc64/tcg-target.h | ||
126 | @@ -XXX,XX +XXX,XX @@ typedef enum { | ||
127 | #define TCG_TARGET_STACK_ALIGN 16 | ||
128 | #define TCG_TARGET_CALL_STACK_OFFSET (128 + 6*8 + TCG_TARGET_STACK_BIAS) | ||
129 | #define TCG_TARGET_EXTEND_ARGS 1 | ||
130 | +#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL | ||
131 | |||
132 | #if defined(__VIS__) && __VIS__ >= 0x300 | ||
133 | #define use_vis3_instructions 1 | ||
108 | diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h | 134 | diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h |
109 | index XXXXXXX..XXXXXXX 100644 | 135 | index XXXXXXX..XXXXXXX 100644 |
110 | --- a/tcg/tci/tcg-target.h | 136 | --- a/tcg/tci/tcg-target.h |
111 | +++ b/tcg/tci/tcg-target.h | 137 | +++ b/tcg/tci/tcg-target.h |
112 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | 138 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
113 | /* no need to flush icache explicitly */ | 139 | /* Used for function call generation. */ |
114 | } | 140 | #define TCG_TARGET_CALL_STACK_OFFSET 0 |
115 | 141 | #define TCG_TARGET_STACK_ALIGN 8 | |
116 | -#define TCG_TARGET_CON_SET_H | 142 | +#if TCG_TARGET_REG_BITS == 32 |
117 | - | 143 | +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN |
118 | #endif /* TCG_TARGET_H */ | 144 | +#else |
145 | +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL | ||
146 | +#endif | ||
147 | |||
148 | #define HAVE_TCG_QEMU_TB_EXEC | ||
149 | #define TCG_TARGET_NEED_POOL_LABELS | ||
119 | diff --git a/tcg/tcg.c b/tcg/tcg.c | 150 | diff --git a/tcg/tcg.c b/tcg/tcg.c |
120 | index XXXXXXX..XXXXXXX 100644 | 151 | index XXXXXXX..XXXXXXX 100644 |
121 | --- a/tcg/tcg.c | 152 | --- a/tcg/tcg.c |
122 | +++ b/tcg/tcg.c | 153 | +++ b/tcg/tcg.c |
154 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
155 | * for passing off to ffi_call. | ||
156 | */ | ||
157 | want_align = true; | ||
158 | -#elif defined(TCG_TARGET_CALL_ALIGN_ARGS) | ||
159 | +#else | ||
160 | /* Some targets want aligned 64 bit args */ | ||
161 | - want_align = is_64bit; | ||
162 | + if (is_64bit) { | ||
163 | + want_align = TCG_TARGET_CALL_ARG_I64 == TCG_CALL_ARG_EVEN; | ||
164 | + } | ||
165 | #endif | ||
166 | |||
167 | if (TCG_TARGET_REG_BITS < 64 && want_align && (real_args & 1)) { | ||
168 | diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc | ||
169 | index XXXXXXX..XXXXXXX 100644 | ||
170 | --- a/tcg/ppc/tcg-target.c.inc | ||
171 | +++ b/tcg/ppc/tcg-target.c.inc | ||
123 | @@ -XXX,XX +XXX,XX @@ | 172 | @@ -XXX,XX +XXX,XX @@ |
124 | /* Forward declarations for functions declared in tcg-target.c.inc and | 173 | #endif |
125 | used here. */ | 174 | |
126 | static void tcg_target_init(TCGContext *s); | 175 | #ifdef _CALL_SYSV |
127 | -#ifndef TCG_TARGET_CON_SET_H | 176 | -# define TCG_TARGET_CALL_ALIGN_ARGS 1 |
128 | -static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode); | 177 | +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN |
129 | -#endif | 178 | +#else |
130 | static void tcg_target_qemu_prologue(TCGContext *s); | 179 | +# define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL |
131 | static bool patch_reloc(tcg_insn_unit *code_ptr, int type, | 180 | #endif |
132 | intptr_t value, intptr_t addend); | 181 | |
133 | @@ -XXX,XX +XXX,XX @@ static void set_jmp_reset_offset(TCGContext *s, int which) | 182 | /* For some memory operations, we need a scratch that isn't R0. For the AIX |
134 | s->tb_jmp_reset_offset[which] = tcg_current_code_size(s); | 183 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) |
135 | } | 184 | lo = lb->addrlo_reg; |
136 | 185 | hi = lb->addrhi_reg; | |
137 | -#ifdef TCG_TARGET_CON_SET_H | 186 | if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { |
138 | #define C_PFX1(P, A) P##A | 187 | -#ifdef TCG_TARGET_CALL_ALIGN_ARGS |
139 | #define C_PFX2(P, A, B) P##A##_##B | 188 | - arg |= 1; |
140 | #define C_PFX3(P, A, B, C) P##A##_##B##_##C | 189 | -#endif |
141 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef constraint_sets[] = { | 190 | + arg |= (TCG_TARGET_CALL_ARG_I64 == TCG_CALL_ARG_EVEN); |
142 | #define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3) | 191 | tcg_out_mov(s, TCG_TYPE_I32, arg++, hi); |
143 | #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) | 192 | tcg_out_mov(s, TCG_TYPE_I32, arg++, lo); |
144 | 193 | } else { | |
145 | -#endif /* TCG_TARGET_CON_SET_H */ | 194 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) |
146 | - | 195 | lo = lb->addrlo_reg; |
147 | #include "tcg-target.c.inc" | 196 | hi = lb->addrhi_reg; |
148 | 197 | if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { | |
149 | /* compare a pointer @ptr and a tb_tc @s */ | 198 | -#ifdef TCG_TARGET_CALL_ALIGN_ARGS |
150 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | 199 | - arg |= 1; |
151 | continue; | 200 | -#endif |
152 | } | 201 | + arg |= (TCG_TARGET_CALL_ARG_I64 == TCG_CALL_ARG_EVEN); |
153 | 202 | tcg_out_mov(s, TCG_TYPE_I32, arg++, hi); | |
154 | -#ifdef TCG_TARGET_CON_SET_H | 203 | tcg_out_mov(s, TCG_TYPE_I32, arg++, lo); |
155 | /* | 204 | } else { |
156 | * Macro magic should make it impossible, but double-check that | 205 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) |
157 | * the array index is in range. Since the signness of an enum | 206 | if (TCG_TARGET_REG_BITS == 32) { |
158 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | 207 | switch (s_bits) { |
159 | unsigned con_set = tcg_target_op_def(op); | 208 | case MO_64: |
160 | tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); | 209 | -#ifdef TCG_TARGET_CALL_ALIGN_ARGS |
161 | tdefs = &constraint_sets[con_set]; | 210 | - arg |= 1; |
162 | -#else | 211 | -#endif |
163 | - tdefs = tcg_target_op_def(op); | 212 | + arg |= (TCG_TARGET_CALL_ARG_I64 == TCG_CALL_ARG_EVEN); |
164 | - /* Missing TCGTargetOpDef entry. */ | 213 | tcg_out_mov(s, TCG_TYPE_I32, arg++, hi); |
165 | - tcg_debug_assert(tdefs != NULL); | 214 | /* FALLTHRU */ |
166 | -#endif | 215 | case MO_32: |
167 | 216 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l) | |
168 | for (i = 0; i < nb_args; i++) { | 217 | |
169 | const char *ct_str = tdefs->args_ct_str[i]; | 218 | if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { |
219 | TCGReg arg = TCG_REG_R4; | ||
220 | -#ifdef TCG_TARGET_CALL_ALIGN_ARGS | ||
221 | - arg |= 1; | ||
222 | -#endif | ||
223 | + | ||
224 | + arg |= (TCG_TARGET_CALL_ARG_I64 == TCG_CALL_ARG_EVEN); | ||
225 | if (l->addrlo_reg != arg) { | ||
226 | tcg_out_mov(s, TCG_TYPE_I32, arg, l->addrhi_reg); | ||
227 | tcg_out_mov(s, TCG_TYPE_I32, arg + 1, l->addrlo_reg); | ||
170 | -- | 228 | -- |
171 | 2.25.1 | 229 | 2.34.1 |
172 | 230 | ||
173 | 231 | diff view generated by jsdifflib |
1 | All backends have now been converted to tcg-target-con-str.h, | 1 | For 64-bit hosts that had TCG_TARGET_EXTEND_ARGS, set |
---|---|---|---|
2 | so we can remove the fallback code. | 2 | TCG_TARGET_CALL_ARG_I32 to TCG_CALL_ARG_EXTEND. |
3 | 3 | Otherwise, use TCG_CALL_ARG_NORMAL. | |
4 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 4 | |
5 | Reviewed-by: Alistair Francis <alistair.francis@wdc.com> | 5 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
7 | --- | 7 | --- |
8 | tcg/aarch64/tcg-target.h | 1 - | 8 | tcg/aarch64/tcg-target.h | 1 + |
9 | tcg/arm/tcg-target.h | 1 - | 9 | tcg/arm/tcg-target.h | 1 + |
10 | tcg/i386/tcg-target.h | 1 - | 10 | tcg/i386/tcg-target.h | 1 + |
11 | tcg/mips/tcg-target.h | 1 - | 11 | tcg/loongarch64/tcg-target.h | 1 + |
12 | tcg/ppc/tcg-target.h | 1 - | 12 | tcg/mips/tcg-target.h | 1 + |
13 | tcg/riscv/tcg-target.h | 1 - | 13 | tcg/riscv/tcg-target.h | 1 + |
14 | tcg/s390/tcg-target.h | 1 - | 14 | tcg/s390x/tcg-target.h | 2 +- |
15 | tcg/sparc/tcg-target.h | 1 - | 15 | tcg/sparc64/tcg-target.h | 2 +- |
16 | tcg/tci/tcg-target.h | 2 -- | 16 | tcg/tci/tcg-target.h | 1 + |
17 | tcg/tcg.c | 16 ---------------- | 17 | tcg/tcg.c | 42 ++++++++++++++++++------------------ |
18 | 10 files changed, 26 deletions(-) | 18 | tcg/ppc/tcg-target.c.inc | 6 +++++- |
19 | 11 files changed, 35 insertions(+), 24 deletions(-) | ||
19 | 20 | ||
20 | diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h | 21 | diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h |
21 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/tcg/aarch64/tcg-target.h | 23 | --- a/tcg/aarch64/tcg-target.h |
23 | +++ b/tcg/aarch64/tcg-target.h | 24 | +++ b/tcg/aarch64/tcg-target.h |
24 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 25 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
25 | #define TCG_TARGET_NEED_LDST_LABELS | 26 | #define TCG_REG_CALL_STACK TCG_REG_SP |
26 | #endif | 27 | #define TCG_TARGET_STACK_ALIGN 16 |
27 | #define TCG_TARGET_NEED_POOL_LABELS | 28 | #define TCG_TARGET_CALL_STACK_OFFSET 0 |
28 | -#define TCG_TARGET_CON_STR_H | 29 | +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL |
29 | 30 | #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL | |
30 | #endif /* AARCH64_TCG_TARGET_H */ | 31 | |
32 | /* optional instructions */ | ||
31 | diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h | 33 | diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h |
32 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/tcg/arm/tcg-target.h | 35 | --- a/tcg/arm/tcg-target.h |
34 | +++ b/tcg/arm/tcg-target.h | 36 | +++ b/tcg/arm/tcg-target.h |
35 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 37 | @@ -XXX,XX +XXX,XX @@ extern bool use_neon_instructions; |
36 | #define TCG_TARGET_NEED_LDST_LABELS | 38 | /* used for function call generation */ |
37 | #endif | 39 | #define TCG_TARGET_STACK_ALIGN 8 |
38 | #define TCG_TARGET_NEED_POOL_LABELS | 40 | #define TCG_TARGET_CALL_STACK_OFFSET 0 |
39 | -#define TCG_TARGET_CON_STR_H | 41 | +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL |
40 | 42 | #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN | |
41 | #endif | 43 | |
44 | /* optional instructions */ | ||
42 | diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h | 45 | diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h |
43 | index XXXXXXX..XXXXXXX 100644 | 46 | index XXXXXXX..XXXXXXX 100644 |
44 | --- a/tcg/i386/tcg-target.h | 47 | --- a/tcg/i386/tcg-target.h |
45 | +++ b/tcg/i386/tcg-target.h | 48 | +++ b/tcg/i386/tcg-target.h |
46 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | 49 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
47 | #define TCG_TARGET_NEED_LDST_LABELS | 50 | #else |
48 | #endif | 51 | #define TCG_TARGET_CALL_STACK_OFFSET 0 |
49 | #define TCG_TARGET_NEED_POOL_LABELS | 52 | #endif |
50 | -#define TCG_TARGET_CON_STR_H | 53 | +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL |
51 | 54 | #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL | |
52 | #endif | 55 | |
56 | extern bool have_bmi1; | ||
57 | diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h | ||
58 | index XXXXXXX..XXXXXXX 100644 | ||
59 | --- a/tcg/loongarch64/tcg-target.h | ||
60 | +++ b/tcg/loongarch64/tcg-target.h | ||
61 | @@ -XXX,XX +XXX,XX @@ typedef enum { | ||
62 | #define TCG_REG_CALL_STACK TCG_REG_SP | ||
63 | #define TCG_TARGET_STACK_ALIGN 16 | ||
64 | #define TCG_TARGET_CALL_STACK_OFFSET 0 | ||
65 | +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL | ||
66 | #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL | ||
67 | |||
68 | /* optional instructions */ | ||
53 | diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h | 69 | diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h |
54 | index XXXXXXX..XXXXXXX 100644 | 70 | index XXXXXXX..XXXXXXX 100644 |
55 | --- a/tcg/mips/tcg-target.h | 71 | --- a/tcg/mips/tcg-target.h |
56 | +++ b/tcg/mips/tcg-target.h | 72 | +++ b/tcg/mips/tcg-target.h |
57 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 73 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
58 | #ifdef CONFIG_SOFTMMU | 74 | # define TCG_TARGET_CALL_STACK_OFFSET 0 |
59 | #define TCG_TARGET_NEED_LDST_LABELS | 75 | # define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL |
60 | #endif | 76 | #endif |
61 | -#define TCG_TARGET_CON_STR_H | 77 | +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL |
62 | 78 | ||
63 | #endif | 79 | /* MOVN/MOVZ instructions detection */ |
64 | diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h | 80 | #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 1)) || \ |
65 | index XXXXXXX..XXXXXXX 100644 | ||
66 | --- a/tcg/ppc/tcg-target.h | ||
67 | +++ b/tcg/ppc/tcg-target.h | ||
68 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | ||
69 | #define TCG_TARGET_NEED_LDST_LABELS | ||
70 | #endif | ||
71 | #define TCG_TARGET_NEED_POOL_LABELS | ||
72 | -#define TCG_TARGET_CON_STR_H | ||
73 | |||
74 | #endif | ||
75 | diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h | 81 | diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h |
76 | index XXXXXXX..XXXXXXX 100644 | 82 | index XXXXXXX..XXXXXXX 100644 |
77 | --- a/tcg/riscv/tcg-target.h | 83 | --- a/tcg/riscv/tcg-target.h |
78 | +++ b/tcg/riscv/tcg-target.h | 84 | +++ b/tcg/riscv/tcg-target.h |
79 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 85 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
80 | #define TCG_TARGET_NEED_POOL_LABELS | 86 | #define TCG_REG_CALL_STACK TCG_REG_SP |
81 | 87 | #define TCG_TARGET_STACK_ALIGN 16 | |
82 | #define TCG_TARGET_HAS_MEMORY_BSWAP 0 | 88 | #define TCG_TARGET_CALL_STACK_OFFSET 0 |
83 | -#define TCG_TARGET_CON_STR_H | 89 | +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL |
84 | 90 | #if TCG_TARGET_REG_BITS == 32 | |
85 | #endif | 91 | #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN |
86 | diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h | 92 | #else |
87 | index XXXXXXX..XXXXXXX 100644 | 93 | diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h |
88 | --- a/tcg/s390/tcg-target.h | 94 | index XXXXXXX..XXXXXXX 100644 |
89 | +++ b/tcg/s390/tcg-target.h | 95 | --- a/tcg/s390x/tcg-target.h |
90 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | 96 | +++ b/tcg/s390x/tcg-target.h |
91 | #define TCG_TARGET_NEED_LDST_LABELS | 97 | @@ -XXX,XX +XXX,XX @@ extern uint64_t s390_facilities[3]; |
92 | #endif | 98 | /* used for function call generation */ |
93 | #define TCG_TARGET_NEED_POOL_LABELS | 99 | #define TCG_TARGET_STACK_ALIGN 8 |
94 | -#define TCG_TARGET_CON_STR_H | 100 | #define TCG_TARGET_CALL_STACK_OFFSET 160 |
95 | 101 | +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EXTEND | |
96 | #endif | 102 | #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL |
97 | diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h | 103 | |
98 | index XXXXXXX..XXXXXXX 100644 | 104 | -#define TCG_TARGET_EXTEND_ARGS 1 |
99 | --- a/tcg/sparc/tcg-target.h | 105 | #define TCG_TARGET_HAS_MEMORY_BSWAP 1 |
100 | +++ b/tcg/sparc/tcg-target.h | 106 | |
101 | @@ -XXX,XX +XXX,XX @@ extern bool use_vis3_instructions; | 107 | #define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD) |
102 | void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 108 | diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h |
103 | 109 | index XXXXXXX..XXXXXXX 100644 | |
104 | #define TCG_TARGET_NEED_POOL_LABELS | 110 | --- a/tcg/sparc64/tcg-target.h |
105 | -#define TCG_TARGET_CON_STR_H | 111 | +++ b/tcg/sparc64/tcg-target.h |
106 | 112 | @@ -XXX,XX +XXX,XX @@ typedef enum { | |
107 | #endif | 113 | #define TCG_TARGET_STACK_BIAS 2047 |
114 | #define TCG_TARGET_STACK_ALIGN 16 | ||
115 | #define TCG_TARGET_CALL_STACK_OFFSET (128 + 6*8 + TCG_TARGET_STACK_BIAS) | ||
116 | -#define TCG_TARGET_EXTEND_ARGS 1 | ||
117 | +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EXTEND | ||
118 | #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL | ||
119 | |||
120 | #if defined(__VIS__) && __VIS__ >= 0x300 | ||
108 | diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h | 121 | diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h |
109 | index XXXXXXX..XXXXXXX 100644 | 122 | index XXXXXXX..XXXXXXX 100644 |
110 | --- a/tcg/tci/tcg-target.h | 123 | --- a/tcg/tci/tcg-target.h |
111 | +++ b/tcg/tci/tcg-target.h | 124 | +++ b/tcg/tci/tcg-target.h |
112 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | 125 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
113 | /* no need to flush icache explicitly */ | 126 | /* Used for function call generation. */ |
114 | } | 127 | #define TCG_TARGET_CALL_STACK_OFFSET 0 |
115 | 128 | #define TCG_TARGET_STACK_ALIGN 8 | |
116 | -#define TCG_TARGET_CON_STR_H | 129 | +#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL |
117 | - | 130 | #if TCG_TARGET_REG_BITS == 32 |
118 | #endif /* TCG_TARGET_H */ | 131 | # define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN |
132 | #else | ||
119 | diff --git a/tcg/tcg.c b/tcg/tcg.c | 133 | diff --git a/tcg/tcg.c b/tcg/tcg.c |
120 | index XXXXXXX..XXXXXXX 100644 | 134 | index XXXXXXX..XXXXXXX 100644 |
121 | --- a/tcg/tcg.c | 135 | --- a/tcg/tcg.c |
122 | +++ b/tcg/tcg.c | 136 | +++ b/tcg/tcg.c |
123 | @@ -XXX,XX +XXX,XX @@ static void tcg_register_jit_int(const void *buf, size_t size, | 137 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) |
124 | __attribute__((unused)); | 138 | } |
125 | 139 | #endif | |
126 | /* Forward declarations for functions declared and used in tcg-target.c.inc. */ | 140 | |
127 | -#ifndef TCG_TARGET_CON_STR_H | 141 | -#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 |
128 | -static const char *target_parse_constraint(TCGArgConstraint *ct, | 142 | - for (i = 0; i < nargs; ++i) { |
129 | - const char *ct_str, TCGType type); | 143 | - int argtype = extract32(typemask, (i + 1) * 3, 3); |
130 | -#endif | 144 | - bool is_32bit = (argtype & ~1) == dh_typecode_i32; |
131 | static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, | 145 | - bool is_signed = argtype & 1; |
132 | intptr_t arg2); | 146 | + if (TCG_TARGET_CALL_ARG_I32 == TCG_CALL_ARG_EXTEND) { |
133 | static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); | 147 | + for (i = 0; i < nargs; ++i) { |
134 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | 148 | + int argtype = extract32(typemask, (i + 1) * 3, 3); |
135 | ct_str++; | 149 | + bool is_32bit = (argtype & ~1) == dh_typecode_i32; |
136 | break; | 150 | + bool is_signed = argtype & 1; |
137 | 151 | ||
138 | -#ifdef TCG_TARGET_CON_STR_H | 152 | - if (is_32bit) { |
139 | /* Include all of the target-specific constraints. */ | 153 | - TCGv_i64 temp = tcg_temp_new_i64(); |
140 | 154 | - TCGv_i32 orig = temp_tcgv_i32(args[i]); | |
141 | #undef CONST | 155 | - if (is_signed) { |
142 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | 156 | - tcg_gen_ext_i32_i64(temp, orig); |
143 | default: | 157 | - } else { |
144 | /* Typo in TCGTargetOpDef constraint. */ | 158 | - tcg_gen_extu_i32_i64(temp, orig); |
145 | g_assert_not_reached(); | 159 | + if (is_32bit) { |
146 | -#else | 160 | + TCGv_i64 temp = tcg_temp_new_i64(); |
147 | - default: | 161 | + TCGv_i32 orig = temp_tcgv_i32(args[i]); |
148 | - { | 162 | + if (is_signed) { |
149 | - TCGType type = (def->flags & TCG_OPF_64BIT | 163 | + tcg_gen_ext_i32_i64(temp, orig); |
150 | - ? TCG_TYPE_I64 : TCG_TYPE_I32); | 164 | + } else { |
151 | - ct_str = target_parse_constraint(&def->args_ct[i], | 165 | + tcg_gen_extu_i32_i64(temp, orig); |
152 | - ct_str, type); | 166 | + } |
153 | - /* Typo in TCGTargetOpDef constraint. */ | 167 | + args[i] = tcgv_i64_temp(temp); |
154 | - tcg_debug_assert(ct_str != NULL); | ||
155 | - } | ||
156 | -#endif | ||
157 | } | ||
158 | } | 168 | } |
169 | - args[i] = tcgv_i64_temp(temp); | ||
159 | } | 170 | } |
171 | } | ||
172 | -#endif /* TCG_TARGET_EXTEND_ARGS */ | ||
173 | |||
174 | op = tcg_emit_op(INDEX_op_call); | ||
175 | |||
176 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
177 | tcg_debug_assert(TCGOP_CALLI(op) == real_args); | ||
178 | tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); | ||
179 | |||
180 | -#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 | ||
181 | - for (i = 0; i < nargs; ++i) { | ||
182 | - int argtype = extract32(typemask, (i + 1) * 3, 3); | ||
183 | - bool is_32bit = (argtype & ~1) == dh_typecode_i32; | ||
184 | + if (TCG_TARGET_CALL_ARG_I32 == TCG_CALL_ARG_EXTEND) { | ||
185 | + for (i = 0; i < nargs; ++i) { | ||
186 | + int argtype = extract32(typemask, (i + 1) * 3, 3); | ||
187 | + bool is_32bit = (argtype & ~1) == dh_typecode_i32; | ||
188 | |||
189 | - if (is_32bit) { | ||
190 | - tcg_temp_free_internal(args[i]); | ||
191 | + if (is_32bit) { | ||
192 | + tcg_temp_free_internal(args[i]); | ||
193 | + } | ||
194 | } | ||
195 | } | ||
196 | -#endif /* TCG_TARGET_EXTEND_ARGS */ | ||
197 | } | ||
198 | |||
199 | static void tcg_reg_alloc_start(TCGContext *s) | ||
200 | diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc | ||
201 | index XXXXXXX..XXXXXXX 100644 | ||
202 | --- a/tcg/ppc/tcg-target.c.inc | ||
203 | +++ b/tcg/ppc/tcg-target.c.inc | ||
204 | @@ -XXX,XX +XXX,XX @@ | ||
205 | # endif | ||
206 | #endif | ||
207 | |||
208 | +#if TCG_TARGET_REG_BITS == 64 | ||
209 | +# define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EXTEND | ||
210 | +#else | ||
211 | +# define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL | ||
212 | +#endif | ||
213 | #ifdef _CALL_SYSV | ||
214 | # define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN | ||
215 | #else | ||
216 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count) | ||
217 | |||
218 | /* Parameters for function call generation, used in tcg.c. */ | ||
219 | #define TCG_TARGET_STACK_ALIGN 16 | ||
220 | -#define TCG_TARGET_EXTEND_ARGS 1 | ||
221 | |||
222 | #ifdef _CALL_AIX | ||
223 | # define LINK_AREA_SIZE (6 * SZR) | ||
160 | -- | 224 | -- |
161 | 2.25.1 | 225 | 2.34.1 |
162 | 226 | ||
163 | 227 | diff view generated by jsdifflib |
1 | This requires finishing the conversion to tcg_target_op_def. | 1 | Change 32-bit tci TCG_TARGET_CALL_ARG_I32 to TCG_CALL_ARG_EVEN, to |
---|---|---|---|
2 | force 32-bit values to be aligned to 64-bit. With a small reorg | ||
3 | to the argument processing loop, this neatly replaces an ifdef for | ||
4 | CONFIG_TCG_INTERPRETER. | ||
2 | 5 | ||
3 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 6 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
4 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 7 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
5 | --- | 8 | --- |
6 | tcg/tci/tcg-target-con-set.h | 25 ++++ | 9 | tcg/tci/tcg-target.h | 3 +- |
7 | tcg/tci/tcg-target.h | 2 + | 10 | tcg/tcg.c | 70 ++++++++++++++++++++++++++++---------------- |
8 | tcg/tci/tcg-target.c.inc | 279 +++++++++++++++++------------------ | 11 | 2 files changed, 47 insertions(+), 26 deletions(-) |
9 | 3 files changed, 161 insertions(+), 145 deletions(-) | ||
10 | create mode 100644 tcg/tci/tcg-target-con-set.h | ||
11 | 12 | ||
12 | diff --git a/tcg/tci/tcg-target-con-set.h b/tcg/tci/tcg-target-con-set.h | ||
13 | new file mode 100644 | ||
14 | index XXXXXXX..XXXXXXX | ||
15 | --- /dev/null | ||
16 | +++ b/tcg/tci/tcg-target-con-set.h | ||
17 | @@ -XXX,XX +XXX,XX @@ | ||
18 | +/* SPDX-License-Identifier: MIT */ | ||
19 | +/* | ||
20 | + * TCI target-specific constraint sets. | ||
21 | + * Copyright (c) 2021 Linaro | ||
22 | + */ | ||
23 | + | ||
24 | +/* | ||
25 | + * C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs. | ||
26 | + * Each operand should be a sequence of constraint letters as defined by | ||
27 | + * tcg-target-con-str.h; the constraint combination is inclusive or. | ||
28 | + */ | ||
29 | +C_O0_I2(r, r) | ||
30 | +C_O0_I2(r, ri) | ||
31 | +C_O0_I3(r, r, r) | ||
32 | +C_O0_I4(r, r, ri, ri) | ||
33 | +C_O0_I4(r, r, r, r) | ||
34 | +C_O1_I1(r, r) | ||
35 | +C_O1_I2(r, 0, r) | ||
36 | +C_O1_I2(r, ri, ri) | ||
37 | +C_O1_I2(r, r, r) | ||
38 | +C_O1_I2(r, r, ri) | ||
39 | +C_O1_I4(r, r, r, ri, ri) | ||
40 | +C_O2_I1(r, r, r) | ||
41 | +C_O2_I2(r, r, r, r) | ||
42 | +C_O2_I4(r, r, r, r, r, r) | ||
43 | diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h | 13 | diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h |
44 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
45 | --- a/tcg/tci/tcg-target.h | 15 | --- a/tcg/tci/tcg-target.h |
46 | +++ b/tcg/tci/tcg-target.h | 16 | +++ b/tcg/tci/tcg-target.h |
47 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | 17 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
48 | /* no need to flush icache explicitly */ | 18 | /* Used for function call generation. */ |
49 | } | 19 | #define TCG_TARGET_CALL_STACK_OFFSET 0 |
50 | 20 | #define TCG_TARGET_STACK_ALIGN 8 | |
51 | +#define TCG_TARGET_CON_SET_H | 21 | -#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL |
52 | + | 22 | #if TCG_TARGET_REG_BITS == 32 |
53 | #endif /* TCG_TARGET_H */ | 23 | +# define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EVEN |
54 | diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc | 24 | # define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN |
25 | #else | ||
26 | +# define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL | ||
27 | # define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL | ||
28 | #endif | ||
29 | |||
30 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
55 | index XXXXXXX..XXXXXXX 100644 | 31 | index XXXXXXX..XXXXXXX 100644 |
56 | --- a/tcg/tci/tcg-target.c.inc | 32 | --- a/tcg/tcg.c |
57 | +++ b/tcg/tci/tcg-target.c.inc | 33 | +++ b/tcg/tcg.c |
58 | @@ -XXX,XX +XXX,XX @@ | 34 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) |
59 | /* Bitfield n...m (in 32 bit value). */ | 35 | real_args = 0; |
60 | #define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m) | 36 | for (i = 0; i < nargs; i++) { |
61 | 37 | int argtype = extract32(typemask, (i + 1) * 3, 3); | |
62 | -/* Macros used in tcg_target_op_defs. */ | 38 | - bool is_64bit = (argtype & ~1) == dh_typecode_i64; |
63 | -#define R "r" | 39 | - bool want_align = false; |
64 | -#define RI "ri" | 40 | + TCGCallArgumentKind kind; |
65 | -#if TCG_TARGET_REG_BITS == 32 | 41 | + TCGType type; |
66 | -# define R64 "r", "r" | 42 | |
43 | -#if defined(CONFIG_TCG_INTERPRETER) | ||
44 | - /* | ||
45 | - * Align all arguments, so that they land in predictable places | ||
46 | - * for passing off to ffi_call. | ||
47 | - */ | ||
48 | - want_align = true; | ||
67 | -#else | 49 | -#else |
68 | -# define R64 "r" | 50 | - /* Some targets want aligned 64 bit args */ |
69 | -#endif | 51 | - if (is_64bit) { |
70 | -#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS | 52 | - want_align = TCG_TARGET_CALL_ARG_I64 == TCG_CALL_ARG_EVEN; |
71 | -# define L "r", "r" | 53 | - } |
72 | -# define S "r", "r" | ||
73 | -#else | ||
74 | -# define L "r" | ||
75 | -# define S "r" | ||
76 | -#endif | 54 | -#endif |
77 | - | 55 | - |
78 | -/* TODO: documentation. */ | 56 | - if (TCG_TARGET_REG_BITS < 64 && want_align && (real_args & 1)) { |
79 | -static const TCGTargetOpDef tcg_target_op_defs[] = { | 57 | - op->args[pi++] = TCG_CALL_DUMMY_ARG; |
80 | - { INDEX_op_exit_tb, { NULL } }, | 58 | - real_args++; |
81 | - { INDEX_op_goto_tb, { NULL } }, | 59 | + switch (argtype) { |
82 | - { INDEX_op_br, { NULL } }, | 60 | + case dh_typecode_i32: |
61 | + case dh_typecode_s32: | ||
62 | + type = TCG_TYPE_I32; | ||
63 | + break; | ||
64 | + case dh_typecode_i64: | ||
65 | + case dh_typecode_s64: | ||
66 | + type = TCG_TYPE_I64; | ||
67 | + break; | ||
68 | + case dh_typecode_ptr: | ||
69 | + type = TCG_TYPE_PTR; | ||
70 | + break; | ||
71 | + default: | ||
72 | + g_assert_not_reached(); | ||
73 | } | ||
74 | |||
75 | - if (TCG_TARGET_REG_BITS < 64 && is_64bit) { | ||
76 | + switch (type) { | ||
77 | + case TCG_TYPE_I32: | ||
78 | + kind = TCG_TARGET_CALL_ARG_I32; | ||
79 | + break; | ||
80 | + case TCG_TYPE_I64: | ||
81 | + kind = TCG_TARGET_CALL_ARG_I64; | ||
82 | + break; | ||
83 | + default: | ||
84 | + g_assert_not_reached(); | ||
85 | + } | ||
86 | + | ||
87 | + switch (kind) { | ||
88 | + case TCG_CALL_ARG_EVEN: | ||
89 | + if (real_args & 1) { | ||
90 | + op->args[pi++] = TCG_CALL_DUMMY_ARG; | ||
91 | + real_args++; | ||
92 | + } | ||
93 | + /* fall through */ | ||
94 | + case TCG_CALL_ARG_NORMAL: | ||
95 | + if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { | ||
96 | + op->args[pi++] = temp_arg(args[i]); | ||
97 | + op->args[pi++] = temp_arg(args[i] + 1); | ||
98 | + real_args += 2; | ||
99 | + break; | ||
100 | + } | ||
101 | op->args[pi++] = temp_arg(args[i]); | ||
102 | - op->args[pi++] = temp_arg(args[i] + 1); | ||
103 | - real_args += 2; | ||
104 | - continue; | ||
105 | + real_args++; | ||
106 | + break; | ||
107 | + default: | ||
108 | + g_assert_not_reached(); | ||
109 | } | ||
83 | - | 110 | - |
84 | - { INDEX_op_ld8u_i32, { R, R } }, | 111 | - op->args[pi++] = temp_arg(args[i]); |
85 | - { INDEX_op_ld8s_i32, { R, R } }, | 112 | - real_args++; |
86 | - { INDEX_op_ld16u_i32, { R, R } }, | ||
87 | - { INDEX_op_ld16s_i32, { R, R } }, | ||
88 | - { INDEX_op_ld_i32, { R, R } }, | ||
89 | - { INDEX_op_st8_i32, { R, R } }, | ||
90 | - { INDEX_op_st16_i32, { R, R } }, | ||
91 | - { INDEX_op_st_i32, { R, R } }, | ||
92 | - | ||
93 | - { INDEX_op_add_i32, { R, RI, RI } }, | ||
94 | - { INDEX_op_sub_i32, { R, RI, RI } }, | ||
95 | - { INDEX_op_mul_i32, { R, RI, RI } }, | ||
96 | - { INDEX_op_div_i32, { R, R, R } }, | ||
97 | - { INDEX_op_divu_i32, { R, R, R } }, | ||
98 | - { INDEX_op_rem_i32, { R, R, R } }, | ||
99 | - { INDEX_op_remu_i32, { R, R, R } }, | ||
100 | - /* TODO: Does R, RI, RI result in faster code than R, R, RI? | ||
101 | - If both operands are constants, we can optimize. */ | ||
102 | - { INDEX_op_and_i32, { R, RI, RI } }, | ||
103 | - { INDEX_op_andc_i32, { R, RI, RI } }, | ||
104 | - { INDEX_op_eqv_i32, { R, RI, RI } }, | ||
105 | - { INDEX_op_nand_i32, { R, RI, RI } }, | ||
106 | - { INDEX_op_nor_i32, { R, RI, RI } }, | ||
107 | - { INDEX_op_or_i32, { R, RI, RI } }, | ||
108 | - { INDEX_op_orc_i32, { R, RI, RI } }, | ||
109 | - { INDEX_op_xor_i32, { R, RI, RI } }, | ||
110 | - { INDEX_op_shl_i32, { R, RI, RI } }, | ||
111 | - { INDEX_op_shr_i32, { R, RI, RI } }, | ||
112 | - { INDEX_op_sar_i32, { R, RI, RI } }, | ||
113 | - { INDEX_op_rotl_i32, { R, RI, RI } }, | ||
114 | - { INDEX_op_rotr_i32, { R, RI, RI } }, | ||
115 | - { INDEX_op_deposit_i32, { R, "0", R } }, | ||
116 | - | ||
117 | - { INDEX_op_brcond_i32, { R, RI } }, | ||
118 | - | ||
119 | - { INDEX_op_setcond_i32, { R, R, RI } }, | ||
120 | - { INDEX_op_setcond_i64, { R, R, RI } }, | ||
121 | - | ||
122 | - /* TODO: Support R, R, R, R, RI, RI? Will it be faster? */ | ||
123 | - { INDEX_op_add2_i32, { R, R, R, R, R, R } }, | ||
124 | - { INDEX_op_sub2_i32, { R, R, R, R, R, R } }, | ||
125 | - { INDEX_op_brcond2_i32, { R, R, RI, RI } }, | ||
126 | - { INDEX_op_mulu2_i32, { R, R, R, R } }, | ||
127 | - { INDEX_op_setcond2_i32, { R, R, R, RI, RI } }, | ||
128 | - | ||
129 | - { INDEX_op_not_i32, { R, R } }, | ||
130 | - { INDEX_op_neg_i32, { R, R } }, | ||
131 | - | ||
132 | - { INDEX_op_ld8u_i64, { R, R } }, | ||
133 | - { INDEX_op_ld8s_i64, { R, R } }, | ||
134 | - { INDEX_op_ld16u_i64, { R, R } }, | ||
135 | - { INDEX_op_ld16s_i64, { R, R } }, | ||
136 | - { INDEX_op_ld32u_i64, { R, R } }, | ||
137 | - { INDEX_op_ld32s_i64, { R, R } }, | ||
138 | - { INDEX_op_ld_i64, { R, R } }, | ||
139 | - | ||
140 | - { INDEX_op_st8_i64, { R, R } }, | ||
141 | - { INDEX_op_st16_i64, { R, R } }, | ||
142 | - { INDEX_op_st32_i64, { R, R } }, | ||
143 | - { INDEX_op_st_i64, { R, R } }, | ||
144 | - | ||
145 | - { INDEX_op_add_i64, { R, RI, RI } }, | ||
146 | - { INDEX_op_sub_i64, { R, RI, RI } }, | ||
147 | - { INDEX_op_mul_i64, { R, RI, RI } }, | ||
148 | - { INDEX_op_div_i64, { R, R, R } }, | ||
149 | - { INDEX_op_divu_i64, { R, R, R } }, | ||
150 | - { INDEX_op_rem_i64, { R, R, R } }, | ||
151 | - { INDEX_op_remu_i64, { R, R, R } }, | ||
152 | - { INDEX_op_and_i64, { R, RI, RI } }, | ||
153 | - { INDEX_op_andc_i64, { R, RI, RI } }, | ||
154 | - { INDEX_op_eqv_i64, { R, RI, RI } }, | ||
155 | - { INDEX_op_nand_i64, { R, RI, RI } }, | ||
156 | - { INDEX_op_nor_i64, { R, RI, RI } }, | ||
157 | - { INDEX_op_or_i64, { R, RI, RI } }, | ||
158 | - { INDEX_op_orc_i64, { R, RI, RI } }, | ||
159 | - { INDEX_op_xor_i64, { R, RI, RI } }, | ||
160 | - { INDEX_op_shl_i64, { R, RI, RI } }, | ||
161 | - { INDEX_op_shr_i64, { R, RI, RI } }, | ||
162 | - { INDEX_op_sar_i64, { R, RI, RI } }, | ||
163 | - { INDEX_op_rotl_i64, { R, RI, RI } }, | ||
164 | - { INDEX_op_rotr_i64, { R, RI, RI } }, | ||
165 | - { INDEX_op_deposit_i64, { R, "0", R } }, | ||
166 | - { INDEX_op_brcond_i64, { R, RI } }, | ||
167 | - | ||
168 | - { INDEX_op_ext8s_i64, { R, R } }, | ||
169 | - { INDEX_op_ext16s_i64, { R, R } }, | ||
170 | - { INDEX_op_ext32s_i64, { R, R } }, | ||
171 | - { INDEX_op_ext8u_i64, { R, R } }, | ||
172 | - { INDEX_op_ext16u_i64, { R, R } }, | ||
173 | - { INDEX_op_ext32u_i64, { R, R } }, | ||
174 | - { INDEX_op_ext_i32_i64, { R, R } }, | ||
175 | - { INDEX_op_extu_i32_i64, { R, R } }, | ||
176 | - { INDEX_op_bswap16_i64, { R, R } }, | ||
177 | - { INDEX_op_bswap32_i64, { R, R } }, | ||
178 | - { INDEX_op_bswap64_i64, { R, R } }, | ||
179 | - { INDEX_op_not_i64, { R, R } }, | ||
180 | - { INDEX_op_neg_i64, { R, R } }, | ||
181 | - | ||
182 | - { INDEX_op_qemu_ld_i32, { R, L } }, | ||
183 | - { INDEX_op_qemu_ld_i64, { R64, L } }, | ||
184 | - | ||
185 | - { INDEX_op_qemu_st_i32, { R, S } }, | ||
186 | - { INDEX_op_qemu_st_i64, { R64, S } }, | ||
187 | - | ||
188 | - { INDEX_op_ext8s_i32, { R, R } }, | ||
189 | - { INDEX_op_ext16s_i32, { R, R } }, | ||
190 | - { INDEX_op_ext8u_i32, { R, R } }, | ||
191 | - { INDEX_op_ext16u_i32, { R, R } }, | ||
192 | - | ||
193 | - { INDEX_op_bswap16_i32, { R, R } }, | ||
194 | - { INDEX_op_bswap32_i32, { R, R } }, | ||
195 | - | ||
196 | - { INDEX_op_mb, { } }, | ||
197 | - { -1 }, | ||
198 | -}; | ||
199 | - | ||
200 | -static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
201 | +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) | ||
202 | { | ||
203 | - int i, n = ARRAY_SIZE(tcg_target_op_defs); | ||
204 | + switch (op) { | ||
205 | + case INDEX_op_ld8u_i32: | ||
206 | + case INDEX_op_ld8s_i32: | ||
207 | + case INDEX_op_ld16u_i32: | ||
208 | + case INDEX_op_ld16s_i32: | ||
209 | + case INDEX_op_ld_i32: | ||
210 | + case INDEX_op_ld8u_i64: | ||
211 | + case INDEX_op_ld8s_i64: | ||
212 | + case INDEX_op_ld16u_i64: | ||
213 | + case INDEX_op_ld16s_i64: | ||
214 | + case INDEX_op_ld32u_i64: | ||
215 | + case INDEX_op_ld32s_i64: | ||
216 | + case INDEX_op_ld_i64: | ||
217 | + case INDEX_op_not_i32: | ||
218 | + case INDEX_op_not_i64: | ||
219 | + case INDEX_op_neg_i32: | ||
220 | + case INDEX_op_neg_i64: | ||
221 | + case INDEX_op_ext8s_i32: | ||
222 | + case INDEX_op_ext8s_i64: | ||
223 | + case INDEX_op_ext16s_i32: | ||
224 | + case INDEX_op_ext16s_i64: | ||
225 | + case INDEX_op_ext8u_i32: | ||
226 | + case INDEX_op_ext8u_i64: | ||
227 | + case INDEX_op_ext16u_i32: | ||
228 | + case INDEX_op_ext16u_i64: | ||
229 | + case INDEX_op_ext32s_i64: | ||
230 | + case INDEX_op_ext32u_i64: | ||
231 | + case INDEX_op_ext_i32_i64: | ||
232 | + case INDEX_op_extu_i32_i64: | ||
233 | + case INDEX_op_bswap16_i32: | ||
234 | + case INDEX_op_bswap16_i64: | ||
235 | + case INDEX_op_bswap32_i32: | ||
236 | + case INDEX_op_bswap32_i64: | ||
237 | + case INDEX_op_bswap64_i64: | ||
238 | + return C_O1_I1(r, r); | ||
239 | |||
240 | - for (i = 0; i < n; ++i) { | ||
241 | - if (tcg_target_op_defs[i].op == op) { | ||
242 | - return &tcg_target_op_defs[i]; | ||
243 | - } | ||
244 | + case INDEX_op_st8_i32: | ||
245 | + case INDEX_op_st16_i32: | ||
246 | + case INDEX_op_st_i32: | ||
247 | + case INDEX_op_st8_i64: | ||
248 | + case INDEX_op_st16_i64: | ||
249 | + case INDEX_op_st32_i64: | ||
250 | + case INDEX_op_st_i64: | ||
251 | + return C_O0_I2(r, r); | ||
252 | + | ||
253 | + case INDEX_op_div_i32: | ||
254 | + case INDEX_op_div_i64: | ||
255 | + case INDEX_op_divu_i32: | ||
256 | + case INDEX_op_divu_i64: | ||
257 | + case INDEX_op_rem_i32: | ||
258 | + case INDEX_op_rem_i64: | ||
259 | + case INDEX_op_remu_i32: | ||
260 | + case INDEX_op_remu_i64: | ||
261 | + return C_O1_I2(r, r, r); | ||
262 | + | ||
263 | + case INDEX_op_add_i32: | ||
264 | + case INDEX_op_add_i64: | ||
265 | + case INDEX_op_sub_i32: | ||
266 | + case INDEX_op_sub_i64: | ||
267 | + case INDEX_op_mul_i32: | ||
268 | + case INDEX_op_mul_i64: | ||
269 | + case INDEX_op_and_i32: | ||
270 | + case INDEX_op_and_i64: | ||
271 | + case INDEX_op_andc_i32: | ||
272 | + case INDEX_op_andc_i64: | ||
273 | + case INDEX_op_eqv_i32: | ||
274 | + case INDEX_op_eqv_i64: | ||
275 | + case INDEX_op_nand_i32: | ||
276 | + case INDEX_op_nand_i64: | ||
277 | + case INDEX_op_nor_i32: | ||
278 | + case INDEX_op_nor_i64: | ||
279 | + case INDEX_op_or_i32: | ||
280 | + case INDEX_op_or_i64: | ||
281 | + case INDEX_op_orc_i32: | ||
282 | + case INDEX_op_orc_i64: | ||
283 | + case INDEX_op_xor_i32: | ||
284 | + case INDEX_op_xor_i64: | ||
285 | + case INDEX_op_shl_i32: | ||
286 | + case INDEX_op_shl_i64: | ||
287 | + case INDEX_op_shr_i32: | ||
288 | + case INDEX_op_shr_i64: | ||
289 | + case INDEX_op_sar_i32: | ||
290 | + case INDEX_op_sar_i64: | ||
291 | + case INDEX_op_rotl_i32: | ||
292 | + case INDEX_op_rotl_i64: | ||
293 | + case INDEX_op_rotr_i32: | ||
294 | + case INDEX_op_rotr_i64: | ||
295 | + /* TODO: Does R, RI, RI result in faster code than R, R, RI? */ | ||
296 | + return C_O1_I2(r, ri, ri); | ||
297 | + | ||
298 | + case INDEX_op_deposit_i32: | ||
299 | + case INDEX_op_deposit_i64: | ||
300 | + return C_O1_I2(r, 0, r); | ||
301 | + | ||
302 | + case INDEX_op_brcond_i32: | ||
303 | + case INDEX_op_brcond_i64: | ||
304 | + return C_O0_I2(r, ri); | ||
305 | + | ||
306 | + case INDEX_op_setcond_i32: | ||
307 | + case INDEX_op_setcond_i64: | ||
308 | + return C_O1_I2(r, r, ri); | ||
309 | + | ||
310 | +#if TCG_TARGET_REG_BITS == 32 | ||
311 | + /* TODO: Support R, R, R, R, RI, RI? Will it be faster? */ | ||
312 | + case INDEX_op_add2_i32: | ||
313 | + case INDEX_op_sub2_i32: | ||
314 | + return C_O2_I4(r, r, r, r, r, r); | ||
315 | + case INDEX_op_brcond2_i32: | ||
316 | + return C_O0_I4(r, r, ri, ri); | ||
317 | + case INDEX_op_mulu2_i32: | ||
318 | + return C_O2_I2(r, r, r, r); | ||
319 | + case INDEX_op_setcond2_i32: | ||
320 | + return C_O1_I4(r, r, r, ri, ri); | ||
321 | +#endif | ||
322 | + | ||
323 | + case INDEX_op_qemu_ld_i32: | ||
324 | + return (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS | ||
325 | + ? C_O1_I1(r, r) | ||
326 | + : C_O1_I2(r, r, r)); | ||
327 | + case INDEX_op_qemu_ld_i64: | ||
328 | + return (TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) | ||
329 | + : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? C_O2_I1(r, r, r) | ||
330 | + : C_O2_I2(r, r, r, r)); | ||
331 | + case INDEX_op_qemu_st_i32: | ||
332 | + return (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS | ||
333 | + ? C_O0_I2(r, r) | ||
334 | + : C_O0_I3(r, r, r)); | ||
335 | + case INDEX_op_qemu_st_i64: | ||
336 | + return (TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r) | ||
337 | + : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? C_O0_I3(r, r, r) | ||
338 | + : C_O0_I4(r, r, r, r)); | ||
339 | + | ||
340 | + default: | ||
341 | + g_assert_not_reached(); | ||
342 | } | 113 | } |
343 | - return NULL; | 114 | op->args[pi++] = (uintptr_t)func; |
344 | } | 115 | op->args[pi++] = (uintptr_t)info; |
345 | |||
346 | static const int tcg_target_reg_alloc_order[] = { | ||
347 | -- | 116 | -- |
348 | 2.25.1 | 117 | 2.34.1 |
349 | 118 | ||
350 | 119 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The function pointer is immediately after the output and input | ||
2 | operands; no need to search. | ||
1 | 3 | ||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | --- | ||
7 | accel/tcg/plugin-gen.c | 29 +++++++++++------------------ | ||
8 | 1 file changed, 11 insertions(+), 18 deletions(-) | ||
9 | |||
10 | diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/accel/tcg/plugin-gen.c | ||
13 | +++ b/accel/tcg/plugin-gen.c | ||
14 | @@ -XXX,XX +XXX,XX @@ static TCGOp *copy_st_ptr(TCGOp **begin_op, TCGOp *op) | ||
15 | static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *empty_func, | ||
16 | void *func, int *cb_idx) | ||
17 | { | ||
18 | + TCGOp *old_op; | ||
19 | + int func_idx; | ||
20 | + | ||
21 | /* copy all ops until the call */ | ||
22 | do { | ||
23 | op = copy_op_nocheck(begin_op, op); | ||
24 | } while (op->opc != INDEX_op_call); | ||
25 | |||
26 | /* fill in the op call */ | ||
27 | - op->param1 = (*begin_op)->param1; | ||
28 | - op->param2 = (*begin_op)->param2; | ||
29 | + old_op = *begin_op; | ||
30 | + TCGOP_CALLI(op) = TCGOP_CALLI(old_op); | ||
31 | + TCGOP_CALLO(op) = TCGOP_CALLO(old_op); | ||
32 | tcg_debug_assert(op->life == 0); | ||
33 | - if (*cb_idx == -1) { | ||
34 | - int i; | ||
35 | |||
36 | - /* | ||
37 | - * Instead of working out the position of the callback in args[], just | ||
38 | - * look for @empty_func, since it should be a unique pointer. | ||
39 | - */ | ||
40 | - for (i = 0; i < MAX_OPC_PARAM_ARGS; i++) { | ||
41 | - if ((uintptr_t)(*begin_op)->args[i] == (uintptr_t)empty_func) { | ||
42 | - *cb_idx = i; | ||
43 | - break; | ||
44 | - } | ||
45 | - } | ||
46 | - tcg_debug_assert(i < MAX_OPC_PARAM_ARGS); | ||
47 | - } | ||
48 | - op->args[*cb_idx] = (uintptr_t)func; | ||
49 | - op->args[*cb_idx + 1] = (*begin_op)->args[*cb_idx + 1]; | ||
50 | + func_idx = TCGOP_CALLO(op) + TCGOP_CALLI(op); | ||
51 | + *cb_idx = func_idx; | ||
52 | + | ||
53 | + op->args[func_idx] = (uintptr_t)func; | ||
54 | + op->args[func_idx + 1] = old_op->args[func_idx + 1]; | ||
55 | |||
56 | return op; | ||
57 | } | ||
58 | -- | ||
59 | 2.34.1 | ||
60 | |||
61 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | We copied all of the arguments in copy_op_nocheck. | ||
2 | We only need to replace the one argument that we change. | ||
1 | 3 | ||
4 | Reviewed-by: Alex Bennée <alex.bennee@linaro.org> | ||
5 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | --- | ||
8 | accel/tcg/plugin-gen.c | 2 -- | ||
9 | 1 file changed, 2 deletions(-) | ||
10 | |||
11 | diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/accel/tcg/plugin-gen.c | ||
14 | +++ b/accel/tcg/plugin-gen.c | ||
15 | @@ -XXX,XX +XXX,XX @@ static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *empty_func, | ||
16 | |||
17 | func_idx = TCGOP_CALLO(op) + TCGOP_CALLI(op); | ||
18 | *cb_idx = func_idx; | ||
19 | - | ||
20 | op->args[func_idx] = (uintptr_t)func; | ||
21 | - op->args[func_idx + 1] = old_op->args[func_idx + 1]; | ||
22 | |||
23 | return op; | ||
24 | } | ||
25 | -- | ||
26 | 2.34.1 | ||
27 | |||
28 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | Better to re-use the existing function for copying ops. |
---|---|---|---|
2 | |||
3 | Acked-by: Alex Bennée <alex.bennee@linaro.org> | ||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 6 | --- |
4 | tcg/aarch64/tcg-target-con-str.h | 24 +++++++++++++++ | 7 | accel/tcg/plugin-gen.c | 16 ++++++++-------- |
5 | tcg/aarch64/tcg-target.h | 1 + | 8 | 1 file changed, 8 insertions(+), 8 deletions(-) |
6 | tcg/aarch64/tcg-target.c.inc | 51 +++++--------------------------- | ||
7 | 3 files changed, 33 insertions(+), 43 deletions(-) | ||
8 | create mode 100644 tcg/aarch64/tcg-target-con-str.h | ||
9 | 9 | ||
10 | diff --git a/tcg/aarch64/tcg-target-con-str.h b/tcg/aarch64/tcg-target-con-str.h | 10 | diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c |
11 | new file mode 100644 | ||
12 | index XXXXXXX..XXXXXXX | ||
13 | --- /dev/null | ||
14 | +++ b/tcg/aarch64/tcg-target-con-str.h | ||
15 | @@ -XXX,XX +XXX,XX @@ | ||
16 | +/* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
17 | +/* | ||
18 | + * Define AArch64 target-specific operand constraints. | ||
19 | + * Copyright (c) 2021 Linaro | ||
20 | + */ | ||
21 | + | ||
22 | +/* | ||
23 | + * Define constraint letters for register sets: | ||
24 | + * REGS(letter, register_mask) | ||
25 | + */ | ||
26 | +REGS('r', ALL_GENERAL_REGS) | ||
27 | +REGS('l', ALL_QLDST_REGS) | ||
28 | +REGS('w', ALL_VECTOR_REGS) | ||
29 | + | ||
30 | +/* | ||
31 | + * Define constraint letters for constants: | ||
32 | + * CONST(letter, TCG_CT_CONST_* bit set) | ||
33 | + */ | ||
34 | +CONST('A', TCG_CT_CONST_AIMM) | ||
35 | +CONST('L', TCG_CT_CONST_LIMM) | ||
36 | +CONST('M', TCG_CT_CONST_MONE) | ||
37 | +CONST('O', TCG_CT_CONST_ORRI) | ||
38 | +CONST('N', TCG_CT_CONST_ANDI) | ||
39 | +CONST('Z', TCG_CT_CONST_ZERO) | ||
40 | diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h | ||
41 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
42 | --- a/tcg/aarch64/tcg-target.h | 12 | --- a/accel/tcg/plugin-gen.c |
43 | +++ b/tcg/aarch64/tcg-target.h | 13 | +++ b/accel/tcg/plugin-gen.c |
44 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 14 | @@ -XXX,XX +XXX,XX @@ static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb, |
45 | #define TCG_TARGET_NEED_LDST_LABELS | 15 | op = copy_const_ptr(&begin_op, op, cb->userp); |
46 | #endif | 16 | |
47 | #define TCG_TARGET_NEED_POOL_LABELS | 17 | /* copy the ld_i32, but note that we only have to copy it once */ |
48 | +#define TCG_TARGET_CON_STR_H | 18 | - begin_op = QTAILQ_NEXT(begin_op, link); |
49 | 19 | - tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32); | |
50 | #endif /* AARCH64_TCG_TARGET_H */ | 20 | if (*cb_idx == -1) { |
51 | diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc | 21 | - op = tcg_op_insert_after(tcg_ctx, op, INDEX_op_ld_i32); |
52 | index XXXXXXX..XXXXXXX 100644 | 22 | - memcpy(op->args, begin_op->args, sizeof(op->args)); |
53 | --- a/tcg/aarch64/tcg-target.c.inc | 23 | + op = copy_op(&begin_op, op, INDEX_op_ld_i32); |
54 | +++ b/tcg/aarch64/tcg-target.c.inc | 24 | + } else { |
55 | @@ -XXX,XX +XXX,XX @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, | 25 | + begin_op = QTAILQ_NEXT(begin_op, link); |
56 | #define TCG_CT_CONST_ORRI 0x1000 | 26 | + tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32); |
57 | #define TCG_CT_CONST_ANDI 0x2000 | 27 | } |
58 | 28 | ||
59 | -/* parse target specific constraints */ | 29 | /* call */ |
60 | -static const char *target_parse_constraint(TCGArgConstraint *ct, | 30 | @@ -XXX,XX +XXX,XX @@ static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb, |
61 | - const char *ct_str, TCGType type) | 31 | op = copy_const_ptr(&begin_op, op, cb->userp); |
62 | -{ | 32 | |
63 | - switch (*ct_str++) { | 33 | /* copy the ld_i32, but note that we only have to copy it once */ |
64 | - case 'r': /* general registers */ | 34 | - begin_op = QTAILQ_NEXT(begin_op, link); |
65 | - ct->regs |= 0xffffffffu; | 35 | - tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32); |
66 | - break; | 36 | if (*cb_idx == -1) { |
67 | - case 'w': /* advsimd registers */ | 37 | - op = tcg_op_insert_after(tcg_ctx, op, INDEX_op_ld_i32); |
68 | - ct->regs |= 0xffffffff00000000ull; | 38 | - memcpy(op->args, begin_op->args, sizeof(op->args)); |
69 | - break; | 39 | + op = copy_op(&begin_op, op, INDEX_op_ld_i32); |
70 | - case 'l': /* qemu_ld / qemu_st address, data_reg */ | 40 | + } else { |
71 | - ct->regs = 0xffffffffu; | 41 | + begin_op = QTAILQ_NEXT(begin_op, link); |
72 | +#define ALL_GENERAL_REGS 0xffffffffu | 42 | + tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32); |
73 | +#define ALL_VECTOR_REGS 0xffffffff00000000ull | 43 | } |
74 | + | 44 | |
75 | #ifdef CONFIG_SOFTMMU | 45 | /* extu_tl_i64 */ |
76 | - /* x0 and x1 will be overwritten when reading the tlb entry, | ||
77 | - and x2, and x3 for helper args, better to avoid using them. */ | ||
78 | - tcg_regset_reset_reg(ct->regs, TCG_REG_X0); | ||
79 | - tcg_regset_reset_reg(ct->regs, TCG_REG_X1); | ||
80 | - tcg_regset_reset_reg(ct->regs, TCG_REG_X2); | ||
81 | - tcg_regset_reset_reg(ct->regs, TCG_REG_X3); | ||
82 | +#define ALL_QLDST_REGS \ | ||
83 | + (ALL_GENERAL_REGS & ~((1 << TCG_REG_X0) | (1 << TCG_REG_X1) | \ | ||
84 | + (1 << TCG_REG_X2) | (1 << TCG_REG_X3))) | ||
85 | +#else | ||
86 | +#define ALL_QLDST_REGS ALL_GENERAL_REGS | ||
87 | #endif | ||
88 | - break; | ||
89 | - case 'A': /* Valid for arithmetic immediate (positive or negative). */ | ||
90 | - ct->ct |= TCG_CT_CONST_AIMM; | ||
91 | - break; | ||
92 | - case 'L': /* Valid for logical immediate. */ | ||
93 | - ct->ct |= TCG_CT_CONST_LIMM; | ||
94 | - break; | ||
95 | - case 'M': /* minus one */ | ||
96 | - ct->ct |= TCG_CT_CONST_MONE; | ||
97 | - break; | ||
98 | - case 'O': /* vector orr/bic immediate */ | ||
99 | - ct->ct |= TCG_CT_CONST_ORRI; | ||
100 | - break; | ||
101 | - case 'N': /* vector orr/bic immediate, inverted */ | ||
102 | - ct->ct |= TCG_CT_CONST_ANDI; | ||
103 | - break; | ||
104 | - case 'Z': /* zero */ | ||
105 | - ct->ct |= TCG_CT_CONST_ZERO; | ||
106 | - break; | ||
107 | - default: | ||
108 | - return NULL; | ||
109 | - } | ||
110 | - return ct_str; | ||
111 | -} | ||
112 | |||
113 | /* Match a constant valid for addition (12-bit, optionally shifted). */ | ||
114 | static inline bool is_aimm(uint64_t val) | ||
115 | -- | 46 | -- |
116 | 2.25.1 | 47 | 2.34.1 |
117 | 48 | ||
118 | 49 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | From: Philippe Mathieu-Daudé <philmd@linaro.org> | |
2 | |||
3 | In order to have variable size allocated TCGOp, pass the number | ||
4 | of arguments we use (and would allocate) up to tcg_op_alloc(). | ||
5 | |||
6 | This alters tcg_emit_op(), tcg_op_insert_before() and | ||
7 | tcg_op_insert_after() prototypes. | ||
8 | |||
9 | In tcg_op_alloc() ensure the number of arguments is in range. | ||
10 | |||
11 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
12 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
13 | [PMD: Extracted from bigger patch] | ||
14 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
15 | Message-Id: <20221218211832.73312-2-philmd@linaro.org> | ||
16 | --- | ||
17 | include/tcg/tcg-op.h | 2 +- | ||
18 | include/tcg/tcg.h | 8 +++++--- | ||
19 | accel/tcg/plugin-gen.c | 5 ++++- | ||
20 | tcg/optimize.c | 4 ++-- | ||
21 | tcg/tcg-op-vec.c | 8 ++++---- | ||
22 | tcg/tcg-op.c | 12 ++++++------ | ||
23 | tcg/tcg.c | 30 +++++++++++++++++------------- | ||
24 | 7 files changed, 39 insertions(+), 30 deletions(-) | ||
25 | |||
26 | diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h | ||
27 | index XXXXXXX..XXXXXXX 100644 | ||
28 | --- a/include/tcg/tcg-op.h | ||
29 | +++ b/include/tcg/tcg-op.h | ||
30 | @@ -XXX,XX +XXX,XX @@ static inline void tcg_gen_plugin_cb_start(unsigned from, unsigned type, | ||
31 | |||
32 | static inline void tcg_gen_plugin_cb_end(void) | ||
33 | { | ||
34 | - tcg_emit_op(INDEX_op_plugin_cb_end); | ||
35 | + tcg_emit_op(INDEX_op_plugin_cb_end, 0); | ||
36 | } | ||
37 | |||
38 | #if TARGET_LONG_BITS == 32 | ||
39 | diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h | ||
40 | index XXXXXXX..XXXXXXX 100644 | ||
41 | --- a/include/tcg/tcg.h | ||
42 | +++ b/include/tcg/tcg.h | ||
43 | @@ -XXX,XX +XXX,XX @@ bool tcg_op_supported(TCGOpcode op); | ||
44 | |||
45 | void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args); | ||
46 | |||
47 | -TCGOp *tcg_emit_op(TCGOpcode opc); | ||
48 | +TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs); | ||
49 | void tcg_op_remove(TCGContext *s, TCGOp *op); | ||
50 | -TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *op, TCGOpcode opc); | ||
51 | -TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op, TCGOpcode opc); | ||
52 | +TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *op, | ||
53 | + TCGOpcode opc, unsigned nargs); | ||
54 | +TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op, | ||
55 | + TCGOpcode opc, unsigned nargs); | ||
56 | |||
57 | /** | ||
58 | * tcg_remove_ops_after: | ||
59 | diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c | ||
60 | index XXXXXXX..XXXXXXX 100644 | ||
61 | --- a/accel/tcg/plugin-gen.c | ||
62 | +++ b/accel/tcg/plugin-gen.c | ||
63 | @@ -XXX,XX +XXX,XX @@ static TCGOp *rm_ops(TCGOp *op) | ||
64 | |||
65 | static TCGOp *copy_op_nocheck(TCGOp **begin_op, TCGOp *op) | ||
66 | { | ||
67 | + unsigned nargs = ARRAY_SIZE(op->args); | ||
68 | + | ||
69 | *begin_op = QTAILQ_NEXT(*begin_op, link); | ||
70 | tcg_debug_assert(*begin_op); | ||
71 | - op = tcg_op_insert_after(tcg_ctx, op, (*begin_op)->opc); | ||
72 | + op = tcg_op_insert_after(tcg_ctx, op, (*begin_op)->opc, nargs); | ||
73 | memcpy(op->args, (*begin_op)->args, sizeof(op->args)); | ||
74 | + | ||
75 | return op; | ||
76 | } | ||
77 | |||
78 | diff --git a/tcg/optimize.c b/tcg/optimize.c | ||
79 | index XXXXXXX..XXXXXXX 100644 | ||
80 | --- a/tcg/optimize.c | ||
81 | +++ b/tcg/optimize.c | ||
82 | @@ -XXX,XX +XXX,XX @@ static bool fold_addsub2(OptContext *ctx, TCGOp *op, bool add) | ||
83 | rh = op->args[1]; | ||
84 | |||
85 | /* The proper opcode is supplied by tcg_opt_gen_mov. */ | ||
86 | - op2 = tcg_op_insert_before(ctx->tcg, op, 0); | ||
87 | + op2 = tcg_op_insert_before(ctx->tcg, op, 0, 2); | ||
88 | |||
89 | tcg_opt_gen_movi(ctx, op, rl, al); | ||
90 | tcg_opt_gen_movi(ctx, op2, rh, ah); | ||
91 | @@ -XXX,XX +XXX,XX @@ static bool fold_multiply2(OptContext *ctx, TCGOp *op) | ||
92 | rh = op->args[1]; | ||
93 | |||
94 | /* The proper opcode is supplied by tcg_opt_gen_mov. */ | ||
95 | - op2 = tcg_op_insert_before(ctx->tcg, op, 0); | ||
96 | + op2 = tcg_op_insert_before(ctx->tcg, op, 0, 2); | ||
97 | |||
98 | tcg_opt_gen_movi(ctx, op, rl, l); | ||
99 | tcg_opt_gen_movi(ctx, op2, rh, h); | ||
100 | diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c | ||
101 | index XXXXXXX..XXXXXXX 100644 | ||
102 | --- a/tcg/tcg-op-vec.c | ||
103 | +++ b/tcg/tcg-op-vec.c | ||
104 | @@ -XXX,XX +XXX,XX @@ bool tcg_can_emit_vecop_list(const TCGOpcode *list, | ||
105 | |||
106 | void vec_gen_2(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r, TCGArg a) | ||
107 | { | ||
108 | - TCGOp *op = tcg_emit_op(opc); | ||
109 | + TCGOp *op = tcg_emit_op(opc, 2); | ||
110 | TCGOP_VECL(op) = type - TCG_TYPE_V64; | ||
111 | TCGOP_VECE(op) = vece; | ||
112 | op->args[0] = r; | ||
113 | @@ -XXX,XX +XXX,XX @@ void vec_gen_2(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r, TCGArg a) | ||
114 | void vec_gen_3(TCGOpcode opc, TCGType type, unsigned vece, | ||
115 | TCGArg r, TCGArg a, TCGArg b) | ||
116 | { | ||
117 | - TCGOp *op = tcg_emit_op(opc); | ||
118 | + TCGOp *op = tcg_emit_op(opc, 3); | ||
119 | TCGOP_VECL(op) = type - TCG_TYPE_V64; | ||
120 | TCGOP_VECE(op) = vece; | ||
121 | op->args[0] = r; | ||
122 | @@ -XXX,XX +XXX,XX @@ void vec_gen_3(TCGOpcode opc, TCGType type, unsigned vece, | ||
123 | void vec_gen_4(TCGOpcode opc, TCGType type, unsigned vece, | ||
124 | TCGArg r, TCGArg a, TCGArg b, TCGArg c) | ||
125 | { | ||
126 | - TCGOp *op = tcg_emit_op(opc); | ||
127 | + TCGOp *op = tcg_emit_op(opc, 4); | ||
128 | TCGOP_VECL(op) = type - TCG_TYPE_V64; | ||
129 | TCGOP_VECE(op) = vece; | ||
130 | op->args[0] = r; | ||
131 | @@ -XXX,XX +XXX,XX @@ void vec_gen_4(TCGOpcode opc, TCGType type, unsigned vece, | ||
132 | static void vec_gen_6(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r, | ||
133 | TCGArg a, TCGArg b, TCGArg c, TCGArg d, TCGArg e) | ||
134 | { | ||
135 | - TCGOp *op = tcg_emit_op(opc); | ||
136 | + TCGOp *op = tcg_emit_op(opc, 6); | ||
137 | TCGOP_VECL(op) = type - TCG_TYPE_V64; | ||
138 | TCGOP_VECE(op) = vece; | ||
139 | op->args[0] = r; | ||
140 | diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c | ||
141 | index XXXXXXX..XXXXXXX 100644 | ||
142 | --- a/tcg/tcg-op.c | ||
143 | +++ b/tcg/tcg-op.c | ||
144 | @@ -XXX,XX +XXX,XX @@ | ||
145 | |||
146 | void tcg_gen_op1(TCGOpcode opc, TCGArg a1) | ||
147 | { | ||
148 | - TCGOp *op = tcg_emit_op(opc); | ||
149 | + TCGOp *op = tcg_emit_op(opc, 1); | ||
150 | op->args[0] = a1; | ||
151 | } | ||
152 | |||
153 | void tcg_gen_op2(TCGOpcode opc, TCGArg a1, TCGArg a2) | ||
154 | { | ||
155 | - TCGOp *op = tcg_emit_op(opc); | ||
156 | + TCGOp *op = tcg_emit_op(opc, 2); | ||
157 | op->args[0] = a1; | ||
158 | op->args[1] = a2; | ||
159 | } | ||
160 | |||
161 | void tcg_gen_op3(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3) | ||
162 | { | ||
163 | - TCGOp *op = tcg_emit_op(opc); | ||
164 | + TCGOp *op = tcg_emit_op(opc, 3); | ||
165 | op->args[0] = a1; | ||
166 | op->args[1] = a2; | ||
167 | op->args[2] = a3; | ||
168 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_op3(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3) | ||
169 | |||
170 | void tcg_gen_op4(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, TCGArg a4) | ||
171 | { | ||
172 | - TCGOp *op = tcg_emit_op(opc); | ||
173 | + TCGOp *op = tcg_emit_op(opc, 4); | ||
174 | op->args[0] = a1; | ||
175 | op->args[1] = a2; | ||
176 | op->args[2] = a3; | ||
177 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_op4(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, TCGArg a4) | ||
178 | void tcg_gen_op5(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, | ||
179 | TCGArg a4, TCGArg a5) | ||
180 | { | ||
181 | - TCGOp *op = tcg_emit_op(opc); | ||
182 | + TCGOp *op = tcg_emit_op(opc, 5); | ||
183 | op->args[0] = a1; | ||
184 | op->args[1] = a2; | ||
185 | op->args[2] = a3; | ||
186 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_op5(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, | ||
187 | void tcg_gen_op6(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, | ||
188 | TCGArg a4, TCGArg a5, TCGArg a6) | ||
189 | { | ||
190 | - TCGOp *op = tcg_emit_op(opc); | ||
191 | + TCGOp *op = tcg_emit_op(opc, 6); | ||
192 | op->args[0] = a1; | ||
193 | op->args[1] = a2; | ||
194 | op->args[2] = a3; | ||
195 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
196 | index XXXXXXX..XXXXXXX 100644 | ||
197 | --- a/tcg/tcg.c | ||
198 | +++ b/tcg/tcg.c | ||
199 | @@ -XXX,XX +XXX,XX @@ bool tcg_op_supported(TCGOpcode op) | ||
200 | and endian swap in tcg_reg_alloc_call(). */ | ||
201 | void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
202 | { | ||
203 | - int i, real_args, nb_rets, pi; | ||
204 | + int i, real_args, nb_rets, pi, max_args; | ||
205 | unsigned typemask; | ||
206 | const TCGHelperInfo *info; | ||
207 | TCGOp *op; | ||
208 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
209 | } | ||
210 | } | ||
211 | |||
212 | - op = tcg_emit_op(INDEX_op_call); | ||
213 | + max_args = ARRAY_SIZE(op->args); | ||
214 | + op = tcg_emit_op(INDEX_op_call, max_args); | ||
215 | |||
216 | pi = 0; | ||
217 | if (ret != NULL) { | ||
218 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
219 | |||
220 | /* Make sure the fields didn't overflow. */ | ||
221 | tcg_debug_assert(TCGOP_CALLI(op) == real_args); | ||
222 | - tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); | ||
223 | + tcg_debug_assert(pi <= max_args); | ||
224 | |||
225 | if (TCG_TARGET_CALL_ARG_I32 == TCG_CALL_ARG_EXTEND) { | ||
226 | for (i = 0; i < nargs; ++i) { | ||
227 | @@ -XXX,XX +XXX,XX @@ void tcg_remove_ops_after(TCGOp *op) | ||
228 | } | ||
229 | } | ||
230 | |||
231 | -static TCGOp *tcg_op_alloc(TCGOpcode opc) | ||
232 | +static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) | ||
233 | { | ||
234 | TCGContext *s = tcg_ctx; | ||
235 | TCGOp *op; | ||
236 | |||
237 | + assert(nargs < ARRAY_SIZE(op->args)); | ||
238 | if (likely(QTAILQ_EMPTY(&s->free_ops))) { | ||
239 | op = tcg_malloc(sizeof(TCGOp)); | ||
240 | } else { | ||
241 | @@ -XXX,XX +XXX,XX @@ static TCGOp *tcg_op_alloc(TCGOpcode opc) | ||
242 | return op; | ||
243 | } | ||
244 | |||
245 | -TCGOp *tcg_emit_op(TCGOpcode opc) | ||
246 | +TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) | ||
247 | { | ||
248 | - TCGOp *op = tcg_op_alloc(opc); | ||
249 | + TCGOp *op = tcg_op_alloc(opc, nargs); | ||
250 | QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); | ||
251 | return op; | ||
252 | } | ||
253 | |||
254 | -TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc) | ||
255 | +TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, | ||
256 | + TCGOpcode opc, unsigned nargs) | ||
257 | { | ||
258 | - TCGOp *new_op = tcg_op_alloc(opc); | ||
259 | + TCGOp *new_op = tcg_op_alloc(opc, nargs); | ||
260 | QTAILQ_INSERT_BEFORE(old_op, new_op, link); | ||
261 | return new_op; | ||
262 | } | ||
263 | |||
264 | -TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc) | ||
265 | +TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, | ||
266 | + TCGOpcode opc, unsigned nargs) | ||
267 | { | ||
268 | - TCGOp *new_op = tcg_op_alloc(opc); | ||
269 | + TCGOp *new_op = tcg_op_alloc(opc, nargs); | ||
270 | QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); | ||
271 | return new_op; | ||
272 | } | ||
273 | @@ -XXX,XX +XXX,XX @@ static bool liveness_pass_2(TCGContext *s) | ||
274 | TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 | ||
275 | ? INDEX_op_ld_i32 | ||
276 | : INDEX_op_ld_i64); | ||
277 | - TCGOp *lop = tcg_op_insert_before(s, op, lopc); | ||
278 | + TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); | ||
279 | |||
280 | lop->args[0] = temp_arg(dir_ts); | ||
281 | lop->args[1] = temp_arg(arg_ts->mem_base); | ||
282 | @@ -XXX,XX +XXX,XX @@ static bool liveness_pass_2(TCGContext *s) | ||
283 | TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 | ||
284 | ? INDEX_op_st_i32 | ||
285 | : INDEX_op_st_i64); | ||
286 | - TCGOp *sop = tcg_op_insert_after(s, op, sopc); | ||
287 | + TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); | ||
288 | TCGTemp *out_ts = dir_ts; | ||
289 | |||
290 | if (IS_DEAD_ARG(0)) { | ||
291 | @@ -XXX,XX +XXX,XX @@ static bool liveness_pass_2(TCGContext *s) | ||
292 | TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 | ||
293 | ? INDEX_op_st_i32 | ||
294 | : INDEX_op_st_i64); | ||
295 | - TCGOp *sop = tcg_op_insert_after(s, op, sopc); | ||
296 | + TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); | ||
297 | |||
298 | sop->args[0] = temp_arg(dir_ts); | ||
299 | sop->args[1] = temp_arg(arg_ts->mem_base); | ||
300 | -- | ||
301 | 2.34.1 | ||
302 | |||
303 | diff view generated by jsdifflib |
1 | Rather than check the type when filling in the constraint, | 1 | We have been allocating a worst case number of arguments |
---|---|---|---|
2 | check it when matching the constant. This removes the only | 2 | to support calls. Instead, allow the size to vary. |
3 | use of the type argument to target_parse_constraint. | 3 | By default leave space for 4 args, to maximize reuse, |
4 | but allow calls to increase the number of args to 32. | ||
4 | 5 | ||
5 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
7 | [PMD: Split patch in two] | ||
8 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
9 | Message-Id: <20221218211832.73312-3-philmd@linaro.org> | ||
7 | --- | 10 | --- |
8 | tcg/i386/tcg-target.c.inc | 28 +++++++++++++++++----------- | 11 | include/exec/helper-head.h | 2 -- |
9 | 1 file changed, 17 insertions(+), 11 deletions(-) | 12 | include/tcg/tcg.h | 46 +++++++++++++------------------------- |
13 | accel/tcg/plugin-gen.c | 10 ++++----- | ||
14 | tcg/tcg.c | 35 +++++++++++++++++++++-------- | ||
15 | 4 files changed, 47 insertions(+), 46 deletions(-) | ||
10 | 16 | ||
11 | diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc | 17 | diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h |
12 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/tcg/i386/tcg-target.c.inc | 19 | --- a/include/exec/helper-head.h |
14 | +++ b/tcg/i386/tcg-target.c.inc | 20 | +++ b/include/exec/helper-head.h |
15 | @@ -XXX,XX +XXX,XX @@ static const char *target_parse_constraint(TCGArgConstraint *ct, | 21 | @@ -XXX,XX +XXX,XX @@ |
16 | break; | 22 | #define DEF_HELPER_7(name, ret, t1, t2, t3, t4, t5, t6, t7) \ |
17 | 23 | DEF_HELPER_FLAGS_7(name, 0, ret, t1, t2, t3, t4, t5, t6, t7) | |
18 | case 'e': | 24 | |
19 | - ct->ct |= (type == TCG_TYPE_I32 ? TCG_CT_CONST : TCG_CT_CONST_S32); | 25 | -/* MAX_OPC_PARAM_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */ |
20 | + ct->ct |= TCG_CT_CONST_S32; | 26 | - |
21 | break; | 27 | #endif /* EXEC_HELPER_HEAD_H */ |
22 | case 'Z': | 28 | diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h |
23 | - ct->ct |= (type == TCG_TYPE_I32 ? TCG_CT_CONST : TCG_CT_CONST_U32); | 29 | index XXXXXXX..XXXXXXX 100644 |
24 | + ct->ct |= TCG_CT_CONST_U32; | 30 | --- a/include/tcg/tcg.h |
25 | break; | 31 | +++ b/include/tcg/tcg.h |
26 | case 'I': | 32 | @@ -XXX,XX +XXX,XX @@ |
27 | - ct->ct |= (type == TCG_TYPE_I32 ? TCG_CT_CONST : TCG_CT_CONST_I32); | 33 | /* XXX: make safe guess about sizes */ |
28 | + ct->ct |= TCG_CT_CONST_I32; | 34 | #define MAX_OP_PER_INSTR 266 |
29 | break; | 35 | |
30 | 36 | -#if HOST_LONG_BITS == 32 | |
31 | default: | 37 | -#define MAX_OPC_PARAM_PER_ARG 2 |
32 | @@ -XXX,XX +XXX,XX @@ static inline int tcg_target_const_match(tcg_target_long val, TCGType type, | 38 | -#else |
33 | if (ct & TCG_CT_CONST) { | 39 | -#define MAX_OPC_PARAM_PER_ARG 1 |
34 | return 1; | 40 | -#endif |
41 | -#define MAX_OPC_PARAM_IARGS 7 | ||
42 | -#define MAX_OPC_PARAM_OARGS 1 | ||
43 | -#define MAX_OPC_PARAM_ARGS (MAX_OPC_PARAM_IARGS + MAX_OPC_PARAM_OARGS) | ||
44 | - | ||
45 | -/* A Call op needs up to 4 + 2N parameters on 32-bit archs, | ||
46 | - * and up to 4 + N parameters on 64-bit archs | ||
47 | - * (N = number of input arguments + output arguments). */ | ||
48 | -#define MAX_OPC_PARAM (4 + (MAX_OPC_PARAM_PER_ARG * MAX_OPC_PARAM_ARGS)) | ||
49 | - | ||
50 | #define CPU_TEMP_BUF_NLONGS 128 | ||
51 | #define TCG_STATIC_FRAME_SIZE (CPU_TEMP_BUF_NLONGS * sizeof(long)) | ||
52 | |||
53 | @@ -XXX,XX +XXX,XX @@ typedef struct TCGTempSet { | ||
54 | unsigned long l[BITS_TO_LONGS(TCG_MAX_TEMPS)]; | ||
55 | } TCGTempSet; | ||
56 | |||
57 | -/* While we limit helpers to 6 arguments, for 32-bit hosts, with padding, | ||
58 | - this imples a max of 6*2 (64-bit in) + 2 (64-bit out) = 14 operands. | ||
59 | - There are never more than 2 outputs, which means that we can store all | ||
60 | - dead + sync data within 16 bits. */ | ||
61 | -#define DEAD_ARG 4 | ||
62 | -#define SYNC_ARG 1 | ||
63 | -typedef uint16_t TCGLifeData; | ||
64 | +/* | ||
65 | + * With 1 128-bit output, a 32-bit host requires 4 output parameters, | ||
66 | + * which leaves a maximum of 28 other slots. Which is enough for 7 | ||
67 | + * 128-bit operands. | ||
68 | + */ | ||
69 | +#define DEAD_ARG (1 << 4) | ||
70 | +#define SYNC_ARG (1 << 0) | ||
71 | +typedef uint32_t TCGLifeData; | ||
72 | |||
73 | -/* The layout here is designed to avoid a bitfield crossing of | ||
74 | - a 32-bit boundary, which would cause GCC to add extra padding. */ | ||
75 | typedef struct TCGOp { | ||
76 | - TCGOpcode opc : 8; /* 8 */ | ||
77 | + TCGOpcode opc : 8; | ||
78 | + unsigned nargs : 8; | ||
79 | |||
80 | /* Parameters for this opcode. See below. */ | ||
81 | - unsigned param1 : 4; /* 12 */ | ||
82 | - unsigned param2 : 4; /* 16 */ | ||
83 | + unsigned param1 : 8; | ||
84 | + unsigned param2 : 8; | ||
85 | |||
86 | /* Lifetime data of the operands. */ | ||
87 | - unsigned life : 16; /* 32 */ | ||
88 | + TCGLifeData life; | ||
89 | |||
90 | /* Next and previous opcodes. */ | ||
91 | QTAILQ_ENTRY(TCGOp) link; | ||
92 | |||
93 | - /* Arguments for the opcode. */ | ||
94 | - TCGArg args[MAX_OPC_PARAM]; | ||
95 | - | ||
96 | /* Register preferences for the output(s). */ | ||
97 | TCGRegSet output_pref[2]; | ||
98 | + | ||
99 | + /* Arguments for the opcode. */ | ||
100 | + TCGArg args[]; | ||
101 | } TCGOp; | ||
102 | |||
103 | #define TCGOP_CALLI(X) (X)->param1 | ||
104 | diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c | ||
105 | index XXXXXXX..XXXXXXX 100644 | ||
106 | --- a/accel/tcg/plugin-gen.c | ||
107 | +++ b/accel/tcg/plugin-gen.c | ||
108 | @@ -XXX,XX +XXX,XX @@ static TCGOp *rm_ops(TCGOp *op) | ||
109 | |||
110 | static TCGOp *copy_op_nocheck(TCGOp **begin_op, TCGOp *op) | ||
111 | { | ||
112 | - unsigned nargs = ARRAY_SIZE(op->args); | ||
113 | + TCGOp *old_op = QTAILQ_NEXT(*begin_op, link); | ||
114 | + unsigned nargs = old_op->nargs; | ||
115 | |||
116 | - *begin_op = QTAILQ_NEXT(*begin_op, link); | ||
117 | - tcg_debug_assert(*begin_op); | ||
118 | - op = tcg_op_insert_after(tcg_ctx, op, (*begin_op)->opc, nargs); | ||
119 | - memcpy(op->args, (*begin_op)->args, sizeof(op->args)); | ||
120 | + *begin_op = old_op; | ||
121 | + op = tcg_op_insert_after(tcg_ctx, op, old_op->opc, nargs); | ||
122 | + memcpy(op->args, old_op->args, sizeof(op->args[0]) * nargs); | ||
123 | |||
124 | return op; | ||
125 | } | ||
126 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
127 | index XXXXXXX..XXXXXXX 100644 | ||
128 | --- a/tcg/tcg.c | ||
129 | +++ b/tcg/tcg.c | ||
130 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
131 | } | ||
35 | } | 132 | } |
36 | - if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) { | 133 | |
37 | - return 1; | 134 | - max_args = ARRAY_SIZE(op->args); |
38 | - } | 135 | + /* |
39 | - if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val) { | 136 | + * A Call op needs up to 4 + 2N parameters on 32-bit archs, |
40 | - return 1; | 137 | + * and up to 4 + N parameters on 64-bit archs |
41 | - } | 138 | + * (N = number of input arguments + output arguments). |
42 | - if ((ct & TCG_CT_CONST_I32) && ~val == (int32_t)~val) { | 139 | + */ |
43 | - return 1; | 140 | + max_args = (64 / TCG_TARGET_REG_BITS) * nargs + 4; |
44 | + if (type == TCG_TYPE_I32) { | 141 | op = tcg_emit_op(INDEX_op_call, max_args); |
45 | + if (ct & (TCG_CT_CONST_S32 | TCG_CT_CONST_U32 | TCG_CT_CONST_I32)) { | 142 | |
46 | + return 1; | 143 | pi = 0; |
47 | + } | 144 | @@ -XXX,XX +XXX,XX @@ void tcg_remove_ops_after(TCGOp *op) |
48 | + } else { | 145 | static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs) |
49 | + if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) { | 146 | { |
50 | + return 1; | 147 | TCGContext *s = tcg_ctx; |
51 | + } | 148 | - TCGOp *op; |
52 | + if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val) { | 149 | + TCGOp *op = NULL; |
53 | + return 1; | 150 | |
54 | + } | 151 | - assert(nargs < ARRAY_SIZE(op->args)); |
55 | + if ((ct & TCG_CT_CONST_I32) && ~val == (int32_t)~val) { | 152 | - if (likely(QTAILQ_EMPTY(&s->free_ops))) { |
56 | + return 1; | 153 | - op = tcg_malloc(sizeof(TCGOp)); |
154 | - } else { | ||
155 | - op = QTAILQ_FIRST(&s->free_ops); | ||
156 | - QTAILQ_REMOVE(&s->free_ops, op, link); | ||
157 | + if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) { | ||
158 | + QTAILQ_FOREACH(op, &s->free_ops, link) { | ||
159 | + if (nargs <= op->nargs) { | ||
160 | + QTAILQ_REMOVE(&s->free_ops, op, link); | ||
161 | + nargs = op->nargs; | ||
162 | + goto found; | ||
163 | + } | ||
57 | + } | 164 | + } |
58 | } | 165 | } |
59 | if ((ct & TCG_CT_CONST_WSZ) && val == (type == TCG_TYPE_I32 ? 32 : 64)) { | 166 | + |
60 | return 1; | 167 | + /* Most opcodes have 3 or 4 operands: reduce fragmentation. */ |
168 | + nargs = MAX(4, nargs); | ||
169 | + op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs); | ||
170 | + | ||
171 | + found: | ||
172 | memset(op, 0, offsetof(TCGOp, link)); | ||
173 | op->opc = opc; | ||
174 | - s->nb_ops++; | ||
175 | + op->nargs = nargs; | ||
176 | |||
177 | + /* Check for bitfield overflow. */ | ||
178 | + tcg_debug_assert(op->nargs == nargs); | ||
179 | + | ||
180 | + s->nb_ops++; | ||
181 | return op; | ||
182 | } | ||
183 | |||
61 | -- | 184 | -- |
62 | 2.25.1 | 185 | 2.34.1 |
63 | 186 | ||
64 | 187 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | We will shortly have the possibility of more that two outputs, |
---|---|---|---|
2 | though only for calls (for which preferences are moot). Avoid | ||
3 | direct references to op->output_pref[] when possible. | ||
4 | |||
5 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 7 | --- |
4 | tcg/sparc/tcg-target-con-set.h | 32 +++++++++++++++ | 8 | include/tcg/tcg.h | 5 +++++ |
5 | tcg/sparc/tcg-target.h | 1 + | 9 | tcg/tcg.c | 34 ++++++++++++++++++---------------- |
6 | tcg/sparc/tcg-target.c.inc | 75 +++++++++++----------------------- | 10 | 2 files changed, 23 insertions(+), 16 deletions(-) |
7 | 3 files changed, 56 insertions(+), 52 deletions(-) | ||
8 | create mode 100644 tcg/sparc/tcg-target-con-set.h | ||
9 | 11 | ||
10 | diff --git a/tcg/sparc/tcg-target-con-set.h b/tcg/sparc/tcg-target-con-set.h | 12 | diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h |
11 | new file mode 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
12 | index XXXXXXX..XXXXXXX | 14 | --- a/include/tcg/tcg.h |
13 | --- /dev/null | 15 | +++ b/include/tcg/tcg.h |
14 | +++ b/tcg/sparc/tcg-target-con-set.h | 16 | @@ -XXX,XX +XXX,XX @@ typedef struct TCGOp { |
15 | @@ -XXX,XX +XXX,XX @@ | 17 | /* Make sure operands fit in the bitfields above. */ |
16 | +/* SPDX-License-Identifier: MIT */ | 18 | QEMU_BUILD_BUG_ON(NB_OPS > (1 << 8)); |
17 | +/* | 19 | |
18 | + * Define Sparc target-specific constraint sets. | 20 | +static inline TCGRegSet output_pref(const TCGOp *op, unsigned i) |
19 | + * Copyright (c) 2021 Linaro | 21 | +{ |
20 | + */ | 22 | + return i < ARRAY_SIZE(op->output_pref) ? op->output_pref[i] : 0; |
23 | +} | ||
21 | + | 24 | + |
22 | +/* | 25 | typedef struct TCGProfile { |
23 | + * C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs. | 26 | int64_t cpu_exec_time; |
24 | + * Each operand should be a sequence of constraint letters as defined by | 27 | int64_t tb_count1; |
25 | + * tcg-target-con-str.h; the constraint combination is inclusive or. | 28 | diff --git a/tcg/tcg.c b/tcg/tcg.c |
26 | + */ | ||
27 | +C_O0_I1(r) | ||
28 | +C_O0_I2(rZ, r) | ||
29 | +C_O0_I2(RZ, r) | ||
30 | +C_O0_I2(rZ, rJ) | ||
31 | +C_O0_I2(RZ, RJ) | ||
32 | +C_O0_I2(sZ, A) | ||
33 | +C_O0_I2(SZ, A) | ||
34 | +C_O1_I1(r, A) | ||
35 | +C_O1_I1(R, A) | ||
36 | +C_O1_I1(r, r) | ||
37 | +C_O1_I1(r, R) | ||
38 | +C_O1_I1(R, r) | ||
39 | +C_O1_I1(R, R) | ||
40 | +C_O1_I2(R, R, R) | ||
41 | +C_O1_I2(r, rZ, rJ) | ||
42 | +C_O1_I2(R, RZ, RJ) | ||
43 | +C_O1_I4(r, rZ, rJ, rI, 0) | ||
44 | +C_O1_I4(R, RZ, RJ, RI, 0) | ||
45 | +C_O2_I2(r, r, rZ, rJ) | ||
46 | +C_O2_I4(R, R, RZ, RZ, RJ, RI) | ||
47 | +C_O2_I4(r, r, rZ, rZ, rJ, rJ) | ||
48 | diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h | ||
49 | index XXXXXXX..XXXXXXX 100644 | 29 | index XXXXXXX..XXXXXXX 100644 |
50 | --- a/tcg/sparc/tcg-target.h | 30 | --- a/tcg/tcg.c |
51 | +++ b/tcg/sparc/tcg-target.h | 31 | +++ b/tcg/tcg.c |
52 | @@ -XXX,XX +XXX,XX @@ extern bool use_vis3_instructions; | 32 | @@ -XXX,XX +XXX,XX @@ static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) |
53 | void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 33 | |
54 | 34 | if (have_prefs) { | |
55 | #define TCG_TARGET_NEED_POOL_LABELS | 35 | for (i = 0; i < nb_oargs; ++i) { |
56 | +#define TCG_TARGET_CON_SET_H | 36 | - TCGRegSet set = op->output_pref[i]; |
57 | 37 | + TCGRegSet set = output_pref(op, i); | |
58 | #endif | 38 | |
59 | diff --git a/tcg/sparc/tcg-target.c.inc b/tcg/sparc/tcg-target.c.inc | 39 | if (i == 0) { |
60 | index XXXXXXX..XXXXXXX 100644 | 40 | ne_fprintf(f, " pref="); |
61 | --- a/tcg/sparc/tcg-target.c.inc | 41 | @@ -XXX,XX +XXX,XX @@ static void liveness_pass_1(TCGContext *s) |
62 | +++ b/tcg/sparc/tcg-target.c.inc | 42 | } |
63 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, | 43 | ts->state = TS_DEAD; |
44 | la_reset_pref(ts); | ||
45 | - | ||
46 | - /* Not used -- it will be tcg_target_call_oarg_regs[i]. */ | ||
47 | - op->output_pref[i] = 0; | ||
48 | } | ||
49 | |||
50 | + /* Not used -- it will be tcg_target_call_oarg_reg(). */ | ||
51 | + memset(op->output_pref, 0, sizeof(op->output_pref)); | ||
52 | + | ||
53 | if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | | ||
54 | TCG_CALL_NO_READ_GLOBALS))) { | ||
55 | la_global_kill(s, nb_globals); | ||
56 | @@ -XXX,XX +XXX,XX @@ static void liveness_pass_1(TCGContext *s) | ||
57 | ts = arg_temp(op->args[i]); | ||
58 | |||
59 | /* Remember the preference of the uses that followed. */ | ||
60 | - op->output_pref[i] = *la_temp_pref(ts); | ||
61 | + if (i < ARRAY_SIZE(op->output_pref)) { | ||
62 | + op->output_pref[i] = *la_temp_pref(ts); | ||
63 | + } | ||
64 | |||
65 | /* Output args are dead. */ | ||
66 | if (ts->state & TS_DEAD) { | ||
67 | @@ -XXX,XX +XXX,XX @@ static void liveness_pass_1(TCGContext *s) | ||
68 | |||
69 | set &= ct->regs; | ||
70 | if (ct->ialias) { | ||
71 | - set &= op->output_pref[ct->alias_index]; | ||
72 | + set &= output_pref(op, ct->alias_index); | ||
73 | } | ||
74 | /* If the combination is not possible, restart. */ | ||
75 | if (set == 0) { | ||
76 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) | ||
77 | TCGReg oreg, ireg; | ||
78 | |||
79 | allocated_regs = s->reserved_regs; | ||
80 | - preferred_regs = op->output_pref[0]; | ||
81 | + preferred_regs = output_pref(op, 0); | ||
82 | ots = arg_temp(op->args[0]); | ||
83 | ts = arg_temp(op->args[1]); | ||
84 | |||
85 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) | ||
86 | if (IS_DEAD_ARG(1)) { | ||
87 | temp_dead(s, its); | ||
88 | } | ||
89 | - tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]); | ||
90 | + tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0)); | ||
91 | return; | ||
64 | } | 92 | } |
65 | } | 93 | |
66 | 94 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) | |
67 | -static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | 95 | tcg_regset_set_reg(allocated_regs, its->reg); |
68 | +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) | 96 | } |
69 | { | 97 | oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, |
70 | - static const TCGTargetOpDef r = { .args_ct_str = { "r" } }; | 98 | - op->output_pref[0], ots->indirect_base); |
71 | - static const TCGTargetOpDef r_r = { .args_ct_str = { "r", "r" } }; | 99 | + output_pref(op, 0), ots->indirect_base); |
72 | - static const TCGTargetOpDef R_r = { .args_ct_str = { "R", "r" } }; | 100 | set_temp_val_reg(s, ots, oreg); |
73 | - static const TCGTargetOpDef r_R = { .args_ct_str = { "r", "R" } }; | ||
74 | - static const TCGTargetOpDef R_R = { .args_ct_str = { "R", "R" } }; | ||
75 | - static const TCGTargetOpDef r_A = { .args_ct_str = { "r", "A" } }; | ||
76 | - static const TCGTargetOpDef R_A = { .args_ct_str = { "R", "A" } }; | ||
77 | - static const TCGTargetOpDef rZ_r = { .args_ct_str = { "rZ", "r" } }; | ||
78 | - static const TCGTargetOpDef RZ_r = { .args_ct_str = { "RZ", "r" } }; | ||
79 | - static const TCGTargetOpDef sZ_A = { .args_ct_str = { "sZ", "A" } }; | ||
80 | - static const TCGTargetOpDef SZ_A = { .args_ct_str = { "SZ", "A" } }; | ||
81 | - static const TCGTargetOpDef rZ_rJ = { .args_ct_str = { "rZ", "rJ" } }; | ||
82 | - static const TCGTargetOpDef RZ_RJ = { .args_ct_str = { "RZ", "RJ" } }; | ||
83 | - static const TCGTargetOpDef R_R_R = { .args_ct_str = { "R", "R", "R" } }; | ||
84 | - static const TCGTargetOpDef r_rZ_rJ | ||
85 | - = { .args_ct_str = { "r", "rZ", "rJ" } }; | ||
86 | - static const TCGTargetOpDef R_RZ_RJ | ||
87 | - = { .args_ct_str = { "R", "RZ", "RJ" } }; | ||
88 | - static const TCGTargetOpDef r_r_rZ_rJ | ||
89 | - = { .args_ct_str = { "r", "r", "rZ", "rJ" } }; | ||
90 | - static const TCGTargetOpDef movc_32 | ||
91 | - = { .args_ct_str = { "r", "rZ", "rJ", "rI", "0" } }; | ||
92 | - static const TCGTargetOpDef movc_64 | ||
93 | - = { .args_ct_str = { "R", "RZ", "RJ", "RI", "0" } }; | ||
94 | - static const TCGTargetOpDef add2_32 | ||
95 | - = { .args_ct_str = { "r", "r", "rZ", "rZ", "rJ", "rJ" } }; | ||
96 | - static const TCGTargetOpDef add2_64 | ||
97 | - = { .args_ct_str = { "R", "R", "RZ", "RZ", "RJ", "RI" } }; | ||
98 | - | ||
99 | switch (op) { | ||
100 | case INDEX_op_goto_ptr: | ||
101 | - return &r; | ||
102 | + return C_O0_I1(r); | ||
103 | |||
104 | case INDEX_op_ld8u_i32: | ||
105 | case INDEX_op_ld8s_i32: | ||
106 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
107 | case INDEX_op_ld_i32: | ||
108 | case INDEX_op_neg_i32: | ||
109 | case INDEX_op_not_i32: | ||
110 | - return &r_r; | ||
111 | + return C_O1_I1(r, r); | ||
112 | |||
113 | case INDEX_op_st8_i32: | ||
114 | case INDEX_op_st16_i32: | ||
115 | case INDEX_op_st_i32: | ||
116 | - return &rZ_r; | ||
117 | + return C_O0_I2(rZ, r); | ||
118 | |||
119 | case INDEX_op_add_i32: | ||
120 | case INDEX_op_mul_i32: | ||
121 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
122 | case INDEX_op_shr_i32: | ||
123 | case INDEX_op_sar_i32: | ||
124 | case INDEX_op_setcond_i32: | ||
125 | - return &r_rZ_rJ; | ||
126 | + return C_O1_I2(r, rZ, rJ); | ||
127 | |||
128 | case INDEX_op_brcond_i32: | ||
129 | - return &rZ_rJ; | ||
130 | + return C_O0_I2(rZ, rJ); | ||
131 | case INDEX_op_movcond_i32: | ||
132 | - return &movc_32; | ||
133 | + return C_O1_I4(r, rZ, rJ, rI, 0); | ||
134 | case INDEX_op_add2_i32: | ||
135 | case INDEX_op_sub2_i32: | ||
136 | - return &add2_32; | ||
137 | + return C_O2_I4(r, r, rZ, rZ, rJ, rJ); | ||
138 | case INDEX_op_mulu2_i32: | ||
139 | case INDEX_op_muls2_i32: | ||
140 | - return &r_r_rZ_rJ; | ||
141 | + return C_O2_I2(r, r, rZ, rJ); | ||
142 | |||
143 | case INDEX_op_ld8u_i64: | ||
144 | case INDEX_op_ld8s_i64: | ||
145 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
146 | case INDEX_op_ld_i64: | ||
147 | case INDEX_op_ext_i32_i64: | ||
148 | case INDEX_op_extu_i32_i64: | ||
149 | - return &R_r; | ||
150 | + return C_O1_I1(R, r); | ||
151 | |||
152 | case INDEX_op_st8_i64: | ||
153 | case INDEX_op_st16_i64: | ||
154 | case INDEX_op_st32_i64: | ||
155 | case INDEX_op_st_i64: | ||
156 | - return &RZ_r; | ||
157 | + return C_O0_I2(RZ, r); | ||
158 | |||
159 | case INDEX_op_add_i64: | ||
160 | case INDEX_op_mul_i64: | ||
161 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
162 | case INDEX_op_shr_i64: | ||
163 | case INDEX_op_sar_i64: | ||
164 | case INDEX_op_setcond_i64: | ||
165 | - return &R_RZ_RJ; | ||
166 | + return C_O1_I2(R, RZ, RJ); | ||
167 | |||
168 | case INDEX_op_neg_i64: | ||
169 | case INDEX_op_not_i64: | ||
170 | case INDEX_op_ext32s_i64: | ||
171 | case INDEX_op_ext32u_i64: | ||
172 | - return &R_R; | ||
173 | + return C_O1_I1(R, R); | ||
174 | |||
175 | case INDEX_op_extrl_i64_i32: | ||
176 | case INDEX_op_extrh_i64_i32: | ||
177 | - return &r_R; | ||
178 | + return C_O1_I1(r, R); | ||
179 | |||
180 | case INDEX_op_brcond_i64: | ||
181 | - return &RZ_RJ; | ||
182 | + return C_O0_I2(RZ, RJ); | ||
183 | case INDEX_op_movcond_i64: | ||
184 | - return &movc_64; | ||
185 | + return C_O1_I4(R, RZ, RJ, RI, 0); | ||
186 | case INDEX_op_add2_i64: | ||
187 | case INDEX_op_sub2_i64: | ||
188 | - return &add2_64; | ||
189 | + return C_O2_I4(R, R, RZ, RZ, RJ, RI); | ||
190 | case INDEX_op_muluh_i64: | ||
191 | - return &R_R_R; | ||
192 | + return C_O1_I2(R, R, R); | ||
193 | |||
194 | case INDEX_op_qemu_ld_i32: | ||
195 | - return &r_A; | ||
196 | + return C_O1_I1(r, A); | ||
197 | case INDEX_op_qemu_ld_i64: | ||
198 | - return &R_A; | ||
199 | + return C_O1_I1(R, A); | ||
200 | case INDEX_op_qemu_st_i32: | ||
201 | - return &sZ_A; | ||
202 | + return C_O0_I2(sZ, A); | ||
203 | case INDEX_op_qemu_st_i64: | ||
204 | - return &SZ_A; | ||
205 | + return C_O0_I2(SZ, A); | ||
206 | |||
207 | default: | ||
208 | - return NULL; | ||
209 | + g_assert_not_reached(); | ||
210 | } | 101 | } |
211 | } | 102 | |
103 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
104 | switch (arg_ct->pair) { | ||
105 | case 0: /* not paired */ | ||
106 | if (arg_ct->ialias) { | ||
107 | - i_preferred_regs = op->output_pref[arg_ct->alias_index]; | ||
108 | + i_preferred_regs = output_pref(op, arg_ct->alias_index); | ||
109 | |||
110 | /* | ||
111 | * If the input is not dead after the instruction, | ||
112 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
113 | * and to identify a few cases where it's not required. | ||
114 | */ | ||
115 | if (arg_ct->ialias) { | ||
116 | - i_preferred_regs = op->output_pref[arg_ct->alias_index]; | ||
117 | + i_preferred_regs = output_pref(op, arg_ct->alias_index); | ||
118 | if (IS_DEAD_ARG(i1) && | ||
119 | IS_DEAD_ARG(i2) && | ||
120 | ts->val_type == TEMP_VAL_REG && | ||
121 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
122 | |||
123 | case 3: /* ialias with second output, no first input */ | ||
124 | tcg_debug_assert(arg_ct->ialias); | ||
125 | - i_preferred_regs = op->output_pref[arg_ct->alias_index]; | ||
126 | + i_preferred_regs = output_pref(op, arg_ct->alias_index); | ||
127 | |||
128 | if (IS_DEAD_ARG(i) && | ||
129 | ts->val_type == TEMP_VAL_REG && | ||
130 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
131 | } else if (arg_ct->newreg) { | ||
132 | reg = tcg_reg_alloc(s, arg_ct->regs, | ||
133 | i_allocated_regs | o_allocated_regs, | ||
134 | - op->output_pref[k], ts->indirect_base); | ||
135 | + output_pref(op, k), ts->indirect_base); | ||
136 | } else { | ||
137 | reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, | ||
138 | - op->output_pref[k], ts->indirect_base); | ||
139 | + output_pref(op, k), ts->indirect_base); | ||
140 | } | ||
141 | break; | ||
142 | |||
143 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) | ||
144 | break; | ||
145 | } | ||
146 | reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, | ||
147 | - op->output_pref[k], ts->indirect_base); | ||
148 | + output_pref(op, k), ts->indirect_base); | ||
149 | break; | ||
150 | |||
151 | case 2: /* second of pair */ | ||
152 | @@ -XXX,XX +XXX,XX @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) | ||
153 | } | ||
154 | |||
155 | oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, | ||
156 | - op->output_pref[0], ots->indirect_base); | ||
157 | + output_pref(op, 0), ots->indirect_base); | ||
158 | set_temp_val_reg(s, ots, oreg); | ||
159 | } | ||
212 | 160 | ||
213 | -- | 161 | -- |
214 | 2.25.1 | 162 | 2.34.1 |
215 | 163 | ||
216 | 164 | diff view generated by jsdifflib |
1 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | 1 | Pre-compute the function call layout for each helper at startup. |
---|---|---|---|
2 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 2 | Drop TCG_CALL_DUMMY_ARG, as we no longer need to leave gaps |
3 | in the op->args[] array. This allows several places to stop | ||
4 | checking for NULL TCGTemp, to which TCG_CALL_DUMMY_ARG mapped. | ||
5 | |||
6 | For tcg_gen_callN, loop over the arguments once. Allocate the TCGOp | ||
7 | for the call early but delay emitting it, collecting arguments first. | ||
8 | This allows the argument processing loop to emit code for extensions | ||
9 | and have them sequenced before the call. | ||
10 | |||
11 | For tcg_reg_alloc_call, loop over the arguments in reverse order, | ||
12 | which allows stack slots to be filled first naturally. | ||
13 | |||
3 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 14 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
4 | --- | 15 | --- |
5 | tcg/sparc/tcg-target-con-str.h | 23 ++++++++++ | 16 | include/exec/helper-head.h | 2 + |
6 | tcg/sparc/tcg-target.h | 5 +-- | 17 | include/tcg/tcg.h | 5 +- |
7 | tcg/sparc/tcg-target.c.inc | 81 +++++++++++++--------------------- | 18 | tcg/tcg-internal.h | 22 +- |
8 | 3 files changed, 55 insertions(+), 54 deletions(-) | 19 | tcg/optimize.c | 6 +- |
9 | create mode 100644 tcg/sparc/tcg-target-con-str.h | 20 | tcg/tcg.c | 609 ++++++++++++++++++++++--------------- |
21 | 5 files changed, 394 insertions(+), 250 deletions(-) | ||
10 | 22 | ||
11 | diff --git a/tcg/sparc/tcg-target-con-str.h b/tcg/sparc/tcg-target-con-str.h | 23 | diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h |
12 | new file mode 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
13 | index XXXXXXX..XXXXXXX | 25 | --- a/include/exec/helper-head.h |
14 | --- /dev/null | 26 | +++ b/include/exec/helper-head.h |
15 | +++ b/tcg/sparc/tcg-target-con-str.h | ||
16 | @@ -XXX,XX +XXX,XX @@ | 27 | @@ -XXX,XX +XXX,XX @@ |
17 | +/* SPDX-License-Identifier: MIT */ | 28 | #define DEF_HELPER_7(name, ret, t1, t2, t3, t4, t5, t6, t7) \ |
18 | +/* | 29 | DEF_HELPER_FLAGS_7(name, 0, ret, t1, t2, t3, t4, t5, t6, t7) |
19 | + * Define Sparc target-specific operand constraints. | 30 | |
20 | + * Copyright (c) 2021 Linaro | 31 | +/* MAX_CALL_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */ |
21 | + */ | 32 | + |
22 | + | 33 | #endif /* EXEC_HELPER_HEAD_H */ |
23 | +/* | 34 | diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h |
24 | + * Define constraint letters for register sets: | ||
25 | + * REGS(letter, register_mask) | ||
26 | + */ | ||
27 | +REGS('r', ALL_GENERAL_REGS) | ||
28 | +REGS('R', ALL_GENERAL_REGS64) | ||
29 | +REGS('s', ALL_QLDST_REGS) | ||
30 | +REGS('S', ALL_QLDST_REGS64) | ||
31 | +REGS('A', TARGET_LONG_BITS == 64 ? ALL_QLDST_REGS64 : ALL_QLDST_REGS) | ||
32 | + | ||
33 | +/* | ||
34 | + * Define constraint letters for constants: | ||
35 | + * CONST(letter, TCG_CT_CONST_* bit set) | ||
36 | + */ | ||
37 | +CONST('I', TCG_CT_CONST_S11) | ||
38 | +CONST('J', TCG_CT_CONST_S13) | ||
39 | +CONST('Z', TCG_CT_CONST_ZERO) | ||
40 | diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h | ||
41 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
42 | --- a/tcg/sparc/tcg-target.h | 36 | --- a/include/tcg/tcg.h |
43 | +++ b/tcg/sparc/tcg-target.h | 37 | +++ b/include/tcg/tcg.h |
38 | @@ -XXX,XX +XXX,XX @@ | ||
39 | /* XXX: make safe guess about sizes */ | ||
40 | #define MAX_OP_PER_INSTR 266 | ||
41 | |||
42 | +#define MAX_CALL_IARGS 7 | ||
43 | + | ||
44 | #define CPU_TEMP_BUF_NLONGS 128 | ||
45 | #define TCG_STATIC_FRAME_SIZE (CPU_TEMP_BUF_NLONGS * sizeof(long)) | ||
46 | |||
47 | @@ -XXX,XX +XXX,XX @@ typedef TCGv_ptr TCGv_env; | ||
48 | #define TCG_CALL_NO_RWG_SE (TCG_CALL_NO_RWG | TCG_CALL_NO_SE) | ||
49 | #define TCG_CALL_NO_WG_SE (TCG_CALL_NO_WG | TCG_CALL_NO_SE) | ||
50 | |||
51 | -/* Used to align parameters. See the comment before tcgv_i32_temp. */ | ||
52 | -#define TCG_CALL_DUMMY_ARG ((TCGArg)0) | ||
53 | - | ||
54 | /* | ||
55 | * Flags for the bswap opcodes. | ||
56 | * If IZ, the input is zero-extended, otherwise unknown. | ||
57 | diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h | ||
58 | index XXXXXXX..XXXXXXX 100644 | ||
59 | --- a/tcg/tcg-internal.h | ||
60 | +++ b/tcg/tcg-internal.h | ||
44 | @@ -XXX,XX +XXX,XX @@ typedef enum { | 61 | @@ -XXX,XX +XXX,XX @@ typedef enum { |
45 | TCG_REG_I7, | 62 | TCG_CALL_ARG_EXTEND_S, /* ... as a sign-extended i64 */ |
46 | } TCGReg; | 63 | } TCGCallArgumentKind; |
47 | 64 | ||
48 | -#define TCG_CT_CONST_S11 0x100 | 65 | +typedef struct TCGCallArgumentLoc { |
49 | -#define TCG_CT_CONST_S13 0x200 | 66 | + TCGCallArgumentKind kind : 8; |
50 | -#define TCG_CT_CONST_ZERO 0x400 | 67 | + unsigned arg_slot : 8; |
51 | - | 68 | + unsigned ref_slot : 8; |
52 | /* used for function call generation */ | 69 | + unsigned arg_idx : 4; |
53 | #define TCG_REG_CALL_STACK TCG_REG_O6 | 70 | + unsigned tmp_subindex : 2; |
54 | 71 | +} TCGCallArgumentLoc; | |
55 | @@ -XXX,XX +XXX,XX @@ extern bool use_vis3_instructions; | 72 | + |
56 | void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 73 | +/* Avoid "unsigned < 0 is always false" Werror, when iarg_regs is empty. */ |
57 | 74 | +#define REG_P(L) \ | |
58 | #define TCG_TARGET_NEED_POOL_LABELS | 75 | + ((int)(L)->arg_slot < (int)ARRAY_SIZE(tcg_target_call_iarg_regs)) |
59 | +#define TCG_TARGET_CON_STR_H | 76 | + |
60 | 77 | typedef struct TCGHelperInfo { | |
78 | void *func; | ||
79 | const char *name; | ||
80 | - unsigned flags; | ||
81 | - unsigned typemask; | ||
82 | + unsigned typemask : 32; | ||
83 | + unsigned flags : 8; | ||
84 | + unsigned nr_in : 8; | ||
85 | + unsigned nr_out : 8; | ||
86 | + TCGCallReturnKind out_kind : 8; | ||
87 | + | ||
88 | + /* Maximum physical arguments are constrained by TCG_TYPE_I128. */ | ||
89 | + TCGCallArgumentLoc in[MAX_CALL_IARGS * (128 / TCG_TARGET_REG_BITS)]; | ||
90 | } TCGHelperInfo; | ||
91 | |||
92 | extern TCGContext tcg_init_ctx; | ||
93 | diff --git a/tcg/optimize.c b/tcg/optimize.c | ||
94 | index XXXXXXX..XXXXXXX 100644 | ||
95 | --- a/tcg/optimize.c | ||
96 | +++ b/tcg/optimize.c | ||
97 | @@ -XXX,XX +XXX,XX @@ static void init_arguments(OptContext *ctx, TCGOp *op, int nb_args) | ||
98 | { | ||
99 | for (int i = 0; i < nb_args; i++) { | ||
100 | TCGTemp *ts = arg_temp(op->args[i]); | ||
101 | - if (ts) { | ||
102 | - init_ts_info(ctx, ts); | ||
103 | - } | ||
104 | + init_ts_info(ctx, ts); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | @@ -XXX,XX +XXX,XX @@ static void copy_propagate(OptContext *ctx, TCGOp *op, | ||
109 | |||
110 | for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) { | ||
111 | TCGTemp *ts = arg_temp(op->args[i]); | ||
112 | - if (ts && ts_is_copy(ts)) { | ||
113 | + if (ts_is_copy(ts)) { | ||
114 | op->args[i] = temp_arg(find_better_copy(s, ts)); | ||
115 | } | ||
116 | } | ||
117 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
118 | index XXXXXXX..XXXXXXX 100644 | ||
119 | --- a/tcg/tcg.c | ||
120 | +++ b/tcg/tcg.c | ||
121 | @@ -XXX,XX +XXX,XX @@ void tcg_pool_reset(TCGContext *s) | ||
122 | |||
123 | #include "exec/helper-proto.h" | ||
124 | |||
125 | -static const TCGHelperInfo all_helpers[] = { | ||
126 | +static TCGHelperInfo all_helpers[] = { | ||
127 | #include "exec/helper-tcg.h" | ||
128 | }; | ||
129 | static GHashTable *helper_table; | ||
130 | @@ -XXX,XX +XXX,XX @@ static ffi_type * const typecode_to_ffi[8] = { | ||
131 | }; | ||
61 | #endif | 132 | #endif |
62 | diff --git a/tcg/sparc/tcg-target.c.inc b/tcg/sparc/tcg-target.c.inc | 133 | |
63 | index XXXXXXX..XXXXXXX 100644 | 134 | +typedef struct TCGCumulativeArgs { |
64 | --- a/tcg/sparc/tcg-target.c.inc | 135 | + int arg_idx; /* tcg_gen_callN args[] */ |
65 | +++ b/tcg/sparc/tcg-target.c.inc | 136 | + int info_in_idx; /* TCGHelperInfo in[] */ |
66 | @@ -XXX,XX +XXX,XX @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { | 137 | + int arg_slot; /* regs+stack slot */ |
67 | # define SPARC64 0 | 138 | + int ref_slot; /* stack slots for references */ |
139 | +} TCGCumulativeArgs; | ||
140 | + | ||
141 | +static void layout_arg_even(TCGCumulativeArgs *cum) | ||
142 | +{ | ||
143 | + cum->arg_slot += cum->arg_slot & 1; | ||
144 | +} | ||
145 | + | ||
146 | +static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info, | ||
147 | + TCGCallArgumentKind kind) | ||
148 | +{ | ||
149 | + TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; | ||
150 | + | ||
151 | + *loc = (TCGCallArgumentLoc){ | ||
152 | + .kind = kind, | ||
153 | + .arg_idx = cum->arg_idx, | ||
154 | + .arg_slot = cum->arg_slot, | ||
155 | + }; | ||
156 | + cum->info_in_idx++; | ||
157 | + cum->arg_slot++; | ||
158 | +} | ||
159 | + | ||
160 | +static void layout_arg_normal_n(TCGCumulativeArgs *cum, | ||
161 | + TCGHelperInfo *info, int n) | ||
162 | +{ | ||
163 | + TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; | ||
164 | + | ||
165 | + for (int i = 0; i < n; ++i) { | ||
166 | + /* Layout all using the same arg_idx, adjusting the subindex. */ | ||
167 | + loc[i] = (TCGCallArgumentLoc){ | ||
168 | + .kind = TCG_CALL_ARG_NORMAL, | ||
169 | + .arg_idx = cum->arg_idx, | ||
170 | + .tmp_subindex = i, | ||
171 | + .arg_slot = cum->arg_slot + i, | ||
172 | + }; | ||
173 | + } | ||
174 | + cum->info_in_idx += n; | ||
175 | + cum->arg_slot += n; | ||
176 | +} | ||
177 | + | ||
178 | +static void init_call_layout(TCGHelperInfo *info) | ||
179 | +{ | ||
180 | + int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); | ||
181 | + int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long); | ||
182 | + unsigned typemask = info->typemask; | ||
183 | + unsigned typecode; | ||
184 | + TCGCumulativeArgs cum = { }; | ||
185 | + | ||
186 | + /* | ||
187 | + * Parse and place any function return value. | ||
188 | + */ | ||
189 | + typecode = typemask & 7; | ||
190 | + switch (typecode) { | ||
191 | + case dh_typecode_void: | ||
192 | + info->nr_out = 0; | ||
193 | + break; | ||
194 | + case dh_typecode_i32: | ||
195 | + case dh_typecode_s32: | ||
196 | + case dh_typecode_ptr: | ||
197 | + info->nr_out = 1; | ||
198 | + info->out_kind = TCG_CALL_RET_NORMAL; | ||
199 | + break; | ||
200 | + case dh_typecode_i64: | ||
201 | + case dh_typecode_s64: | ||
202 | + info->nr_out = 64 / TCG_TARGET_REG_BITS; | ||
203 | + info->out_kind = TCG_CALL_RET_NORMAL; | ||
204 | + break; | ||
205 | + default: | ||
206 | + g_assert_not_reached(); | ||
207 | + } | ||
208 | + assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs)); | ||
209 | + | ||
210 | + /* | ||
211 | + * Parse and place function arguments. | ||
212 | + */ | ||
213 | + for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) { | ||
214 | + TCGCallArgumentKind kind; | ||
215 | + TCGType type; | ||
216 | + | ||
217 | + typecode = typemask & 7; | ||
218 | + switch (typecode) { | ||
219 | + case dh_typecode_i32: | ||
220 | + case dh_typecode_s32: | ||
221 | + type = TCG_TYPE_I32; | ||
222 | + break; | ||
223 | + case dh_typecode_i64: | ||
224 | + case dh_typecode_s64: | ||
225 | + type = TCG_TYPE_I64; | ||
226 | + break; | ||
227 | + case dh_typecode_ptr: | ||
228 | + type = TCG_TYPE_PTR; | ||
229 | + break; | ||
230 | + default: | ||
231 | + g_assert_not_reached(); | ||
232 | + } | ||
233 | + | ||
234 | + switch (type) { | ||
235 | + case TCG_TYPE_I32: | ||
236 | + switch (TCG_TARGET_CALL_ARG_I32) { | ||
237 | + case TCG_CALL_ARG_EVEN: | ||
238 | + layout_arg_even(&cum); | ||
239 | + /* fall through */ | ||
240 | + case TCG_CALL_ARG_NORMAL: | ||
241 | + layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); | ||
242 | + break; | ||
243 | + case TCG_CALL_ARG_EXTEND: | ||
244 | + kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1); | ||
245 | + layout_arg_1(&cum, info, kind); | ||
246 | + break; | ||
247 | + default: | ||
248 | + qemu_build_not_reached(); | ||
249 | + } | ||
250 | + break; | ||
251 | + | ||
252 | + case TCG_TYPE_I64: | ||
253 | + switch (TCG_TARGET_CALL_ARG_I64) { | ||
254 | + case TCG_CALL_ARG_EVEN: | ||
255 | + layout_arg_even(&cum); | ||
256 | + /* fall through */ | ||
257 | + case TCG_CALL_ARG_NORMAL: | ||
258 | + if (TCG_TARGET_REG_BITS == 32) { | ||
259 | + layout_arg_normal_n(&cum, info, 2); | ||
260 | + } else { | ||
261 | + layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL); | ||
262 | + } | ||
263 | + break; | ||
264 | + default: | ||
265 | + qemu_build_not_reached(); | ||
266 | + } | ||
267 | + break; | ||
268 | + | ||
269 | + default: | ||
270 | + g_assert_not_reached(); | ||
271 | + } | ||
272 | + } | ||
273 | + info->nr_in = cum.info_in_idx; | ||
274 | + | ||
275 | + /* Validate that we didn't overrun the input array. */ | ||
276 | + assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); | ||
277 | + /* Validate the backend has enough argument space. */ | ||
278 | + assert(cum.arg_slot <= max_reg_slots + max_stk_slots); | ||
279 | + assert(cum.ref_slot <= max_stk_slots); | ||
280 | +} | ||
281 | + | ||
282 | static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; | ||
283 | static void process_op_defs(TCGContext *s); | ||
284 | static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, | ||
285 | @@ -XXX,XX +XXX,XX @@ static void tcg_context_init(unsigned max_cpus) | ||
286 | helper_table = g_hash_table_new(NULL, NULL); | ||
287 | |||
288 | for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { | ||
289 | + init_call_layout(&all_helpers[i]); | ||
290 | g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, | ||
291 | (gpointer)&all_helpers[i]); | ||
292 | } | ||
293 | @@ -XXX,XX +XXX,XX @@ bool tcg_op_supported(TCGOpcode op) | ||
294 | } | ||
295 | } | ||
296 | |||
297 | -/* Note: we convert the 64 bit args to 32 bit and do some alignment | ||
298 | - and endian swap. Maybe it would be better to do the alignment | ||
299 | - and endian swap in tcg_reg_alloc_call(). */ | ||
300 | +static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs); | ||
301 | + | ||
302 | void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
303 | { | ||
304 | - int i, real_args, nb_rets, pi, max_args; | ||
305 | - unsigned typemask; | ||
306 | const TCGHelperInfo *info; | ||
307 | + TCGv_i64 extend_free[MAX_CALL_IARGS]; | ||
308 | + int n_extend = 0; | ||
309 | TCGOp *op; | ||
310 | + int i, n, pi = 0, total_args; | ||
311 | |||
312 | info = g_hash_table_lookup(helper_table, (gpointer)func); | ||
313 | - typemask = info->typemask; | ||
314 | + total_args = info->nr_out + info->nr_in + 2; | ||
315 | + op = tcg_op_alloc(INDEX_op_call, total_args); | ||
316 | |||
317 | #ifdef CONFIG_PLUGIN | ||
318 | /* detect non-plugin helpers */ | ||
319 | @@ -XXX,XX +XXX,XX @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) | ||
320 | } | ||
68 | #endif | 321 | #endif |
69 | 322 | ||
70 | -/* Note that sparcv8plus can only hold 64 bit quantities in %g and %o | 323 | - if (TCG_TARGET_CALL_ARG_I32 == TCG_CALL_ARG_EXTEND) { |
71 | - registers. These are saved manually by the kernel in full 64-bit | 324 | - for (i = 0; i < nargs; ++i) { |
72 | - slots. The %i and %l registers are saved by the register window | 325 | - int argtype = extract32(typemask, (i + 1) * 3, 3); |
73 | - mechanism, which only allocates space for 32 bits. Given that this | 326 | - bool is_32bit = (argtype & ~1) == dh_typecode_i32; |
74 | - window spill/fill can happen on any signal, we must consider the | 327 | - bool is_signed = argtype & 1; |
75 | - high bits of the %i and %l registers garbage at all times. */ | 328 | + TCGOP_CALLO(op) = n = info->nr_out; |
76 | -#if SPARC64 | 329 | + switch (n) { |
77 | -# define ALL_64 0xffffffffu | 330 | + case 0: |
78 | +#define TCG_CT_CONST_S11 0x100 | 331 | + tcg_debug_assert(ret == NULL); |
79 | +#define TCG_CT_CONST_S13 0x200 | 332 | + break; |
80 | +#define TCG_CT_CONST_ZERO 0x400 | 333 | + case 1: |
81 | + | 334 | + tcg_debug_assert(ret != NULL); |
82 | +/* | 335 | + op->args[pi++] = temp_arg(ret); |
83 | + * For softmmu, we need to avoid conflicts with the first 3 | 336 | + break; |
84 | + * argument registers to perform the tlb lookup, and to call | 337 | + case 2: |
85 | + * the helper function. | 338 | + tcg_debug_assert(ret != NULL); |
86 | + */ | 339 | + tcg_debug_assert(ret->base_type == ret->type + 1); |
87 | +#ifdef CONFIG_SOFTMMU | 340 | + tcg_debug_assert(ret->temp_subindex == 0); |
88 | +#define SOFTMMU_RESERVE_REGS MAKE_64BIT_MASK(TCG_REG_O0, 3) | 341 | + op->args[pi++] = temp_arg(ret); |
89 | #else | 342 | + op->args[pi++] = temp_arg(ret + 1); |
90 | -# define ALL_64 0xffffu | 343 | + break; |
91 | +#define SOFTMMU_RESERVE_REGS 0 | 344 | + default: |
92 | #endif | 345 | + g_assert_not_reached(); |
93 | 346 | + } | |
94 | +/* | 347 | |
95 | + * Note that sparcv8plus can only hold 64 bit quantities in %g and %o | 348 | - if (is_32bit) { |
96 | + * registers. These are saved manually by the kernel in full 64-bit | 349 | + TCGOP_CALLI(op) = n = info->nr_in; |
97 | + * slots. The %i and %l registers are saved by the register window | 350 | + for (i = 0; i < n; i++) { |
98 | + * mechanism, which only allocates space for 32 bits. Given that this | 351 | + const TCGCallArgumentLoc *loc = &info->in[i]; |
99 | + * window spill/fill can happen on any signal, we must consider the | 352 | + TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex; |
100 | + * high bits of the %i and %l registers garbage at all times. | 353 | + |
101 | + */ | 354 | + switch (loc->kind) { |
102 | +#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32) | 355 | + case TCG_CALL_ARG_NORMAL: |
103 | +#if SPARC64 | 356 | + op->args[pi++] = temp_arg(ts); |
104 | +# define ALL_GENERAL_REGS64 ALL_GENERAL_REGS | 357 | + break; |
105 | +#else | 358 | + |
106 | +# define ALL_GENERAL_REGS64 MAKE_64BIT_MASK(0, 16) | 359 | + case TCG_CALL_ARG_EXTEND_U: |
107 | +#endif | 360 | + case TCG_CALL_ARG_EXTEND_S: |
108 | +#define ALL_QLDST_REGS (ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) | 361 | + { |
109 | +#define ALL_QLDST_REGS64 (ALL_GENERAL_REGS64 & ~SOFTMMU_RESERVE_REGS) | 362 | TCGv_i64 temp = tcg_temp_new_i64(); |
110 | + | 363 | - TCGv_i32 orig = temp_tcgv_i32(args[i]); |
111 | /* Define some temporary registers. T2 is used for constant generation. */ | 364 | - if (is_signed) { |
112 | #define TCG_REG_T1 TCG_REG_G1 | 365 | + TCGv_i32 orig = temp_tcgv_i32(ts); |
113 | #define TCG_REG_T2 TCG_REG_O7 | 366 | + |
114 | @@ -XXX,XX +XXX,XX @@ static bool patch_reloc(tcg_insn_unit *src_rw, int type, | 367 | + if (loc->kind == TCG_CALL_ARG_EXTEND_S) { |
368 | tcg_gen_ext_i32_i64(temp, orig); | ||
369 | } else { | ||
370 | tcg_gen_extu_i32_i64(temp, orig); | ||
371 | } | ||
372 | - args[i] = tcgv_i64_temp(temp); | ||
373 | + op->args[pi++] = tcgv_i64_arg(temp); | ||
374 | + extend_free[n_extend++] = temp; | ||
375 | } | ||
376 | - } | ||
377 | - } | ||
378 | - | ||
379 | - /* | ||
380 | - * A Call op needs up to 4 + 2N parameters on 32-bit archs, | ||
381 | - * and up to 4 + N parameters on 64-bit archs | ||
382 | - * (N = number of input arguments + output arguments). | ||
383 | - */ | ||
384 | - max_args = (64 / TCG_TARGET_REG_BITS) * nargs + 4; | ||
385 | - op = tcg_emit_op(INDEX_op_call, max_args); | ||
386 | - | ||
387 | - pi = 0; | ||
388 | - if (ret != NULL) { | ||
389 | - if (TCG_TARGET_REG_BITS < 64 && (typemask & 6) == dh_typecode_i64) { | ||
390 | - op->args[pi++] = temp_arg(ret); | ||
391 | - op->args[pi++] = temp_arg(ret + 1); | ||
392 | - nb_rets = 2; | ||
393 | - } else { | ||
394 | - op->args[pi++] = temp_arg(ret); | ||
395 | - nb_rets = 1; | ||
396 | - } | ||
397 | - } else { | ||
398 | - nb_rets = 0; | ||
399 | - } | ||
400 | - TCGOP_CALLO(op) = nb_rets; | ||
401 | - | ||
402 | - real_args = 0; | ||
403 | - for (i = 0; i < nargs; i++) { | ||
404 | - int argtype = extract32(typemask, (i + 1) * 3, 3); | ||
405 | - TCGCallArgumentKind kind; | ||
406 | - TCGType type; | ||
407 | - | ||
408 | - switch (argtype) { | ||
409 | - case dh_typecode_i32: | ||
410 | - case dh_typecode_s32: | ||
411 | - type = TCG_TYPE_I32; | ||
412 | break; | ||
413 | - case dh_typecode_i64: | ||
414 | - case dh_typecode_s64: | ||
415 | - type = TCG_TYPE_I64; | ||
416 | - break; | ||
417 | - case dh_typecode_ptr: | ||
418 | - type = TCG_TYPE_PTR; | ||
419 | - break; | ||
420 | - default: | ||
421 | - g_assert_not_reached(); | ||
422 | - } | ||
423 | |||
424 | - switch (type) { | ||
425 | - case TCG_TYPE_I32: | ||
426 | - kind = TCG_TARGET_CALL_ARG_I32; | ||
427 | - break; | ||
428 | - case TCG_TYPE_I64: | ||
429 | - kind = TCG_TARGET_CALL_ARG_I64; | ||
430 | - break; | ||
431 | - default: | ||
432 | - g_assert_not_reached(); | ||
433 | - } | ||
434 | - | ||
435 | - switch (kind) { | ||
436 | - case TCG_CALL_ARG_EVEN: | ||
437 | - if (real_args & 1) { | ||
438 | - op->args[pi++] = TCG_CALL_DUMMY_ARG; | ||
439 | - real_args++; | ||
440 | - } | ||
441 | - /* fall through */ | ||
442 | - case TCG_CALL_ARG_NORMAL: | ||
443 | - if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { | ||
444 | - op->args[pi++] = temp_arg(args[i]); | ||
445 | - op->args[pi++] = temp_arg(args[i] + 1); | ||
446 | - real_args += 2; | ||
447 | - break; | ||
448 | - } | ||
449 | - op->args[pi++] = temp_arg(args[i]); | ||
450 | - real_args++; | ||
451 | - break; | ||
452 | default: | ||
453 | g_assert_not_reached(); | ||
454 | } | ||
455 | } | ||
456 | op->args[pi++] = (uintptr_t)func; | ||
457 | op->args[pi++] = (uintptr_t)info; | ||
458 | - TCGOP_CALLI(op) = real_args; | ||
459 | + tcg_debug_assert(pi == total_args); | ||
460 | |||
461 | - /* Make sure the fields didn't overflow. */ | ||
462 | - tcg_debug_assert(TCGOP_CALLI(op) == real_args); | ||
463 | - tcg_debug_assert(pi <= max_args); | ||
464 | + QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); | ||
465 | |||
466 | - if (TCG_TARGET_CALL_ARG_I32 == TCG_CALL_ARG_EXTEND) { | ||
467 | - for (i = 0; i < nargs; ++i) { | ||
468 | - int argtype = extract32(typemask, (i + 1) * 3, 3); | ||
469 | - bool is_32bit = (argtype & ~1) == dh_typecode_i32; | ||
470 | - | ||
471 | - if (is_32bit) { | ||
472 | - tcg_temp_free_internal(args[i]); | ||
473 | - } | ||
474 | - } | ||
475 | + tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free)); | ||
476 | + for (i = 0; i < n_extend; ++i) { | ||
477 | + tcg_temp_free_i64(extend_free[i]); | ||
478 | } | ||
479 | } | ||
480 | |||
481 | @@ -XXX,XX +XXX,XX @@ static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) | ||
482 | } | ||
483 | for (i = 0; i < nb_iargs; i++) { | ||
484 | TCGArg arg = op->args[nb_oargs + i]; | ||
485 | - const char *t = "<dummy>"; | ||
486 | - if (arg != TCG_CALL_DUMMY_ARG) { | ||
487 | - t = tcg_get_arg_str(s, buf, sizeof(buf), arg); | ||
488 | - } | ||
489 | + const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg); | ||
490 | col += ne_fprintf(f, ",%s", t); | ||
491 | } | ||
492 | } else { | ||
493 | @@ -XXX,XX +XXX,XX @@ static void liveness_pass_1(TCGContext *s) | ||
494 | switch (opc) { | ||
495 | case INDEX_op_call: | ||
496 | { | ||
497 | - int call_flags; | ||
498 | - int nb_call_regs; | ||
499 | + const TCGHelperInfo *info = tcg_call_info(op); | ||
500 | + int call_flags = tcg_call_flags(op); | ||
501 | |||
502 | nb_oargs = TCGOP_CALLO(op); | ||
503 | nb_iargs = TCGOP_CALLI(op); | ||
504 | - call_flags = tcg_call_flags(op); | ||
505 | |||
506 | /* pure functions can be removed if their result is unused */ | ||
507 | if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { | ||
508 | @@ -XXX,XX +XXX,XX @@ static void liveness_pass_1(TCGContext *s) | ||
509 | /* Record arguments that die in this helper. */ | ||
510 | for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { | ||
511 | ts = arg_temp(op->args[i]); | ||
512 | - if (ts && ts->state & TS_DEAD) { | ||
513 | + if (ts->state & TS_DEAD) { | ||
514 | arg_life |= DEAD_ARG << i; | ||
515 | } | ||
516 | } | ||
517 | @@ -XXX,XX +XXX,XX @@ static void liveness_pass_1(TCGContext *s) | ||
518 | /* For all live registers, remove call-clobbered prefs. */ | ||
519 | la_cross_call(s, nb_temps); | ||
520 | |||
521 | - nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); | ||
522 | + /* | ||
523 | + * Input arguments are live for preceding opcodes. | ||
524 | + * | ||
525 | + * For those arguments that die, and will be allocated in | ||
526 | + * registers, clear the register set for that arg, to be | ||
527 | + * filled in below. For args that will be on the stack, | ||
528 | + * reset to any available reg. Process arguments in reverse | ||
529 | + * order so that if a temp is used more than once, the stack | ||
530 | + * reset to max happens before the register reset to 0. | ||
531 | + */ | ||
532 | + for (i = nb_iargs - 1; i >= 0; i--) { | ||
533 | + const TCGCallArgumentLoc *loc = &info->in[i]; | ||
534 | + ts = arg_temp(op->args[nb_oargs + i]); | ||
535 | |||
536 | - /* Input arguments are live for preceding opcodes. */ | ||
537 | - for (i = 0; i < nb_iargs; i++) { | ||
538 | - ts = arg_temp(op->args[i + nb_oargs]); | ||
539 | - if (ts && ts->state & TS_DEAD) { | ||
540 | - /* For those arguments that die, and will be allocated | ||
541 | - * in registers, clear the register set for that arg, | ||
542 | - * to be filled in below. For args that will be on | ||
543 | - * the stack, reset to any available reg. | ||
544 | - */ | ||
545 | - *la_temp_pref(ts) | ||
546 | - = (i < nb_call_regs ? 0 : | ||
547 | - tcg_target_available_regs[ts->type]); | ||
548 | + if (ts->state & TS_DEAD) { | ||
549 | + switch (loc->kind) { | ||
550 | + case TCG_CALL_ARG_NORMAL: | ||
551 | + case TCG_CALL_ARG_EXTEND_U: | ||
552 | + case TCG_CALL_ARG_EXTEND_S: | ||
553 | + if (REG_P(loc)) { | ||
554 | + *la_temp_pref(ts) = 0; | ||
555 | + break; | ||
556 | + } | ||
557 | + /* fall through */ | ||
558 | + default: | ||
559 | + *la_temp_pref(ts) = | ||
560 | + tcg_target_available_regs[ts->type]; | ||
561 | + break; | ||
562 | + } | ||
563 | ts->state &= ~TS_DEAD; | ||
564 | } | ||
565 | } | ||
566 | |||
567 | - /* For each input argument, add its input register to prefs. | ||
568 | - If a temp is used once, this produces a single set bit. */ | ||
569 | - for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) { | ||
570 | - ts = arg_temp(op->args[i + nb_oargs]); | ||
571 | - if (ts) { | ||
572 | - tcg_regset_set_reg(*la_temp_pref(ts), | ||
573 | - tcg_target_call_iarg_regs[i]); | ||
574 | + /* | ||
575 | + * For each input argument, add its input register to prefs. | ||
576 | + * If a temp is used once, this produces a single set bit; | ||
577 | + * if a temp is used multiple times, this produces a set. | ||
578 | + */ | ||
579 | + for (i = 0; i < nb_iargs; i++) { | ||
580 | + const TCGCallArgumentLoc *loc = &info->in[i]; | ||
581 | + ts = arg_temp(op->args[nb_oargs + i]); | ||
582 | + | ||
583 | + switch (loc->kind) { | ||
584 | + case TCG_CALL_ARG_NORMAL: | ||
585 | + case TCG_CALL_ARG_EXTEND_U: | ||
586 | + case TCG_CALL_ARG_EXTEND_S: | ||
587 | + if (REG_P(loc)) { | ||
588 | + tcg_regset_set_reg(*la_temp_pref(ts), | ||
589 | + tcg_target_call_iarg_regs[loc->arg_slot]); | ||
590 | + } | ||
591 | + break; | ||
592 | + default: | ||
593 | + break; | ||
594 | } | ||
595 | } | ||
596 | } | ||
597 | @@ -XXX,XX +XXX,XX @@ static bool liveness_pass_2(TCGContext *s) | ||
598 | /* Make sure that input arguments are available. */ | ||
599 | for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { | ||
600 | arg_ts = arg_temp(op->args[i]); | ||
601 | - if (arg_ts) { | ||
602 | - dir_ts = arg_ts->state_ptr; | ||
603 | - if (dir_ts && arg_ts->state == TS_DEAD) { | ||
604 | - TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 | ||
605 | - ? INDEX_op_ld_i32 | ||
606 | - : INDEX_op_ld_i64); | ||
607 | - TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); | ||
608 | + dir_ts = arg_ts->state_ptr; | ||
609 | + if (dir_ts && arg_ts->state == TS_DEAD) { | ||
610 | + TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 | ||
611 | + ? INDEX_op_ld_i32 | ||
612 | + : INDEX_op_ld_i64); | ||
613 | + TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); | ||
614 | |||
615 | - lop->args[0] = temp_arg(dir_ts); | ||
616 | - lop->args[1] = temp_arg(arg_ts->mem_base); | ||
617 | - lop->args[2] = arg_ts->mem_offset; | ||
618 | + lop->args[0] = temp_arg(dir_ts); | ||
619 | + lop->args[1] = temp_arg(arg_ts->mem_base); | ||
620 | + lop->args[2] = arg_ts->mem_offset; | ||
621 | |||
622 | - /* Loaded, but synced with memory. */ | ||
623 | - arg_ts->state = TS_MEM; | ||
624 | - } | ||
625 | + /* Loaded, but synced with memory. */ | ||
626 | + arg_ts->state = TS_MEM; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | @@ -XXX,XX +XXX,XX @@ static bool liveness_pass_2(TCGContext *s) | ||
631 | so that we reload when needed. */ | ||
632 | for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { | ||
633 | arg_ts = arg_temp(op->args[i]); | ||
634 | - if (arg_ts) { | ||
635 | - dir_ts = arg_ts->state_ptr; | ||
636 | - if (dir_ts) { | ||
637 | - op->args[i] = temp_arg(dir_ts); | ||
638 | - changes = true; | ||
639 | - if (IS_DEAD_ARG(i)) { | ||
640 | - arg_ts->state = TS_DEAD; | ||
641 | - } | ||
642 | + dir_ts = arg_ts->state_ptr; | ||
643 | + if (dir_ts) { | ||
644 | + op->args[i] = temp_arg(dir_ts); | ||
645 | + changes = true; | ||
646 | + if (IS_DEAD_ARG(i)) { | ||
647 | + arg_ts->state = TS_DEAD; | ||
648 | } | ||
649 | } | ||
650 | } | ||
651 | @@ -XXX,XX +XXX,XX @@ static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op) | ||
115 | return true; | 652 | return true; |
116 | } | 653 | } |
117 | 654 | ||
118 | -/* parse target specific constraints */ | 655 | +static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts, |
119 | -static const char *target_parse_constraint(TCGArgConstraint *ct, | 656 | + TCGRegSet allocated_regs) |
120 | - const char *ct_str, TCGType type) | 657 | +{ |
121 | -{ | 658 | + if (ts->val_type == TEMP_VAL_REG) { |
122 | - switch (*ct_str++) { | 659 | + if (ts->reg != reg) { |
123 | - case 'r': | 660 | + tcg_reg_free(s, reg, allocated_regs); |
124 | - ct->regs = 0xffffffff; | 661 | + if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { |
125 | - break; | 662 | + /* |
126 | - case 'R': | 663 | + * Cross register class move not supported. Sync the |
127 | - ct->regs = ALL_64; | 664 | + * temp back to its slot and load from there. |
128 | - break; | 665 | + */ |
129 | - case 'A': /* qemu_ld/st address constraint */ | 666 | + temp_sync(s, ts, allocated_regs, 0, 0); |
130 | - ct->regs = TARGET_LONG_BITS == 64 ? ALL_64 : 0xffffffff; | 667 | + tcg_out_ld(s, ts->type, reg, |
131 | - reserve_helpers: | 668 | + ts->mem_base->reg, ts->mem_offset); |
132 | - tcg_regset_reset_reg(ct->regs, TCG_REG_O0); | 669 | + } |
133 | - tcg_regset_reset_reg(ct->regs, TCG_REG_O1); | 670 | + } |
134 | - tcg_regset_reset_reg(ct->regs, TCG_REG_O2); | 671 | + } else { |
135 | - break; | 672 | + TCGRegSet arg_set = 0; |
136 | - case 's': /* qemu_st data 32-bit constraint */ | 673 | + |
137 | - ct->regs = 0xffffffff; | 674 | + tcg_reg_free(s, reg, allocated_regs); |
138 | - goto reserve_helpers; | 675 | + tcg_regset_set_reg(arg_set, reg); |
139 | - case 'S': /* qemu_st data 64-bit constraint */ | 676 | + temp_load(s, ts, arg_set, allocated_regs, 0); |
140 | - ct->regs = ALL_64; | 677 | + } |
141 | - goto reserve_helpers; | 678 | +} |
142 | - case 'I': | 679 | + |
143 | - ct->ct |= TCG_CT_CONST_S11; | 680 | +static void load_arg_stk(TCGContext *s, int stk_slot, TCGTemp *ts, |
144 | - break; | 681 | + TCGRegSet allocated_regs) |
145 | - case 'J': | 682 | +{ |
146 | - ct->ct |= TCG_CT_CONST_S13; | 683 | + /* |
147 | - break; | 684 | + * When the destination is on the stack, load up the temp and store. |
148 | - case 'Z': | 685 | + * If there are many call-saved registers, the temp might live to |
149 | - ct->ct |= TCG_CT_CONST_ZERO; | 686 | + * see another use; otherwise it'll be discarded. |
150 | - break; | 687 | + */ |
151 | - default: | 688 | + temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0); |
152 | - return NULL; | 689 | + tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, |
690 | + TCG_TARGET_CALL_STACK_OFFSET + | ||
691 | + stk_slot * sizeof(tcg_target_long)); | ||
692 | +} | ||
693 | + | ||
694 | +static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, | ||
695 | + TCGTemp *ts, TCGRegSet *allocated_regs) | ||
696 | +{ | ||
697 | + if (REG_P(l)) { | ||
698 | + TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot]; | ||
699 | + load_arg_reg(s, reg, ts, *allocated_regs); | ||
700 | + tcg_regset_set_reg(*allocated_regs, reg); | ||
701 | + } else { | ||
702 | + load_arg_stk(s, l->arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs), | ||
703 | + ts, *allocated_regs); | ||
704 | + } | ||
705 | +} | ||
706 | + | ||
707 | static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) | ||
708 | { | ||
709 | const int nb_oargs = TCGOP_CALLO(op); | ||
710 | const int nb_iargs = TCGOP_CALLI(op); | ||
711 | const TCGLifeData arg_life = op->life; | ||
712 | - const TCGHelperInfo *info; | ||
713 | - int flags, nb_regs, i; | ||
714 | - TCGReg reg; | ||
715 | - TCGArg arg; | ||
716 | - TCGTemp *ts; | ||
717 | - intptr_t stack_offset; | ||
718 | - size_t call_stack_size; | ||
719 | - tcg_insn_unit *func_addr; | ||
720 | - int allocate_args; | ||
721 | - TCGRegSet allocated_regs; | ||
722 | + const TCGHelperInfo *info = tcg_call_info(op); | ||
723 | + TCGRegSet allocated_regs = s->reserved_regs; | ||
724 | + int i; | ||
725 | |||
726 | - func_addr = tcg_call_func(op); | ||
727 | - info = tcg_call_info(op); | ||
728 | - flags = info->flags; | ||
729 | + /* | ||
730 | + * Move inputs into place in reverse order, | ||
731 | + * so that we place stacked arguments first. | ||
732 | + */ | ||
733 | + for (i = nb_iargs - 1; i >= 0; --i) { | ||
734 | + const TCGCallArgumentLoc *loc = &info->in[i]; | ||
735 | + TCGTemp *ts = arg_temp(op->args[nb_oargs + i]); | ||
736 | |||
737 | - nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); | ||
738 | - if (nb_regs > nb_iargs) { | ||
739 | - nb_regs = nb_iargs; | ||
153 | - } | 740 | - } |
154 | - return ct_str; | 741 | - |
155 | -} | 742 | - /* assign stack slots first */ |
156 | - | 743 | - call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); |
157 | /* test if a constant matches the constraint */ | 744 | - call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & |
158 | static inline int tcg_target_const_match(tcg_target_long val, TCGType type, | 745 | - ~(TCG_TARGET_STACK_ALIGN - 1); |
159 | const TCGArgConstraint *arg_ct) | 746 | - allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); |
160 | @@ -XXX,XX +XXX,XX @@ static void tcg_target_init(TCGContext *s) | 747 | - if (allocate_args) { |
161 | } | 748 | - /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, |
749 | - preallocate call stack */ | ||
750 | - tcg_abort(); | ||
751 | - } | ||
752 | - | ||
753 | - stack_offset = TCG_TARGET_CALL_STACK_OFFSET; | ||
754 | - for (i = nb_regs; i < nb_iargs; i++) { | ||
755 | - arg = op->args[nb_oargs + i]; | ||
756 | - if (arg != TCG_CALL_DUMMY_ARG) { | ||
757 | - ts = arg_temp(arg); | ||
758 | - temp_load(s, ts, tcg_target_available_regs[ts->type], | ||
759 | - s->reserved_regs, 0); | ||
760 | - tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); | ||
761 | - } | ||
762 | - stack_offset += sizeof(tcg_target_long); | ||
763 | - } | ||
764 | - | ||
765 | - /* assign input registers */ | ||
766 | - allocated_regs = s->reserved_regs; | ||
767 | - for (i = 0; i < nb_regs; i++) { | ||
768 | - arg = op->args[nb_oargs + i]; | ||
769 | - if (arg != TCG_CALL_DUMMY_ARG) { | ||
770 | - ts = arg_temp(arg); | ||
771 | - reg = tcg_target_call_iarg_regs[i]; | ||
772 | - | ||
773 | - if (ts->val_type == TEMP_VAL_REG) { | ||
774 | - if (ts->reg != reg) { | ||
775 | - tcg_reg_free(s, reg, allocated_regs); | ||
776 | - if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { | ||
777 | - /* | ||
778 | - * Cross register class move not supported. Sync the | ||
779 | - * temp back to its slot and load from there. | ||
780 | - */ | ||
781 | - temp_sync(s, ts, allocated_regs, 0, 0); | ||
782 | - tcg_out_ld(s, ts->type, reg, | ||
783 | - ts->mem_base->reg, ts->mem_offset); | ||
784 | - } | ||
785 | - } | ||
786 | - } else { | ||
787 | - TCGRegSet arg_set = 0; | ||
788 | - | ||
789 | - tcg_reg_free(s, reg, allocated_regs); | ||
790 | - tcg_regset_set_reg(arg_set, reg); | ||
791 | - temp_load(s, ts, arg_set, allocated_regs, 0); | ||
792 | - } | ||
793 | - | ||
794 | - tcg_regset_set_reg(allocated_regs, reg); | ||
795 | + switch (loc->kind) { | ||
796 | + case TCG_CALL_ARG_NORMAL: | ||
797 | + case TCG_CALL_ARG_EXTEND_U: | ||
798 | + case TCG_CALL_ARG_EXTEND_S: | ||
799 | + load_arg_normal(s, loc, ts, &allocated_regs); | ||
800 | + break; | ||
801 | + default: | ||
802 | + g_assert_not_reached(); | ||
803 | } | ||
804 | } | ||
805 | |||
806 | - /* mark dead temporaries and free the associated registers */ | ||
807 | + /* Mark dead temporaries and free the associated registers. */ | ||
808 | for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { | ||
809 | if (IS_DEAD_ARG(i)) { | ||
810 | temp_dead(s, arg_temp(op->args[i])); | ||
811 | } | ||
812 | } | ||
813 | |||
814 | - /* clobber call registers */ | ||
815 | + /* Clobber call registers. */ | ||
816 | for (i = 0; i < TCG_TARGET_NB_REGS; i++) { | ||
817 | if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { | ||
818 | tcg_reg_free(s, i, allocated_regs); | ||
819 | } | ||
820 | } | ||
821 | |||
822 | - /* Save globals if they might be written by the helper, sync them if | ||
823 | - they might be read. */ | ||
824 | - if (flags & TCG_CALL_NO_READ_GLOBALS) { | ||
825 | + /* | ||
826 | + * Save globals if they might be written by the helper, | ||
827 | + * sync them if they might be read. | ||
828 | + */ | ||
829 | + if (info->flags & TCG_CALL_NO_READ_GLOBALS) { | ||
830 | /* Nothing to do */ | ||
831 | - } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { | ||
832 | + } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) { | ||
833 | sync_globals(s, allocated_regs); | ||
834 | } else { | ||
835 | save_globals(s, allocated_regs); | ||
836 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) | ||
837 | gpointer hash = (gpointer)(uintptr_t)info->typemask; | ||
838 | ffi_cif *cif = g_hash_table_lookup(ffi_table, hash); | ||
839 | assert(cif != NULL); | ||
840 | - tcg_out_call(s, func_addr, cif); | ||
841 | + tcg_out_call(s, tcg_call_func(op), cif); | ||
842 | } | ||
843 | #else | ||
844 | - tcg_out_call(s, func_addr); | ||
845 | + tcg_out_call(s, tcg_call_func(op)); | ||
162 | #endif | 846 | #endif |
163 | 847 | ||
164 | - tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffff; | 848 | - /* assign output registers and emit moves if needed */ |
165 | - tcg_target_available_regs[TCG_TYPE_I64] = ALL_64; | 849 | - for(i = 0; i < nb_oargs; i++) { |
166 | + tcg_target_available_regs[TCG_TYPE_I32] = ALL_GENERAL_REGS; | 850 | - arg = op->args[i]; |
167 | + tcg_target_available_regs[TCG_TYPE_I64] = ALL_GENERAL_REGS64; | 851 | - ts = arg_temp(arg); |
168 | 852 | + /* Assign output registers and emit moves if needed. */ | |
169 | tcg_target_call_clobber_regs = 0; | 853 | + switch (info->out_kind) { |
170 | tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_G1); | 854 | + case TCG_CALL_RET_NORMAL: |
855 | + for (i = 0; i < nb_oargs; i++) { | ||
856 | + TCGTemp *ts = arg_temp(op->args[i]); | ||
857 | + TCGReg reg = tcg_target_call_oarg_regs[i]; | ||
858 | |||
859 | - /* ENV should not be modified. */ | ||
860 | - tcg_debug_assert(!temp_readonly(ts)); | ||
861 | + /* ENV should not be modified. */ | ||
862 | + tcg_debug_assert(!temp_readonly(ts)); | ||
863 | |||
864 | - reg = tcg_target_call_oarg_regs[i]; | ||
865 | - set_temp_val_reg(s, ts, reg); | ||
866 | - ts->mem_coherent = 0; | ||
867 | + set_temp_val_reg(s, ts, reg); | ||
868 | + ts->mem_coherent = 0; | ||
869 | + } | ||
870 | + break; | ||
871 | + default: | ||
872 | + g_assert_not_reached(); | ||
873 | + } | ||
874 | + | ||
875 | + /* Flush or discard output registers as needed. */ | ||
876 | + for (i = 0; i < nb_oargs; i++) { | ||
877 | + TCGTemp *ts = arg_temp(op->args[i]); | ||
878 | if (NEED_SYNC_ARG(i)) { | ||
879 | - temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i)); | ||
880 | + temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i)); | ||
881 | } else if (IS_DEAD_ARG(i)) { | ||
882 | temp_dead(s, ts); | ||
883 | } | ||
171 | -- | 884 | -- |
172 | 2.25.1 | 885 | 2.34.1 |
173 | |||
174 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
1 | 2 | ||
3 | In the unlikely case of invalid typecode mask, the function | ||
4 | will abort instead of returning a NULL pointer. | ||
5 | |||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | Message-Id: <20221111074101.2069454-27-richard.henderson@linaro.org> | ||
8 | [PMD: Split from bigger patch] | ||
9 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
10 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
11 | Message-Id: <20221122180804.938-2-philmd@linaro.org> | ||
12 | --- | ||
13 | tcg/tcg.c | 30 ++++++++++++++++++++---------- | ||
14 | 1 file changed, 20 insertions(+), 10 deletions(-) | ||
15 | |||
16 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/tcg/tcg.c | ||
19 | +++ b/tcg/tcg.c | ||
20 | @@ -XXX,XX +XXX,XX @@ static GHashTable *helper_table; | ||
21 | #ifdef CONFIG_TCG_INTERPRETER | ||
22 | static GHashTable *ffi_table; | ||
23 | |||
24 | -static ffi_type * const typecode_to_ffi[8] = { | ||
25 | - [dh_typecode_void] = &ffi_type_void, | ||
26 | - [dh_typecode_i32] = &ffi_type_uint32, | ||
27 | - [dh_typecode_s32] = &ffi_type_sint32, | ||
28 | - [dh_typecode_i64] = &ffi_type_uint64, | ||
29 | - [dh_typecode_s64] = &ffi_type_sint64, | ||
30 | - [dh_typecode_ptr] = &ffi_type_pointer, | ||
31 | -}; | ||
32 | +static ffi_type *typecode_to_ffi(int argmask) | ||
33 | +{ | ||
34 | + switch (argmask) { | ||
35 | + case dh_typecode_void: | ||
36 | + return &ffi_type_void; | ||
37 | + case dh_typecode_i32: | ||
38 | + return &ffi_type_uint32; | ||
39 | + case dh_typecode_s32: | ||
40 | + return &ffi_type_sint32; | ||
41 | + case dh_typecode_i64: | ||
42 | + return &ffi_type_uint64; | ||
43 | + case dh_typecode_s64: | ||
44 | + return &ffi_type_sint64; | ||
45 | + case dh_typecode_ptr: | ||
46 | + return &ffi_type_pointer; | ||
47 | + } | ||
48 | + g_assert_not_reached(); | ||
49 | +} | ||
50 | #endif | ||
51 | |||
52 | typedef struct TCGCumulativeArgs { | ||
53 | @@ -XXX,XX +XXX,XX @@ static void tcg_context_init(unsigned max_cpus) | ||
54 | nargs = DIV_ROUND_UP(nargs, 3); | ||
55 | |||
56 | ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); | ||
57 | - ca->cif.rtype = typecode_to_ffi[typemask & 7]; | ||
58 | + ca->cif.rtype = typecode_to_ffi(typemask & 7); | ||
59 | ca->cif.nargs = nargs; | ||
60 | |||
61 | if (nargs != 0) { | ||
62 | ca->cif.arg_types = ca->args; | ||
63 | for (int j = 0; j < nargs; ++j) { | ||
64 | int typecode = extract32(typemask, (j + 1) * 3, 3); | ||
65 | - ca->args[j] = typecode_to_ffi[typecode]; | ||
66 | + ca->args[j] = typecode_to_ffi(typecode); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | -- | ||
71 | 2.34.1 | ||
72 | |||
73 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
1 | 2 | ||
3 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
4 | Message-Id: <20221111074101.2069454-27-richard.henderson@linaro.org> | ||
5 | [PMD: Split from bigger patch] | ||
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
8 | Message-Id: <20221122180804.938-3-philmd@linaro.org> | ||
9 | --- | ||
10 | tcg/tcg.c | 83 +++++++++++++++++++++++++++++-------------------------- | ||
11 | 1 file changed, 44 insertions(+), 39 deletions(-) | ||
12 | |||
13 | diff --git a/tcg/tcg.c b/tcg/tcg.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/tcg/tcg.c | ||
16 | +++ b/tcg/tcg.c | ||
17 | @@ -XXX,XX +XXX,XX @@ static ffi_type *typecode_to_ffi(int argmask) | ||
18 | } | ||
19 | g_assert_not_reached(); | ||
20 | } | ||
21 | -#endif | ||
22 | + | ||
23 | +static void init_ffi_layouts(void) | ||
24 | +{ | ||
25 | + /* g_direct_hash/equal for direct comparisons on uint32_t. */ | ||
26 | + ffi_table = g_hash_table_new(NULL, NULL); | ||
27 | + for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) { | ||
28 | + uint32_t typemask = all_helpers[i].typemask; | ||
29 | + gpointer hash = (gpointer)(uintptr_t)typemask; | ||
30 | + struct { | ||
31 | + ffi_cif cif; | ||
32 | + ffi_type *args[]; | ||
33 | + } *ca; | ||
34 | + ffi_status status; | ||
35 | + int nargs; | ||
36 | + | ||
37 | + if (g_hash_table_lookup(ffi_table, hash)) { | ||
38 | + continue; | ||
39 | + } | ||
40 | + | ||
41 | + /* Ignoring the return type, find the last non-zero field. */ | ||
42 | + nargs = 32 - clz32(typemask >> 3); | ||
43 | + nargs = DIV_ROUND_UP(nargs, 3); | ||
44 | + | ||
45 | + ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); | ||
46 | + ca->cif.rtype = typecode_to_ffi(typemask & 7); | ||
47 | + ca->cif.nargs = nargs; | ||
48 | + | ||
49 | + if (nargs != 0) { | ||
50 | + ca->cif.arg_types = ca->args; | ||
51 | + for (int j = 0; j < nargs; ++j) { | ||
52 | + int typecode = extract32(typemask, (j + 1) * 3, 3); | ||
53 | + ca->args[j] = typecode_to_ffi(typecode); | ||
54 | + } | ||
55 | + } | ||
56 | + | ||
57 | + status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, | ||
58 | + ca->cif.rtype, ca->cif.arg_types); | ||
59 | + assert(status == FFI_OK); | ||
60 | + | ||
61 | + g_hash_table_insert(ffi_table, hash, (gpointer)&ca->cif); | ||
62 | + } | ||
63 | +} | ||
64 | +#endif /* CONFIG_TCG_INTERPRETER */ | ||
65 | |||
66 | typedef struct TCGCumulativeArgs { | ||
67 | int arg_idx; /* tcg_gen_callN args[] */ | ||
68 | @@ -XXX,XX +XXX,XX @@ static void tcg_context_init(unsigned max_cpus) | ||
69 | } | ||
70 | |||
71 | #ifdef CONFIG_TCG_INTERPRETER | ||
72 | - /* g_direct_hash/equal for direct comparisons on uint32_t. */ | ||
73 | - ffi_table = g_hash_table_new(NULL, NULL); | ||
74 | - for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { | ||
75 | - struct { | ||
76 | - ffi_cif cif; | ||
77 | - ffi_type *args[]; | ||
78 | - } *ca; | ||
79 | - uint32_t typemask = all_helpers[i].typemask; | ||
80 | - gpointer hash = (gpointer)(uintptr_t)typemask; | ||
81 | - ffi_status status; | ||
82 | - int nargs; | ||
83 | - | ||
84 | - if (g_hash_table_lookup(ffi_table, hash)) { | ||
85 | - continue; | ||
86 | - } | ||
87 | - | ||
88 | - /* Ignoring the return type, find the last non-zero field. */ | ||
89 | - nargs = 32 - clz32(typemask >> 3); | ||
90 | - nargs = DIV_ROUND_UP(nargs, 3); | ||
91 | - | ||
92 | - ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); | ||
93 | - ca->cif.rtype = typecode_to_ffi(typemask & 7); | ||
94 | - ca->cif.nargs = nargs; | ||
95 | - | ||
96 | - if (nargs != 0) { | ||
97 | - ca->cif.arg_types = ca->args; | ||
98 | - for (int j = 0; j < nargs; ++j) { | ||
99 | - int typecode = extract32(typemask, (j + 1) * 3, 3); | ||
100 | - ca->args[j] = typecode_to_ffi(typecode); | ||
101 | - } | ||
102 | - } | ||
103 | - | ||
104 | - status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs, | ||
105 | - ca->cif.rtype, ca->cif.arg_types); | ||
106 | - assert(status == FFI_OK); | ||
107 | - | ||
108 | - g_hash_table_insert(ffi_table, hash, (gpointer)&ca->cif); | ||
109 | - } | ||
110 | + init_ffi_layouts(); | ||
111 | #endif | ||
112 | |||
113 | tcg_target_init(s); | ||
114 | -- | ||
115 | 2.34.1 | ||
116 | |||
117 | diff view generated by jsdifflib |
1 | This exports the constraint sets from tcg_target_op_def to | 1 | Instead of requiring a separate hash table lookup, |
---|---|---|---|
2 | a place we will be able to manipulate more in future. | 2 | put a pointer to the CIF into TCGHelperInfo. |
3 | 3 | ||
4 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
5 | Message-Id: <20221111074101.2069454-27-richard.henderson@linaro.org> | ||
6 | [PMD: Split from bigger patch] | ||
7 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
8 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
9 | Message-Id: <20221122180804.938-4-philmd@linaro.org> | ||
6 | --- | 10 | --- |
7 | tcg/i386/tcg-target-con-set.h | 55 ++++++++++ | 11 | tcg/tcg-internal.h | 7 +++++++ |
8 | tcg/i386/tcg-target.h | 1 + | 12 | tcg/tcg.c | 30 ++++++++++++++---------------- |
9 | tcg/tcg.c | 119 +++++++++++++++++++++ | 13 | 2 files changed, 21 insertions(+), 16 deletions(-) |
10 | tcg/i386/tcg-target.c.inc | 194 ++++++++++++---------------------- | ||
11 | 4 files changed, 242 insertions(+), 127 deletions(-) | ||
12 | create mode 100644 tcg/i386/tcg-target-con-set.h | ||
13 | 14 | ||
14 | diff --git a/tcg/i386/tcg-target-con-set.h b/tcg/i386/tcg-target-con-set.h | 15 | diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h |
15 | new file mode 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
16 | index XXXXXXX..XXXXXXX | 17 | --- a/tcg/tcg-internal.h |
17 | --- /dev/null | 18 | +++ b/tcg/tcg-internal.h |
18 | +++ b/tcg/i386/tcg-target-con-set.h | ||
19 | @@ -XXX,XX +XXX,XX @@ | 19 | @@ -XXX,XX +XXX,XX @@ |
20 | +/* SPDX-License-Identifier: MIT */ | 20 | #ifndef TCG_INTERNAL_H |
21 | +/* | 21 | #define TCG_INTERNAL_H |
22 | + * Define i386 target-specific constraint sets. | 22 | |
23 | + * Copyright (c) 2021 Linaro | 23 | +#ifdef CONFIG_TCG_INTERPRETER |
24 | + */ | 24 | +#include <ffi.h> |
25 | +#endif | ||
25 | + | 26 | + |
26 | +/* | 27 | #define TCG_HIGHWATER 1024 |
27 | + * C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs. | 28 | |
28 | + * Each operand should be a sequence of constraint letters as defined by | 29 | /* |
29 | + * tcg-target-con-str.h; the constraint combination is inclusive or. | 30 | @@ -XXX,XX +XXX,XX @@ typedef struct TCGCallArgumentLoc { |
30 | + * | 31 | typedef struct TCGHelperInfo { |
31 | + * C_N1_Im(...) defines a constraint set with 1 output and <m> inputs, | 32 | void *func; |
32 | + * except that the output must use a new register. | 33 | const char *name; |
33 | + */ | 34 | +#ifdef CONFIG_TCG_INTERPRETER |
34 | +C_O0_I1(r) | 35 | + ffi_cif *cif; |
35 | +C_O0_I2(L, L) | 36 | +#endif |
36 | +C_O0_I2(qi, r) | 37 | unsigned typemask : 32; |
37 | +C_O0_I2(re, r) | 38 | unsigned flags : 8; |
38 | +C_O0_I2(ri, r) | 39 | unsigned nr_in : 8; |
39 | +C_O0_I2(r, re) | ||
40 | +C_O0_I2(s, L) | ||
41 | +C_O0_I2(x, r) | ||
42 | +C_O0_I3(L, L, L) | ||
43 | +C_O0_I3(s, L, L) | ||
44 | +C_O0_I4(L, L, L, L) | ||
45 | +C_O0_I4(r, r, ri, ri) | ||
46 | +C_O1_I1(r, 0) | ||
47 | +C_O1_I1(r, L) | ||
48 | +C_O1_I1(r, q) | ||
49 | +C_O1_I1(r, r) | ||
50 | +C_O1_I1(x, r) | ||
51 | +C_O1_I1(x, x) | ||
52 | +C_O1_I2(Q, 0, Q) | ||
53 | +C_O1_I2(q, r, re) | ||
54 | +C_O1_I2(r, 0, ci) | ||
55 | +C_O1_I2(r, 0, r) | ||
56 | +C_O1_I2(r, 0, re) | ||
57 | +C_O1_I2(r, 0, reZ) | ||
58 | +C_O1_I2(r, 0, ri) | ||
59 | +C_O1_I2(r, 0, rI) | ||
60 | +C_O1_I2(r, L, L) | ||
61 | +C_O1_I2(r, r, re) | ||
62 | +C_O1_I2(r, r, ri) | ||
63 | +C_O1_I2(r, r, rI) | ||
64 | +C_O1_I2(x, x, x) | ||
65 | +C_N1_I2(r, r, r) | ||
66 | +C_N1_I2(r, r, rW) | ||
67 | +C_O1_I3(x, x, x, x) | ||
68 | +C_O1_I4(r, r, re, r, 0) | ||
69 | +C_O1_I4(r, r, r, ri, ri) | ||
70 | +C_O2_I1(r, r, L) | ||
71 | +C_O2_I2(a, d, a, r) | ||
72 | +C_O2_I2(r, r, L, L) | ||
73 | +C_O2_I3(a, d, 0, 1, r) | ||
74 | +C_O2_I4(r, r, 0, 1, re, re) | ||
75 | diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h | ||
76 | index XXXXXXX..XXXXXXX 100644 | ||
77 | --- a/tcg/i386/tcg-target.h | ||
78 | +++ b/tcg/i386/tcg-target.h | ||
79 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | ||
80 | #define TCG_TARGET_NEED_LDST_LABELS | ||
81 | #endif | ||
82 | #define TCG_TARGET_NEED_POOL_LABELS | ||
83 | +#define TCG_TARGET_CON_SET_H | ||
84 | |||
85 | #endif | ||
86 | diff --git a/tcg/tcg.c b/tcg/tcg.c | 40 | diff --git a/tcg/tcg.c b/tcg/tcg.c |
87 | index XXXXXXX..XXXXXXX 100644 | 41 | index XXXXXXX..XXXXXXX 100644 |
88 | --- a/tcg/tcg.c | 42 | --- a/tcg/tcg.c |
89 | +++ b/tcg/tcg.c | 43 | +++ b/tcg/tcg.c |
90 | @@ -XXX,XX +XXX,XX @@ | 44 | @@ -XXX,XX +XXX,XX @@ |
45 | #include "tcg/tcg-ldst.h" | ||
46 | #include "tcg-internal.h" | ||
47 | |||
48 | -#ifdef CONFIG_TCG_INTERPRETER | ||
49 | -#include <ffi.h> | ||
50 | -#endif | ||
51 | - | ||
91 | /* Forward declarations for functions declared in tcg-target.c.inc and | 52 | /* Forward declarations for functions declared in tcg-target.c.inc and |
92 | used here. */ | 53 | used here. */ |
93 | static void tcg_target_init(TCGContext *s); | 54 | static void tcg_target_init(TCGContext *s); |
94 | +#ifndef TCG_TARGET_CON_SET_H | 55 | @@ -XXX,XX +XXX,XX @@ static TCGHelperInfo all_helpers[] = { |
95 | static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode); | 56 | static GHashTable *helper_table; |
96 | +#endif | 57 | |
97 | static void tcg_target_qemu_prologue(TCGContext *s); | 58 | #ifdef CONFIG_TCG_INTERPRETER |
98 | static bool patch_reloc(tcg_insn_unit *code_ptr, int type, | 59 | -static GHashTable *ffi_table; |
99 | intptr_t value, intptr_t addend); | 60 | - |
100 | @@ -XXX,XX +XXX,XX @@ static void set_jmp_reset_offset(TCGContext *s, int which) | 61 | static ffi_type *typecode_to_ffi(int argmask) |
101 | s->tb_jmp_reset_offset[which] = tcg_current_code_size(s); | 62 | { |
102 | } | 63 | switch (argmask) { |
103 | 64 | @@ -XXX,XX +XXX,XX @@ static ffi_type *typecode_to_ffi(int argmask) | |
104 | +#ifdef TCG_TARGET_CON_SET_H | 65 | static void init_ffi_layouts(void) |
105 | +#define C_PFX1(P, A) P##A | 66 | { |
106 | +#define C_PFX2(P, A, B) P##A##_##B | 67 | /* g_direct_hash/equal for direct comparisons on uint32_t. */ |
107 | +#define C_PFX3(P, A, B, C) P##A##_##B##_##C | 68 | - ffi_table = g_hash_table_new(NULL, NULL); |
108 | +#define C_PFX4(P, A, B, C, D) P##A##_##B##_##C##_##D | 69 | + GHashTable *ffi_table = g_hash_table_new(NULL, NULL); |
109 | +#define C_PFX5(P, A, B, C, D, E) P##A##_##B##_##C##_##D##_##E | ||
110 | +#define C_PFX6(P, A, B, C, D, E, F) P##A##_##B##_##C##_##D##_##E##_##F | ||
111 | + | 70 | + |
112 | +/* Define an enumeration for the various combinations. */ | 71 | for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) { |
113 | + | 72 | - uint32_t typemask = all_helpers[i].typemask; |
114 | +#define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1), | 73 | + TCGHelperInfo *info = &all_helpers[i]; |
115 | +#define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2), | 74 | + unsigned typemask = info->typemask; |
116 | +#define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3), | 75 | gpointer hash = (gpointer)(uintptr_t)typemask; |
117 | +#define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4), | 76 | struct { |
118 | + | 77 | ffi_cif cif; |
119 | +#define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1), | 78 | @@ -XXX,XX +XXX,XX @@ static void init_ffi_layouts(void) |
120 | +#define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2), | 79 | } *ca; |
121 | +#define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3), | 80 | ffi_status status; |
122 | +#define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), | 81 | int nargs; |
123 | + | 82 | + ffi_cif *cif; |
124 | +#define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), | 83 | |
125 | + | 84 | - if (g_hash_table_lookup(ffi_table, hash)) { |
126 | +#define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), | 85 | + cif = g_hash_table_lookup(ffi_table, hash); |
127 | +#define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2), | 86 | + if (cif) { |
128 | +#define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3), | 87 | + info->cif = cif; |
129 | +#define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4), | ||
130 | + | ||
131 | +typedef enum { | ||
132 | +#include "tcg-target-con-set.h" | ||
133 | +} TCGConstraintSetIndex; | ||
134 | + | ||
135 | +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode); | ||
136 | + | ||
137 | +#undef C_O0_I1 | ||
138 | +#undef C_O0_I2 | ||
139 | +#undef C_O0_I3 | ||
140 | +#undef C_O0_I4 | ||
141 | +#undef C_O1_I1 | ||
142 | +#undef C_O1_I2 | ||
143 | +#undef C_O1_I3 | ||
144 | +#undef C_O1_I4 | ||
145 | +#undef C_N1_I2 | ||
146 | +#undef C_O2_I1 | ||
147 | +#undef C_O2_I2 | ||
148 | +#undef C_O2_I3 | ||
149 | +#undef C_O2_I4 | ||
150 | + | ||
151 | +/* Put all of the constraint sets into an array, indexed by the enum. */ | ||
152 | + | ||
153 | +#define C_O0_I1(I1) { .args_ct_str = { #I1 } }, | ||
154 | +#define C_O0_I2(I1, I2) { .args_ct_str = { #I1, #I2 } }, | ||
155 | +#define C_O0_I3(I1, I2, I3) { .args_ct_str = { #I1, #I2, #I3 } }, | ||
156 | +#define C_O0_I4(I1, I2, I3, I4) { .args_ct_str = { #I1, #I2, #I3, #I4 } }, | ||
157 | + | ||
158 | +#define C_O1_I1(O1, I1) { .args_ct_str = { #O1, #I1 } }, | ||
159 | +#define C_O1_I2(O1, I1, I2) { .args_ct_str = { #O1, #I1, #I2 } }, | ||
160 | +#define C_O1_I3(O1, I1, I2, I3) { .args_ct_str = { #O1, #I1, #I2, #I3 } }, | ||
161 | +#define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } }, | ||
162 | + | ||
163 | +#define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } }, | ||
164 | + | ||
165 | +#define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } }, | ||
166 | +#define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } }, | ||
167 | +#define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } }, | ||
168 | +#define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } }, | ||
169 | + | ||
170 | +static const TCGTargetOpDef constraint_sets[] = { | ||
171 | +#include "tcg-target-con-set.h" | ||
172 | +}; | ||
173 | + | ||
174 | + | ||
175 | +#undef C_O0_I1 | ||
176 | +#undef C_O0_I2 | ||
177 | +#undef C_O0_I3 | ||
178 | +#undef C_O0_I4 | ||
179 | +#undef C_O1_I1 | ||
180 | +#undef C_O1_I2 | ||
181 | +#undef C_O1_I3 | ||
182 | +#undef C_O1_I4 | ||
183 | +#undef C_N1_I2 | ||
184 | +#undef C_O2_I1 | ||
185 | +#undef C_O2_I2 | ||
186 | +#undef C_O2_I3 | ||
187 | +#undef C_O2_I4 | ||
188 | + | ||
189 | +/* Expand the enumerator to be returned from tcg_target_op_def(). */ | ||
190 | + | ||
191 | +#define C_O0_I1(I1) C_PFX1(c_o0_i1_, I1) | ||
192 | +#define C_O0_I2(I1, I2) C_PFX2(c_o0_i2_, I1, I2) | ||
193 | +#define C_O0_I3(I1, I2, I3) C_PFX3(c_o0_i3_, I1, I2, I3) | ||
194 | +#define C_O0_I4(I1, I2, I3, I4) C_PFX4(c_o0_i4_, I1, I2, I3, I4) | ||
195 | + | ||
196 | +#define C_O1_I1(O1, I1) C_PFX2(c_o1_i1_, O1, I1) | ||
197 | +#define C_O1_I2(O1, I1, I2) C_PFX3(c_o1_i2_, O1, I1, I2) | ||
198 | +#define C_O1_I3(O1, I1, I2, I3) C_PFX4(c_o1_i3_, O1, I1, I2, I3) | ||
199 | +#define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4) | ||
200 | + | ||
201 | +#define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2) | ||
202 | + | ||
203 | +#define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1) | ||
204 | +#define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2) | ||
205 | +#define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3) | ||
206 | +#define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) | ||
207 | + | ||
208 | +#endif /* TCG_TARGET_CON_SET_H */ | ||
209 | + | ||
210 | #include "tcg-target.c.inc" | ||
211 | |||
212 | /* compare a pointer @ptr and a tb_tc @s */ | ||
213 | @@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s) | ||
214 | continue; | 88 | continue; |
215 | } | 89 | } |
216 | 90 | ||
217 | +#ifdef TCG_TARGET_CON_SET_H | 91 | @@ -XXX,XX +XXX,XX @@ static void init_ffi_layouts(void) |
218 | + /* | 92 | ca->cif.rtype, ca->cif.arg_types); |
219 | + * Macro magic should make it impossible, but double-check that | 93 | assert(status == FFI_OK); |
220 | + * the array index is in range. Since the signness of an enum | 94 | |
221 | + * is implementation defined, force the result to unsigned. | 95 | - g_hash_table_insert(ffi_table, hash, (gpointer)&ca->cif); |
222 | + */ | 96 | + cif = &ca->cif; |
223 | + unsigned con_set = tcg_target_op_def(op); | 97 | + info->cif = cif; |
224 | + tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); | 98 | + g_hash_table_insert(ffi_table, hash, (gpointer)cif); |
225 | + tdefs = &constraint_sets[con_set]; | ||
226 | +#else | ||
227 | tdefs = tcg_target_op_def(op); | ||
228 | /* Missing TCGTargetOpDef entry. */ | ||
229 | tcg_debug_assert(tdefs != NULL); | ||
230 | +#endif | ||
231 | |||
232 | for (i = 0; i < nb_args; i++) { | ||
233 | const char *ct_str = tdefs->args_ct_str[i]; | ||
234 | diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc | ||
235 | index XXXXXXX..XXXXXXX 100644 | ||
236 | --- a/tcg/i386/tcg-target.c.inc | ||
237 | +++ b/tcg/i386/tcg-target.c.inc | ||
238 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, | ||
239 | } | 99 | } |
100 | + | ||
101 | + g_hash_table_destroy(ffi_table); | ||
240 | } | 102 | } |
241 | 103 | #endif /* CONFIG_TCG_INTERPRETER */ | |
242 | -static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | 104 | |
243 | +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) | 105 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) |
244 | { | 106 | } |
245 | - static const TCGTargetOpDef r = { .args_ct_str = { "r" } }; | 107 | |
246 | - static const TCGTargetOpDef ri_r = { .args_ct_str = { "ri", "r" } }; | 108 | #ifdef CONFIG_TCG_INTERPRETER |
247 | - static const TCGTargetOpDef re_r = { .args_ct_str = { "re", "r" } }; | 109 | - { |
248 | - static const TCGTargetOpDef qi_r = { .args_ct_str = { "qi", "r" } }; | 110 | - gpointer hash = (gpointer)(uintptr_t)info->typemask; |
249 | - static const TCGTargetOpDef r_r = { .args_ct_str = { "r", "r" } }; | 111 | - ffi_cif *cif = g_hash_table_lookup(ffi_table, hash); |
250 | - static const TCGTargetOpDef r_q = { .args_ct_str = { "r", "q" } }; | 112 | - assert(cif != NULL); |
251 | - static const TCGTargetOpDef r_re = { .args_ct_str = { "r", "re" } }; | 113 | - tcg_out_call(s, tcg_call_func(op), cif); |
252 | - static const TCGTargetOpDef r_0 = { .args_ct_str = { "r", "0" } }; | 114 | - } |
253 | - static const TCGTargetOpDef r_r_ri = { .args_ct_str = { "r", "r", "ri" } }; | 115 | + tcg_out_call(s, tcg_call_func(op), info->cif); |
254 | - static const TCGTargetOpDef r_r_re = { .args_ct_str = { "r", "r", "re" } }; | 116 | #else |
255 | - static const TCGTargetOpDef r_0_r = { .args_ct_str = { "r", "0", "r" } }; | 117 | tcg_out_call(s, tcg_call_func(op)); |
256 | - static const TCGTargetOpDef r_0_re = { .args_ct_str = { "r", "0", "re" } }; | ||
257 | - static const TCGTargetOpDef r_0_ci = { .args_ct_str = { "r", "0", "ci" } }; | ||
258 | - static const TCGTargetOpDef r_L = { .args_ct_str = { "r", "L" } }; | ||
259 | - static const TCGTargetOpDef L_L = { .args_ct_str = { "L", "L" } }; | ||
260 | - static const TCGTargetOpDef s_L = { .args_ct_str = { "s", "L" } }; | ||
261 | - static const TCGTargetOpDef r_L_L = { .args_ct_str = { "r", "L", "L" } }; | ||
262 | - static const TCGTargetOpDef r_r_L = { .args_ct_str = { "r", "r", "L" } }; | ||
263 | - static const TCGTargetOpDef L_L_L = { .args_ct_str = { "L", "L", "L" } }; | ||
264 | - static const TCGTargetOpDef s_L_L = { .args_ct_str = { "s", "L", "L" } }; | ||
265 | - static const TCGTargetOpDef r_r_L_L | ||
266 | - = { .args_ct_str = { "r", "r", "L", "L" } }; | ||
267 | - static const TCGTargetOpDef L_L_L_L | ||
268 | - = { .args_ct_str = { "L", "L", "L", "L" } }; | ||
269 | - static const TCGTargetOpDef x_x = { .args_ct_str = { "x", "x" } }; | ||
270 | - static const TCGTargetOpDef x_x_x = { .args_ct_str = { "x", "x", "x" } }; | ||
271 | - static const TCGTargetOpDef x_x_x_x | ||
272 | - = { .args_ct_str = { "x", "x", "x", "x" } }; | ||
273 | - static const TCGTargetOpDef x_r = { .args_ct_str = { "x", "r" } }; | ||
274 | - | ||
275 | switch (op) { | ||
276 | case INDEX_op_goto_ptr: | ||
277 | - return &r; | ||
278 | + return C_O0_I1(r); | ||
279 | |||
280 | case INDEX_op_ld8u_i32: | ||
281 | case INDEX_op_ld8u_i64: | ||
282 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
283 | case INDEX_op_ld32u_i64: | ||
284 | case INDEX_op_ld32s_i64: | ||
285 | case INDEX_op_ld_i64: | ||
286 | - return &r_r; | ||
287 | + return C_O1_I1(r, r); | ||
288 | |||
289 | case INDEX_op_st8_i32: | ||
290 | case INDEX_op_st8_i64: | ||
291 | - return &qi_r; | ||
292 | + return C_O0_I2(qi, r); | ||
293 | + | ||
294 | case INDEX_op_st16_i32: | ||
295 | case INDEX_op_st16_i64: | ||
296 | case INDEX_op_st_i32: | ||
297 | case INDEX_op_st32_i64: | ||
298 | - return &ri_r; | ||
299 | + return C_O0_I2(ri, r); | ||
300 | + | ||
301 | case INDEX_op_st_i64: | ||
302 | - return &re_r; | ||
303 | + return C_O0_I2(re, r); | ||
304 | |||
305 | case INDEX_op_add_i32: | ||
306 | case INDEX_op_add_i64: | ||
307 | - return &r_r_re; | ||
308 | + return C_O1_I2(r, r, re); | ||
309 | + | ||
310 | case INDEX_op_sub_i32: | ||
311 | case INDEX_op_sub_i64: | ||
312 | case INDEX_op_mul_i32: | ||
313 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
314 | case INDEX_op_or_i64: | ||
315 | case INDEX_op_xor_i32: | ||
316 | case INDEX_op_xor_i64: | ||
317 | - return &r_0_re; | ||
318 | + return C_O1_I2(r, 0, re); | ||
319 | |||
320 | case INDEX_op_and_i32: | ||
321 | case INDEX_op_and_i64: | ||
322 | - { | ||
323 | - static const TCGTargetOpDef and | ||
324 | - = { .args_ct_str = { "r", "0", "reZ" } }; | ||
325 | - return ∧ | ||
326 | - } | ||
327 | - break; | ||
328 | + return C_O1_I2(r, 0, reZ); | ||
329 | + | ||
330 | case INDEX_op_andc_i32: | ||
331 | case INDEX_op_andc_i64: | ||
332 | - { | ||
333 | - static const TCGTargetOpDef andc | ||
334 | - = { .args_ct_str = { "r", "r", "rI" } }; | ||
335 | - return &andc; | ||
336 | - } | ||
337 | - break; | ||
338 | + return C_O1_I2(r, r, rI); | ||
339 | |||
340 | case INDEX_op_shl_i32: | ||
341 | case INDEX_op_shl_i64: | ||
342 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
343 | case INDEX_op_shr_i64: | ||
344 | case INDEX_op_sar_i32: | ||
345 | case INDEX_op_sar_i64: | ||
346 | - return have_bmi2 ? &r_r_ri : &r_0_ci; | ||
347 | + return have_bmi2 ? C_O1_I2(r, r, ri) : C_O1_I2(r, 0, ci); | ||
348 | + | ||
349 | case INDEX_op_rotl_i32: | ||
350 | case INDEX_op_rotl_i64: | ||
351 | case INDEX_op_rotr_i32: | ||
352 | case INDEX_op_rotr_i64: | ||
353 | - return &r_0_ci; | ||
354 | + return C_O1_I2(r, 0, ci); | ||
355 | |||
356 | case INDEX_op_brcond_i32: | ||
357 | case INDEX_op_brcond_i64: | ||
358 | - return &r_re; | ||
359 | + return C_O0_I2(r, re); | ||
360 | |||
361 | case INDEX_op_bswap16_i32: | ||
362 | case INDEX_op_bswap16_i64: | ||
363 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
364 | case INDEX_op_not_i32: | ||
365 | case INDEX_op_not_i64: | ||
366 | case INDEX_op_extrh_i64_i32: | ||
367 | - return &r_0; | ||
368 | + return C_O1_I1(r, 0); | ||
369 | |||
370 | case INDEX_op_ext8s_i32: | ||
371 | case INDEX_op_ext8s_i64: | ||
372 | case INDEX_op_ext8u_i32: | ||
373 | case INDEX_op_ext8u_i64: | ||
374 | - return &r_q; | ||
375 | + return C_O1_I1(r, q); | ||
376 | + | ||
377 | case INDEX_op_ext16s_i32: | ||
378 | case INDEX_op_ext16s_i64: | ||
379 | case INDEX_op_ext16u_i32: | ||
380 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
381 | case INDEX_op_sextract_i32: | ||
382 | case INDEX_op_ctpop_i32: | ||
383 | case INDEX_op_ctpop_i64: | ||
384 | - return &r_r; | ||
385 | + return C_O1_I1(r, r); | ||
386 | + | ||
387 | case INDEX_op_extract2_i32: | ||
388 | case INDEX_op_extract2_i64: | ||
389 | - return &r_0_r; | ||
390 | + return C_O1_I2(r, 0, r); | ||
391 | |||
392 | case INDEX_op_deposit_i32: | ||
393 | case INDEX_op_deposit_i64: | ||
394 | - { | ||
395 | - static const TCGTargetOpDef dep | ||
396 | - = { .args_ct_str = { "Q", "0", "Q" } }; | ||
397 | - return &dep; | ||
398 | - } | ||
399 | + return C_O1_I2(Q, 0, Q); | ||
400 | + | ||
401 | case INDEX_op_setcond_i32: | ||
402 | case INDEX_op_setcond_i64: | ||
403 | - { | ||
404 | - static const TCGTargetOpDef setc | ||
405 | - = { .args_ct_str = { "q", "r", "re" } }; | ||
406 | - return &setc; | ||
407 | - } | ||
408 | + return C_O1_I2(q, r, re); | ||
409 | + | ||
410 | case INDEX_op_movcond_i32: | ||
411 | case INDEX_op_movcond_i64: | ||
412 | - { | ||
413 | - static const TCGTargetOpDef movc | ||
414 | - = { .args_ct_str = { "r", "r", "re", "r", "0" } }; | ||
415 | - return &movc; | ||
416 | - } | ||
417 | + return C_O1_I4(r, r, re, r, 0); | ||
418 | + | ||
419 | case INDEX_op_div2_i32: | ||
420 | case INDEX_op_div2_i64: | ||
421 | case INDEX_op_divu2_i32: | ||
422 | case INDEX_op_divu2_i64: | ||
423 | - { | ||
424 | - static const TCGTargetOpDef div2 | ||
425 | - = { .args_ct_str = { "a", "d", "0", "1", "r" } }; | ||
426 | - return &div2; | ||
427 | - } | ||
428 | + return C_O2_I3(a, d, 0, 1, r); | ||
429 | + | ||
430 | case INDEX_op_mulu2_i32: | ||
431 | case INDEX_op_mulu2_i64: | ||
432 | case INDEX_op_muls2_i32: | ||
433 | case INDEX_op_muls2_i64: | ||
434 | - { | ||
435 | - static const TCGTargetOpDef mul2 | ||
436 | - = { .args_ct_str = { "a", "d", "a", "r" } }; | ||
437 | - return &mul2; | ||
438 | - } | ||
439 | + return C_O2_I2(a, d, a, r); | ||
440 | + | ||
441 | case INDEX_op_add2_i32: | ||
442 | case INDEX_op_add2_i64: | ||
443 | case INDEX_op_sub2_i32: | ||
444 | case INDEX_op_sub2_i64: | ||
445 | - { | ||
446 | - static const TCGTargetOpDef arith2 | ||
447 | - = { .args_ct_str = { "r", "r", "0", "1", "re", "re" } }; | ||
448 | - return &arith2; | ||
449 | - } | ||
450 | + return C_O2_I4(r, r, 0, 1, re, re); | ||
451 | + | ||
452 | case INDEX_op_ctz_i32: | ||
453 | case INDEX_op_ctz_i64: | ||
454 | - { | ||
455 | - static const TCGTargetOpDef ctz[2] = { | ||
456 | - { .args_ct_str = { "&r", "r", "r" } }, | ||
457 | - { .args_ct_str = { "&r", "r", "rW" } }, | ||
458 | - }; | ||
459 | - return &ctz[have_bmi1]; | ||
460 | - } | ||
461 | + return have_bmi1 ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r); | ||
462 | + | ||
463 | case INDEX_op_clz_i32: | ||
464 | case INDEX_op_clz_i64: | ||
465 | - { | ||
466 | - static const TCGTargetOpDef clz[2] = { | ||
467 | - { .args_ct_str = { "&r", "r", "r" } }, | ||
468 | - { .args_ct_str = { "&r", "r", "rW" } }, | ||
469 | - }; | ||
470 | - return &clz[have_lzcnt]; | ||
471 | - } | ||
472 | + return have_lzcnt ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r); | ||
473 | |||
474 | case INDEX_op_qemu_ld_i32: | ||
475 | - return TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &r_L : &r_L_L; | ||
476 | + return (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS | ||
477 | + ? C_O1_I1(r, L) : C_O1_I2(r, L, L)); | ||
478 | + | ||
479 | case INDEX_op_qemu_st_i32: | ||
480 | - return TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &L_L : &L_L_L; | ||
481 | + return (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS | ||
482 | + ? C_O0_I2(L, L) : C_O0_I3(L, L, L)); | ||
483 | case INDEX_op_qemu_st8_i32: | ||
484 | - return TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &s_L : &s_L_L; | ||
485 | + return (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS | ||
486 | + ? C_O0_I2(s, L) : C_O0_I3(s, L, L)); | ||
487 | + | ||
488 | case INDEX_op_qemu_ld_i64: | ||
489 | - return (TCG_TARGET_REG_BITS == 64 ? &r_L | ||
490 | - : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &r_r_L | ||
491 | - : &r_r_L_L); | ||
492 | + return (TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, L) | ||
493 | + : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? C_O2_I1(r, r, L) | ||
494 | + : C_O2_I2(r, r, L, L)); | ||
495 | + | ||
496 | case INDEX_op_qemu_st_i64: | ||
497 | - return (TCG_TARGET_REG_BITS == 64 ? &L_L | ||
498 | - : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &L_L_L | ||
499 | - : &L_L_L_L); | ||
500 | + return (TCG_TARGET_REG_BITS == 64 ? C_O0_I2(L, L) | ||
501 | + : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? C_O0_I3(L, L, L) | ||
502 | + : C_O0_I4(L, L, L, L)); | ||
503 | |||
504 | case INDEX_op_brcond2_i32: | ||
505 | - { | ||
506 | - static const TCGTargetOpDef b2 | ||
507 | - = { .args_ct_str = { "r", "r", "ri", "ri" } }; | ||
508 | - return &b2; | ||
509 | - } | ||
510 | + return C_O0_I4(r, r, ri, ri); | ||
511 | + | ||
512 | case INDEX_op_setcond2_i32: | ||
513 | - { | ||
514 | - static const TCGTargetOpDef s2 | ||
515 | - = { .args_ct_str = { "r", "r", "r", "ri", "ri" } }; | ||
516 | - return &s2; | ||
517 | - } | ||
518 | + return C_O1_I4(r, r, r, ri, ri); | ||
519 | |||
520 | case INDEX_op_ld_vec: | ||
521 | - case INDEX_op_st_vec: | ||
522 | case INDEX_op_dupm_vec: | ||
523 | - return &x_r; | ||
524 | + return C_O1_I1(x, r); | ||
525 | + | ||
526 | + case INDEX_op_st_vec: | ||
527 | + return C_O0_I2(x, r); | ||
528 | |||
529 | case INDEX_op_add_vec: | ||
530 | case INDEX_op_sub_vec: | ||
531 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
532 | #if TCG_TARGET_REG_BITS == 32 | ||
533 | case INDEX_op_dup2_vec: | ||
534 | #endif | 118 | #endif |
535 | - return &x_x_x; | ||
536 | + return C_O1_I2(x, x, x); | ||
537 | + | ||
538 | case INDEX_op_abs_vec: | ||
539 | case INDEX_op_dup_vec: | ||
540 | case INDEX_op_shli_vec: | ||
541 | case INDEX_op_shri_vec: | ||
542 | case INDEX_op_sari_vec: | ||
543 | case INDEX_op_x86_psrldq_vec: | ||
544 | - return &x_x; | ||
545 | + return C_O1_I1(x, x); | ||
546 | + | ||
547 | case INDEX_op_x86_vpblendvb_vec: | ||
548 | - return &x_x_x_x; | ||
549 | + return C_O1_I3(x, x, x, x); | ||
550 | |||
551 | default: | ||
552 | - break; | ||
553 | + g_assert_not_reached(); | ||
554 | } | ||
555 | - return NULL; | ||
556 | } | ||
557 | |||
558 | int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) | ||
559 | -- | 119 | -- |
560 | 2.25.1 | 120 | 2.34.1 |
561 | 121 | ||
562 | 122 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | There is only one use, and BLR is perhaps even more |
---|---|---|---|
2 | self-documentary than CALLR. | ||
3 | |||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 6 | --- |
4 | tcg/mips/tcg-target-con-set.h | 36 +++++++++++++ | 7 | tcg/aarch64/tcg-target.c.inc | 7 +------ |
5 | tcg/mips/tcg-target.h | 1 + | 8 | 1 file changed, 1 insertion(+), 6 deletions(-) |
6 | tcg/mips/tcg-target.c.inc | 96 +++++++++++------------------------ | ||
7 | 3 files changed, 66 insertions(+), 67 deletions(-) | ||
8 | create mode 100644 tcg/mips/tcg-target-con-set.h | ||
9 | 9 | ||
10 | diff --git a/tcg/mips/tcg-target-con-set.h b/tcg/mips/tcg-target-con-set.h | 10 | diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc |
11 | new file mode 100644 | ||
12 | index XXXXXXX..XXXXXXX | ||
13 | --- /dev/null | ||
14 | +++ b/tcg/mips/tcg-target-con-set.h | ||
15 | @@ -XXX,XX +XXX,XX @@ | ||
16 | +/* SPDX-License-Identifier: MIT */ | ||
17 | +/* | ||
18 | + * Define MIPS target-specific constraint sets. | ||
19 | + * Copyright (c) 2021 Linaro | ||
20 | + */ | ||
21 | + | ||
22 | +/* | ||
23 | + * C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs. | ||
24 | + * Each operand should be a sequence of constraint letters as defined by | ||
25 | + * tcg-target-con-str.h; the constraint combination is inclusive or. | ||
26 | + */ | ||
27 | +C_O0_I1(r) | ||
28 | +C_O0_I2(rZ, r) | ||
29 | +C_O0_I2(rZ, rZ) | ||
30 | +C_O0_I2(SZ, S) | ||
31 | +C_O0_I3(SZ, S, S) | ||
32 | +C_O0_I3(SZ, SZ, S) | ||
33 | +C_O0_I4(rZ, rZ, rZ, rZ) | ||
34 | +C_O0_I4(SZ, SZ, S, S) | ||
35 | +C_O1_I1(r, L) | ||
36 | +C_O1_I1(r, r) | ||
37 | +C_O1_I2(r, 0, rZ) | ||
38 | +C_O1_I2(r, L, L) | ||
39 | +C_O1_I2(r, r, ri) | ||
40 | +C_O1_I2(r, r, rI) | ||
41 | +C_O1_I2(r, r, rIK) | ||
42 | +C_O1_I2(r, r, rJ) | ||
43 | +C_O1_I2(r, r, rWZ) | ||
44 | +C_O1_I2(r, rZ, rN) | ||
45 | +C_O1_I2(r, rZ, rZ) | ||
46 | +C_O1_I4(r, rZ, rZ, rZ, 0) | ||
47 | +C_O1_I4(r, rZ, rZ, rZ, rZ) | ||
48 | +C_O2_I1(r, r, L) | ||
49 | +C_O2_I2(r, r, L, L) | ||
50 | +C_O2_I2(r, r, r, r) | ||
51 | +C_O2_I4(r, r, rZ, rZ, rN, rN) | ||
52 | diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h | ||
53 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
54 | --- a/tcg/mips/tcg-target.h | 12 | --- a/tcg/aarch64/tcg-target.c.inc |
55 | +++ b/tcg/mips/tcg-target.h | 13 | +++ b/tcg/aarch64/tcg-target.c.inc |
56 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 14 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target) |
57 | #ifdef CONFIG_SOFTMMU | ||
58 | #define TCG_TARGET_NEED_LDST_LABELS | ||
59 | #endif | ||
60 | +#define TCG_TARGET_CON_SET_H | ||
61 | |||
62 | #endif | ||
63 | diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc | ||
64 | index XXXXXXX..XXXXXXX 100644 | ||
65 | --- a/tcg/mips/tcg-target.c.inc | ||
66 | +++ b/tcg/mips/tcg-target.c.inc | ||
67 | @@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, | ||
68 | } | 15 | } |
69 | } | 16 | } |
70 | 17 | ||
71 | -static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | 18 | -static inline void tcg_out_callr(TCGContext *s, TCGReg reg) |
72 | +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) | 19 | -{ |
20 | - tcg_out_insn(s, 3207, BLR, reg); | ||
21 | -} | ||
22 | - | ||
23 | static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) | ||
73 | { | 24 | { |
74 | - static const TCGTargetOpDef r = { .args_ct_str = { "r" } }; | 25 | ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; |
75 | - static const TCGTargetOpDef r_r = { .args_ct_str = { "r", "r" } }; | 26 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) |
76 | - static const TCGTargetOpDef r_L = { .args_ct_str = { "r", "L" } }; | 27 | tcg_out_insn(s, 3206, BL, offset); |
77 | - static const TCGTargetOpDef rZ_r = { .args_ct_str = { "rZ", "r" } }; | 28 | } else { |
78 | - static const TCGTargetOpDef SZ_S = { .args_ct_str = { "SZ", "S" } }; | 29 | tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); |
79 | - static const TCGTargetOpDef rZ_rZ = { .args_ct_str = { "rZ", "rZ" } }; | 30 | - tcg_out_callr(s, TCG_REG_TMP); |
80 | - static const TCGTargetOpDef r_r_L = { .args_ct_str = { "r", "r", "L" } }; | 31 | + tcg_out_insn(s, 3207, BLR, TCG_REG_TMP); |
81 | - static const TCGTargetOpDef r_L_L = { .args_ct_str = { "r", "L", "L" } }; | ||
82 | - static const TCGTargetOpDef r_r_ri = { .args_ct_str = { "r", "r", "ri" } }; | ||
83 | - static const TCGTargetOpDef r_r_rI = { .args_ct_str = { "r", "r", "rI" } }; | ||
84 | - static const TCGTargetOpDef r_r_rJ = { .args_ct_str = { "r", "r", "rJ" } }; | ||
85 | - static const TCGTargetOpDef SZ_S_S = { .args_ct_str = { "SZ", "S", "S" } }; | ||
86 | - static const TCGTargetOpDef SZ_SZ_S | ||
87 | - = { .args_ct_str = { "SZ", "SZ", "S" } }; | ||
88 | - static const TCGTargetOpDef SZ_SZ_S_S | ||
89 | - = { .args_ct_str = { "SZ", "SZ", "S", "S" } }; | ||
90 | - static const TCGTargetOpDef r_rZ_rN | ||
91 | - = { .args_ct_str = { "r", "rZ", "rN" } }; | ||
92 | - static const TCGTargetOpDef r_rZ_rZ | ||
93 | - = { .args_ct_str = { "r", "rZ", "rZ" } }; | ||
94 | - static const TCGTargetOpDef r_r_rIK | ||
95 | - = { .args_ct_str = { "r", "r", "rIK" } }; | ||
96 | - static const TCGTargetOpDef r_r_rWZ | ||
97 | - = { .args_ct_str = { "r", "r", "rWZ" } }; | ||
98 | - static const TCGTargetOpDef r_r_r_r | ||
99 | - = { .args_ct_str = { "r", "r", "r", "r" } }; | ||
100 | - static const TCGTargetOpDef r_r_L_L | ||
101 | - = { .args_ct_str = { "r", "r", "L", "L" } }; | ||
102 | - static const TCGTargetOpDef dep | ||
103 | - = { .args_ct_str = { "r", "0", "rZ" } }; | ||
104 | - static const TCGTargetOpDef movc | ||
105 | - = { .args_ct_str = { "r", "rZ", "rZ", "rZ", "0" } }; | ||
106 | - static const TCGTargetOpDef movc_r6 | ||
107 | - = { .args_ct_str = { "r", "rZ", "rZ", "rZ", "rZ" } }; | ||
108 | - static const TCGTargetOpDef add2 | ||
109 | - = { .args_ct_str = { "r", "r", "rZ", "rZ", "rN", "rN" } }; | ||
110 | - static const TCGTargetOpDef br2 | ||
111 | - = { .args_ct_str = { "rZ", "rZ", "rZ", "rZ" } }; | ||
112 | - static const TCGTargetOpDef setc2 | ||
113 | - = { .args_ct_str = { "r", "rZ", "rZ", "rZ", "rZ" } }; | ||
114 | - | ||
115 | switch (op) { | ||
116 | case INDEX_op_goto_ptr: | ||
117 | - return &r; | ||
118 | + return C_O0_I1(r); | ||
119 | |||
120 | case INDEX_op_ld8u_i32: | ||
121 | case INDEX_op_ld8s_i32: | ||
122 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
123 | case INDEX_op_extrl_i64_i32: | ||
124 | case INDEX_op_extrh_i64_i32: | ||
125 | case INDEX_op_extract_i64: | ||
126 | - return &r_r; | ||
127 | + return C_O1_I1(r, r); | ||
128 | |||
129 | case INDEX_op_st8_i32: | ||
130 | case INDEX_op_st16_i32: | ||
131 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
132 | case INDEX_op_st16_i64: | ||
133 | case INDEX_op_st32_i64: | ||
134 | case INDEX_op_st_i64: | ||
135 | - return &rZ_r; | ||
136 | + return C_O0_I2(rZ, r); | ||
137 | |||
138 | case INDEX_op_add_i32: | ||
139 | case INDEX_op_add_i64: | ||
140 | - return &r_r_rJ; | ||
141 | + return C_O1_I2(r, r, rJ); | ||
142 | case INDEX_op_sub_i32: | ||
143 | case INDEX_op_sub_i64: | ||
144 | - return &r_rZ_rN; | ||
145 | + return C_O1_I2(r, rZ, rN); | ||
146 | case INDEX_op_mul_i32: | ||
147 | case INDEX_op_mulsh_i32: | ||
148 | case INDEX_op_muluh_i32: | ||
149 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
150 | case INDEX_op_remu_i64: | ||
151 | case INDEX_op_nor_i64: | ||
152 | case INDEX_op_setcond_i64: | ||
153 | - return &r_rZ_rZ; | ||
154 | + return C_O1_I2(r, rZ, rZ); | ||
155 | case INDEX_op_muls2_i32: | ||
156 | case INDEX_op_mulu2_i32: | ||
157 | case INDEX_op_muls2_i64: | ||
158 | case INDEX_op_mulu2_i64: | ||
159 | - return &r_r_r_r; | ||
160 | + return C_O2_I2(r, r, r, r); | ||
161 | case INDEX_op_and_i32: | ||
162 | case INDEX_op_and_i64: | ||
163 | - return &r_r_rIK; | ||
164 | + return C_O1_I2(r, r, rIK); | ||
165 | case INDEX_op_or_i32: | ||
166 | case INDEX_op_xor_i32: | ||
167 | case INDEX_op_or_i64: | ||
168 | case INDEX_op_xor_i64: | ||
169 | - return &r_r_rI; | ||
170 | + return C_O1_I2(r, r, rI); | ||
171 | case INDEX_op_shl_i32: | ||
172 | case INDEX_op_shr_i32: | ||
173 | case INDEX_op_sar_i32: | ||
174 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
175 | case INDEX_op_sar_i64: | ||
176 | case INDEX_op_rotr_i64: | ||
177 | case INDEX_op_rotl_i64: | ||
178 | - return &r_r_ri; | ||
179 | + return C_O1_I2(r, r, ri); | ||
180 | case INDEX_op_clz_i32: | ||
181 | case INDEX_op_clz_i64: | ||
182 | - return &r_r_rWZ; | ||
183 | + return C_O1_I2(r, r, rWZ); | ||
184 | |||
185 | case INDEX_op_deposit_i32: | ||
186 | case INDEX_op_deposit_i64: | ||
187 | - return &dep; | ||
188 | + return C_O1_I2(r, 0, rZ); | ||
189 | case INDEX_op_brcond_i32: | ||
190 | case INDEX_op_brcond_i64: | ||
191 | - return &rZ_rZ; | ||
192 | + return C_O0_I2(rZ, rZ); | ||
193 | case INDEX_op_movcond_i32: | ||
194 | case INDEX_op_movcond_i64: | ||
195 | - return use_mips32r6_instructions ? &movc_r6 : &movc; | ||
196 | - | ||
197 | + return (use_mips32r6_instructions | ||
198 | + ? C_O1_I4(r, rZ, rZ, rZ, rZ) | ||
199 | + : C_O1_I4(r, rZ, rZ, rZ, 0)); | ||
200 | case INDEX_op_add2_i32: | ||
201 | case INDEX_op_sub2_i32: | ||
202 | - return &add2; | ||
203 | + return C_O2_I4(r, r, rZ, rZ, rN, rN); | ||
204 | case INDEX_op_setcond2_i32: | ||
205 | - return &setc2; | ||
206 | + return C_O1_I4(r, rZ, rZ, rZ, rZ); | ||
207 | case INDEX_op_brcond2_i32: | ||
208 | - return &br2; | ||
209 | + return C_O0_I4(rZ, rZ, rZ, rZ); | ||
210 | |||
211 | case INDEX_op_qemu_ld_i32: | ||
212 | return (TCG_TARGET_REG_BITS == 64 || TARGET_LONG_BITS == 32 | ||
213 | - ? &r_L : &r_L_L); | ||
214 | + ? C_O1_I1(r, L) : C_O1_I2(r, L, L)); | ||
215 | case INDEX_op_qemu_st_i32: | ||
216 | return (TCG_TARGET_REG_BITS == 64 || TARGET_LONG_BITS == 32 | ||
217 | - ? &SZ_S : &SZ_S_S); | ||
218 | + ? C_O0_I2(SZ, S) : C_O0_I3(SZ, S, S)); | ||
219 | case INDEX_op_qemu_ld_i64: | ||
220 | - return (TCG_TARGET_REG_BITS == 64 ? &r_L | ||
221 | - : TARGET_LONG_BITS == 32 ? &r_r_L : &r_r_L_L); | ||
222 | + return (TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, L) | ||
223 | + : TARGET_LONG_BITS == 32 ? C_O2_I1(r, r, L) | ||
224 | + : C_O2_I2(r, r, L, L)); | ||
225 | case INDEX_op_qemu_st_i64: | ||
226 | - return (TCG_TARGET_REG_BITS == 64 ? &SZ_S | ||
227 | - : TARGET_LONG_BITS == 32 ? &SZ_SZ_S : &SZ_SZ_S_S); | ||
228 | + return (TCG_TARGET_REG_BITS == 64 ? C_O0_I2(SZ, S) | ||
229 | + : TARGET_LONG_BITS == 32 ? C_O0_I3(SZ, SZ, S) | ||
230 | + : C_O0_I4(SZ, SZ, S, S)); | ||
231 | |||
232 | default: | ||
233 | - return NULL; | ||
234 | + g_assert_not_reached(); | ||
235 | } | 32 | } |
236 | } | 33 | } |
237 | 34 | ||
238 | -- | 35 | -- |
239 | 2.25.1 | 36 | 2.34.1 |
240 | 37 | ||
241 | 38 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | This eliminates an ifdef for TCI, and will be required for |
---|---|---|---|
2 | expanding the call for TCGv_i128. | ||
3 | |||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 6 | --- |
4 | tcg/arm/tcg-target-con-set.h | 35 ++++++++++++++ | 7 | tcg/tcg.c | 12 ++---------- |
5 | tcg/arm/tcg-target.h | 1 + | 8 | tcg/aarch64/tcg-target.c.inc | 12 +++++++++--- |
6 | tcg/arm/tcg-target.c.inc | 94 ++++++++++++------------------------ | 9 | tcg/arm/tcg-target.c.inc | 10 ++++++++-- |
7 | 3 files changed, 68 insertions(+), 62 deletions(-) | 10 | tcg/i386/tcg-target.c.inc | 5 +++-- |
8 | create mode 100644 tcg/arm/tcg-target-con-set.h | 11 | tcg/loongarch64/tcg-target.c.inc | 7 ++++--- |
12 | tcg/mips/tcg-target.c.inc | 3 ++- | ||
13 | tcg/ppc/tcg-target.c.inc | 7 ++++--- | ||
14 | tcg/riscv/tcg-target.c.inc | 7 ++++--- | ||
15 | tcg/s390x/tcg-target.c.inc | 12 +++++++++--- | ||
16 | tcg/sparc64/tcg-target.c.inc | 3 ++- | ||
17 | tcg/tci/tcg-target.c.inc | 3 ++- | ||
18 | 11 files changed, 49 insertions(+), 32 deletions(-) | ||
9 | 19 | ||
10 | diff --git a/tcg/arm/tcg-target-con-set.h b/tcg/arm/tcg-target-con-set.h | 20 | diff --git a/tcg/tcg.c b/tcg/tcg.c |
11 | new file mode 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
12 | index XXXXXXX..XXXXXXX | 22 | --- a/tcg/tcg.c |
13 | --- /dev/null | 23 | +++ b/tcg/tcg.c |
14 | +++ b/tcg/arm/tcg-target-con-set.h | 24 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, |
15 | @@ -XXX,XX +XXX,XX @@ | 25 | intptr_t arg2); |
16 | +/* SPDX-License-Identifier: MIT */ | 26 | static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, |
17 | +/* | 27 | TCGReg base, intptr_t ofs); |
18 | + * Define Arm target-specific constraint sets. | 28 | -#ifdef CONFIG_TCG_INTERPRETER |
19 | + * Copyright (c) 2021 Linaro | 29 | static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, |
20 | + */ | 30 | - ffi_cif *cif); |
31 | -#else | ||
32 | -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target); | ||
33 | -#endif | ||
34 | + const TCGHelperInfo *info); | ||
35 | static bool tcg_target_const_match(int64_t val, TCGType type, int ct); | ||
36 | #ifdef TCG_TARGET_NEED_LDST_LABELS | ||
37 | static int tcg_out_ldst_finalize(TCGContext *s); | ||
38 | @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) | ||
39 | save_globals(s, allocated_regs); | ||
40 | } | ||
41 | |||
42 | -#ifdef CONFIG_TCG_INTERPRETER | ||
43 | - tcg_out_call(s, tcg_call_func(op), info->cif); | ||
44 | -#else | ||
45 | - tcg_out_call(s, tcg_call_func(op)); | ||
46 | -#endif | ||
47 | + tcg_out_call(s, tcg_call_func(op), info); | ||
48 | |||
49 | /* Assign output registers and emit moves if needed. */ | ||
50 | switch (info->out_kind) { | ||
51 | diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/tcg/aarch64/tcg-target.c.inc | ||
54 | +++ b/tcg/aarch64/tcg-target.c.inc | ||
55 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target) | ||
56 | } | ||
57 | } | ||
58 | |||
59 | -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) | ||
60 | +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *target) | ||
61 | { | ||
62 | ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; | ||
63 | if (offset == sextract64(offset, 0, 26)) { | ||
64 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) | ||
65 | } | ||
66 | } | ||
67 | |||
68 | +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, | ||
69 | + const TCGHelperInfo *info) | ||
70 | +{ | ||
71 | + tcg_out_call_int(s, target); | ||
72 | +} | ||
21 | + | 73 | + |
22 | +/* | 74 | void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, |
23 | + * C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs. | 75 | uintptr_t jmp_rw, uintptr_t addr) |
24 | + * Each operand should be a sequence of constraint letters as defined by | 76 | { |
25 | + * tcg-target-con-str.h; the constraint combination is inclusive or. | 77 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) |
26 | + */ | 78 | tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X1, lb->addrlo_reg); |
27 | +C_O0_I1(r) | 79 | tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X2, oi); |
28 | +C_O0_I2(r, r) | 80 | tcg_out_adr(s, TCG_REG_X3, lb->raddr); |
29 | +C_O0_I2(r, rIN) | 81 | - tcg_out_call(s, qemu_ld_helpers[opc & MO_SIZE]); |
30 | +C_O0_I2(s, s) | 82 | + tcg_out_call_int(s, qemu_ld_helpers[opc & MO_SIZE]); |
31 | +C_O0_I3(s, s, s) | 83 | if (opc & MO_SIGN) { |
32 | +C_O0_I4(r, r, rI, rI) | 84 | tcg_out_sxt(s, lb->type, size, lb->datalo_reg, TCG_REG_X0); |
33 | +C_O0_I4(s, s, s, s) | 85 | } else { |
34 | +C_O1_I1(r, l) | 86 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) |
35 | +C_O1_I1(r, r) | 87 | tcg_out_mov(s, size == MO_64, TCG_REG_X2, lb->datalo_reg); |
36 | +C_O1_I2(r, 0, rZ) | 88 | tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X3, oi); |
37 | +C_O1_I2(r, l, l) | 89 | tcg_out_adr(s, TCG_REG_X4, lb->raddr); |
38 | +C_O1_I2(r, r, r) | 90 | - tcg_out_call(s, qemu_st_helpers[opc & MO_SIZE]); |
39 | +C_O1_I2(r, r, rI) | 91 | + tcg_out_call_int(s, qemu_st_helpers[opc & MO_SIZE]); |
40 | +C_O1_I2(r, r, rIK) | 92 | tcg_out_goto(s, lb->raddr); |
41 | +C_O1_I2(r, r, rIN) | 93 | return true; |
42 | +C_O1_I2(r, r, ri) | 94 | } |
43 | +C_O1_I2(r, rZ, rZ) | ||
44 | +C_O1_I4(r, r, r, rI, rI) | ||
45 | +C_O1_I4(r, r, rIN, rIK, 0) | ||
46 | +C_O2_I1(r, r, l) | ||
47 | +C_O2_I2(r, r, l, l) | ||
48 | +C_O2_I2(r, r, r, r) | ||
49 | +C_O2_I4(r, r, r, r, rIN, rIK) | ||
50 | +C_O2_I4(r, r, rI, rI, rIN, rIK) | ||
51 | diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/tcg/arm/tcg-target.h | ||
54 | +++ b/tcg/arm/tcg-target.h | ||
55 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | ||
56 | #define TCG_TARGET_NEED_LDST_LABELS | ||
57 | #endif | ||
58 | #define TCG_TARGET_NEED_POOL_LABELS | ||
59 | +#define TCG_TARGET_CON_SET_H | ||
60 | |||
61 | #endif | ||
62 | diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc | 95 | diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc |
63 | index XXXXXXX..XXXXXXX 100644 | 96 | index XXXXXXX..XXXXXXX 100644 |
64 | --- a/tcg/arm/tcg-target.c.inc | 97 | --- a/tcg/arm/tcg-target.c.inc |
65 | +++ b/tcg/arm/tcg-target.c.inc | 98 | +++ b/tcg/arm/tcg-target.c.inc |
66 | @@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, | 99 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_goto(TCGContext *s, ARMCond cond, const tcg_insn_unit *addr) |
67 | } | 100 | * The call case is mostly used for helpers - so it's not unreasonable |
68 | } | 101 | * for them to be beyond branch range. |
69 | 102 | */ | |
70 | -static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | 103 | -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr) |
71 | +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) | 104 | +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *addr) |
72 | { | 105 | { |
73 | - static const TCGTargetOpDef r = { .args_ct_str = { "r" } }; | 106 | intptr_t addri = (intptr_t)addr; |
74 | - static const TCGTargetOpDef r_r = { .args_ct_str = { "r", "r" } }; | 107 | ptrdiff_t disp = tcg_pcrel_diff(s, addr); |
75 | - static const TCGTargetOpDef s_s = { .args_ct_str = { "s", "s" } }; | 108 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr) |
76 | - static const TCGTargetOpDef r_l = { .args_ct_str = { "r", "l" } }; | 109 | tcg_out_blx_reg(s, COND_AL, TCG_REG_TMP); |
77 | - static const TCGTargetOpDef r_r_r = { .args_ct_str = { "r", "r", "r" } }; | 110 | } |
78 | - static const TCGTargetOpDef r_r_l = { .args_ct_str = { "r", "r", "l" } }; | 111 | |
79 | - static const TCGTargetOpDef r_l_l = { .args_ct_str = { "r", "l", "l" } }; | 112 | +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr, |
80 | - static const TCGTargetOpDef s_s_s = { .args_ct_str = { "s", "s", "s" } }; | 113 | + const TCGHelperInfo *info) |
81 | - static const TCGTargetOpDef r_r_ri = { .args_ct_str = { "r", "r", "ri" } }; | 114 | +{ |
82 | - static const TCGTargetOpDef r_r_rI = { .args_ct_str = { "r", "r", "rI" } }; | 115 | + tcg_out_call_int(s, addr); |
83 | - static const TCGTargetOpDef r_r_rIN | 116 | +} |
84 | - = { .args_ct_str = { "r", "r", "rIN" } }; | ||
85 | - static const TCGTargetOpDef r_r_rIK | ||
86 | - = { .args_ct_str = { "r", "r", "rIK" } }; | ||
87 | - static const TCGTargetOpDef r_r_r_r | ||
88 | - = { .args_ct_str = { "r", "r", "r", "r" } }; | ||
89 | - static const TCGTargetOpDef r_r_l_l | ||
90 | - = { .args_ct_str = { "r", "r", "l", "l" } }; | ||
91 | - static const TCGTargetOpDef s_s_s_s | ||
92 | - = { .args_ct_str = { "s", "s", "s", "s" } }; | ||
93 | - static const TCGTargetOpDef br | ||
94 | - = { .args_ct_str = { "r", "rIN" } }; | ||
95 | - static const TCGTargetOpDef ext2 | ||
96 | - = { .args_ct_str = { "r", "rZ", "rZ" } }; | ||
97 | - static const TCGTargetOpDef dep | ||
98 | - = { .args_ct_str = { "r", "0", "rZ" } }; | ||
99 | - static const TCGTargetOpDef movc | ||
100 | - = { .args_ct_str = { "r", "r", "rIN", "rIK", "0" } }; | ||
101 | - static const TCGTargetOpDef add2 | ||
102 | - = { .args_ct_str = { "r", "r", "r", "r", "rIN", "rIK" } }; | ||
103 | - static const TCGTargetOpDef sub2 | ||
104 | - = { .args_ct_str = { "r", "r", "rI", "rI", "rIN", "rIK" } }; | ||
105 | - static const TCGTargetOpDef br2 | ||
106 | - = { .args_ct_str = { "r", "r", "rI", "rI" } }; | ||
107 | - static const TCGTargetOpDef setc2 | ||
108 | - = { .args_ct_str = { "r", "r", "r", "rI", "rI" } }; | ||
109 | - | ||
110 | switch (op) { | ||
111 | case INDEX_op_goto_ptr: | ||
112 | - return &r; | ||
113 | + return C_O0_I1(r); | ||
114 | |||
115 | case INDEX_op_ld8u_i32: | ||
116 | case INDEX_op_ld8s_i32: | ||
117 | case INDEX_op_ld16u_i32: | ||
118 | case INDEX_op_ld16s_i32: | ||
119 | case INDEX_op_ld_i32: | ||
120 | - case INDEX_op_st8_i32: | ||
121 | - case INDEX_op_st16_i32: | ||
122 | - case INDEX_op_st_i32: | ||
123 | case INDEX_op_neg_i32: | ||
124 | case INDEX_op_not_i32: | ||
125 | case INDEX_op_bswap16_i32: | ||
126 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
127 | case INDEX_op_ext16u_i32: | ||
128 | case INDEX_op_extract_i32: | ||
129 | case INDEX_op_sextract_i32: | ||
130 | - return &r_r; | ||
131 | + return C_O1_I1(r, r); | ||
132 | + | 117 | + |
133 | + case INDEX_op_st8_i32: | 118 | static void tcg_out_goto_label(TCGContext *s, ARMCond cond, TCGLabel *l) |
134 | + case INDEX_op_st16_i32: | 119 | { |
135 | + case INDEX_op_st_i32: | 120 | if (l->has_value) { |
136 | + return C_O0_I2(r, r); | 121 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) |
137 | 122 | argreg = tcg_out_arg_reg32(s, argreg, TCG_REG_R14); | |
138 | case INDEX_op_add_i32: | 123 | |
139 | case INDEX_op_sub_i32: | 124 | /* Use the canonical unsigned helpers and minimize icache usage. */ |
140 | case INDEX_op_setcond_i32: | 125 | - tcg_out_call(s, qemu_ld_helpers[opc & MO_SIZE]); |
141 | - return &r_r_rIN; | 126 | + tcg_out_call_int(s, qemu_ld_helpers[opc & MO_SIZE]); |
142 | + return C_O1_I2(r, r, rIN); | 127 | |
128 | datalo = lb->datalo_reg; | ||
129 | datahi = lb->datahi_reg; | ||
130 | diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc | ||
131 | index XXXXXXX..XXXXXXX 100644 | ||
132 | --- a/tcg/i386/tcg-target.c.inc | ||
133 | +++ b/tcg/i386/tcg-target.c.inc | ||
134 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest) | ||
135 | } | ||
136 | } | ||
137 | |||
138 | -static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest) | ||
139 | +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest, | ||
140 | + const TCGHelperInfo *info) | ||
141 | { | ||
142 | tcg_out_branch(s, 1, dest); | ||
143 | } | ||
144 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) | ||
145 | (uintptr_t)l->raddr); | ||
146 | } | ||
147 | |||
148 | - tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]); | ||
149 | + tcg_out_branch(s, 1, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]); | ||
150 | |||
151 | data_reg = l->datalo_reg; | ||
152 | switch (opc & MO_SSIZE) { | ||
153 | diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc | ||
154 | index XXXXXXX..XXXXXXX 100644 | ||
155 | --- a/tcg/loongarch64/tcg-target.c.inc | ||
156 | +++ b/tcg/loongarch64/tcg-target.c.inc | ||
157 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail) | ||
158 | } | ||
159 | } | ||
160 | |||
161 | -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg) | ||
162 | +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg, | ||
163 | + const TCGHelperInfo *info) | ||
164 | { | ||
165 | tcg_out_call_int(s, arg, false); | ||
166 | } | ||
167 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) | ||
168 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A2, oi); | ||
169 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A3, (tcg_target_long)l->raddr); | ||
170 | |||
171 | - tcg_out_call(s, qemu_ld_helpers[size]); | ||
172 | + tcg_out_call_int(s, qemu_ld_helpers[size], false); | ||
173 | |||
174 | switch (opc & MO_SSIZE) { | ||
175 | case MO_SB: | ||
176 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) | ||
177 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A3, oi); | ||
178 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A4, (tcg_target_long)l->raddr); | ||
179 | |||
180 | - tcg_out_call(s, qemu_st_helpers[size]); | ||
181 | + tcg_out_call_int(s, qemu_st_helpers[size], false); | ||
182 | |||
183 | return tcg_out_goto(s, l->raddr); | ||
184 | } | ||
185 | diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc | ||
186 | index XXXXXXX..XXXXXXX 100644 | ||
187 | --- a/tcg/mips/tcg-target.c.inc | ||
188 | +++ b/tcg/mips/tcg-target.c.inc | ||
189 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail) | ||
190 | } | ||
191 | } | ||
192 | |||
193 | -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg) | ||
194 | +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg, | ||
195 | + const TCGHelperInfo *info) | ||
196 | { | ||
197 | tcg_out_call_int(s, arg, false); | ||
198 | tcg_out_nop(s); | ||
199 | diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc | ||
200 | index XXXXXXX..XXXXXXX 100644 | ||
201 | --- a/tcg/ppc/tcg-target.c.inc | ||
202 | +++ b/tcg/ppc/tcg-target.c.inc | ||
203 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_call_int(TCGContext *s, int lk, | ||
204 | #endif | ||
205 | } | ||
206 | |||
207 | -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) | ||
208 | +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, | ||
209 | + const TCGHelperInfo *info) | ||
210 | { | ||
211 | tcg_out_call_int(s, LK, target); | ||
212 | } | ||
213 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) | ||
214 | tcg_out_movi(s, TCG_TYPE_I32, arg++, oi); | ||
215 | tcg_out32(s, MFSPR | RT(arg) | LR); | ||
216 | |||
217 | - tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]); | ||
218 | + tcg_out_call_int(s, LK, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]); | ||
219 | |||
220 | lo = lb->datalo_reg; | ||
221 | hi = lb->datahi_reg; | ||
222 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) | ||
223 | tcg_out_movi(s, TCG_TYPE_I32, arg++, oi); | ||
224 | tcg_out32(s, MFSPR | RT(arg) | LR); | ||
225 | |||
226 | - tcg_out_call(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]); | ||
227 | + tcg_out_call_int(s, LK, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]); | ||
228 | |||
229 | tcg_out_b(s, 0, lb->raddr); | ||
230 | return true; | ||
231 | diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc | ||
232 | index XXXXXXX..XXXXXXX 100644 | ||
233 | --- a/tcg/riscv/tcg-target.c.inc | ||
234 | +++ b/tcg/riscv/tcg-target.c.inc | ||
235 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail) | ||
236 | } | ||
237 | } | ||
238 | |||
239 | -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg) | ||
240 | +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg, | ||
241 | + const TCGHelperInfo *info) | ||
242 | { | ||
243 | tcg_out_call_int(s, arg, false); | ||
244 | } | ||
245 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) | ||
246 | tcg_out_movi(s, TCG_TYPE_PTR, a2, oi); | ||
247 | tcg_out_movi(s, TCG_TYPE_PTR, a3, (tcg_target_long)l->raddr); | ||
248 | |||
249 | - tcg_out_call(s, qemu_ld_helpers[opc & MO_SSIZE]); | ||
250 | + tcg_out_call_int(s, qemu_ld_helpers[opc & MO_SSIZE], false); | ||
251 | tcg_out_mov(s, (opc & MO_SIZE) == MO_64, l->datalo_reg, a0); | ||
252 | |||
253 | tcg_out_goto(s, l->raddr); | ||
254 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) | ||
255 | tcg_out_movi(s, TCG_TYPE_PTR, a3, oi); | ||
256 | tcg_out_movi(s, TCG_TYPE_PTR, a4, (tcg_target_long)l->raddr); | ||
257 | |||
258 | - tcg_out_call(s, qemu_st_helpers[opc & MO_SIZE]); | ||
259 | + tcg_out_call_int(s, qemu_st_helpers[opc & MO_SIZE], false); | ||
260 | |||
261 | tcg_out_goto(s, l->raddr); | ||
262 | return true; | ||
263 | diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc | ||
264 | index XXXXXXX..XXXXXXX 100644 | ||
265 | --- a/tcg/s390x/tcg-target.c.inc | ||
266 | +++ b/tcg/s390x/tcg-target.c.inc | ||
267 | @@ -XXX,XX +XXX,XX @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c, | ||
268 | tgen_branch(s, cc, l); | ||
269 | } | ||
270 | |||
271 | -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest) | ||
272 | +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *dest) | ||
273 | { | ||
274 | ptrdiff_t off = tcg_pcrel_diff(s, dest) >> 1; | ||
275 | if (off == (int32_t)off) { | ||
276 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest) | ||
277 | } | ||
278 | } | ||
279 | |||
280 | +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest, | ||
281 | + const TCGHelperInfo *info) | ||
282 | +{ | ||
283 | + tcg_out_call_int(s, dest); | ||
284 | +} | ||
143 | + | 285 | + |
144 | case INDEX_op_and_i32: | 286 | static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg data, |
145 | case INDEX_op_andc_i32: | 287 | TCGReg base, TCGReg index, int disp) |
146 | case INDEX_op_clz_i32: | 288 | { |
147 | case INDEX_op_ctz_i32: | 289 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) |
148 | - return &r_r_rIK; | 290 | } |
149 | + return C_O1_I2(r, r, rIK); | 291 | tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, oi); |
150 | + | 292 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R5, (uintptr_t)lb->raddr); |
151 | case INDEX_op_mul_i32: | 293 | - tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SSIZE)]); |
152 | case INDEX_op_div_i32: | 294 | + tcg_out_call_int(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SSIZE)]); |
153 | case INDEX_op_divu_i32: | 295 | tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_R2); |
154 | - return &r_r_r; | 296 | |
155 | + return C_O1_I2(r, r, r); | 297 | tgen_gotoi(s, S390_CC_ALWAYS, lb->raddr); |
156 | + | 298 | @@ -XXX,XX +XXX,XX @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) |
157 | case INDEX_op_mulu2_i32: | 299 | } |
158 | case INDEX_op_muls2_i32: | 300 | tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R5, oi); |
159 | - return &r_r_r_r; | 301 | tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R6, (uintptr_t)lb->raddr); |
160 | + return C_O2_I2(r, r, r, r); | 302 | - tcg_out_call(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]); |
161 | + | 303 | + tcg_out_call_int(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]); |
162 | case INDEX_op_or_i32: | 304 | |
163 | case INDEX_op_xor_i32: | 305 | tgen_gotoi(s, S390_CC_ALWAYS, lb->raddr); |
164 | - return &r_r_rI; | 306 | return true; |
165 | + return C_O1_I2(r, r, rI); | 307 | diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc |
166 | + | 308 | index XXXXXXX..XXXXXXX 100644 |
167 | case INDEX_op_shl_i32: | 309 | --- a/tcg/sparc64/tcg-target.c.inc |
168 | case INDEX_op_shr_i32: | 310 | +++ b/tcg/sparc64/tcg-target.c.inc |
169 | case INDEX_op_sar_i32: | 311 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_call_nodelay(TCGContext *s, const tcg_insn_unit *dest, |
170 | case INDEX_op_rotl_i32: | 312 | } |
171 | case INDEX_op_rotr_i32: | 313 | } |
172 | - return &r_r_ri; | 314 | |
173 | + return C_O1_I2(r, r, ri); | 315 | -static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest) |
174 | 316 | +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest, | |
175 | case INDEX_op_brcond_i32: | 317 | + const TCGHelperInfo *info) |
176 | - return &br; | 318 | { |
177 | + return C_O0_I2(r, rIN); | 319 | tcg_out_call_nodelay(s, dest, false); |
178 | case INDEX_op_deposit_i32: | 320 | tcg_out_nop(s); |
179 | - return &dep; | 321 | diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc |
180 | + return C_O1_I2(r, 0, rZ); | 322 | index XXXXXXX..XXXXXXX 100644 |
181 | case INDEX_op_extract2_i32: | 323 | --- a/tcg/tci/tcg-target.c.inc |
182 | - return &ext2; | 324 | +++ b/tcg/tci/tcg-target.c.inc |
183 | + return C_O1_I2(r, rZ, rZ); | 325 | @@ -XXX,XX +XXX,XX @@ static void tcg_out_movi(TCGContext *s, TCGType type, |
184 | case INDEX_op_movcond_i32: | 326 | } |
185 | - return &movc; | 327 | |
186 | + return C_O1_I4(r, r, rIN, rIK, 0); | 328 | static void tcg_out_call(TCGContext *s, const tcg_insn_unit *func, |
187 | case INDEX_op_add2_i32: | 329 | - ffi_cif *cif) |
188 | - return &add2; | 330 | + const TCGHelperInfo *info) |
189 | + return C_O2_I4(r, r, r, r, rIN, rIK); | 331 | { |
190 | case INDEX_op_sub2_i32: | 332 | + ffi_cif *cif = info->cif; |
191 | - return &sub2; | 333 | tcg_insn_unit insn = 0; |
192 | + return C_O2_I4(r, r, rI, rI, rIN, rIK); | 334 | uint8_t which; |
193 | case INDEX_op_brcond2_i32: | ||
194 | - return &br2; | ||
195 | + return C_O0_I4(r, r, rI, rI); | ||
196 | case INDEX_op_setcond2_i32: | ||
197 | - return &setc2; | ||
198 | + return C_O1_I4(r, r, r, rI, rI); | ||
199 | |||
200 | case INDEX_op_qemu_ld_i32: | ||
201 | - return TARGET_LONG_BITS == 32 ? &r_l : &r_l_l; | ||
202 | + return TARGET_LONG_BITS == 32 ? C_O1_I1(r, l) : C_O1_I2(r, l, l); | ||
203 | case INDEX_op_qemu_ld_i64: | ||
204 | - return TARGET_LONG_BITS == 32 ? &r_r_l : &r_r_l_l; | ||
205 | + return TARGET_LONG_BITS == 32 ? C_O2_I1(r, r, l) : C_O2_I2(r, r, l, l); | ||
206 | case INDEX_op_qemu_st_i32: | ||
207 | - return TARGET_LONG_BITS == 32 ? &s_s : &s_s_s; | ||
208 | + return TARGET_LONG_BITS == 32 ? C_O0_I2(s, s) : C_O0_I3(s, s, s); | ||
209 | case INDEX_op_qemu_st_i64: | ||
210 | - return TARGET_LONG_BITS == 32 ? &s_s_s : &s_s_s_s; | ||
211 | + return TARGET_LONG_BITS == 32 ? C_O0_I3(s, s, s) : C_O0_I4(s, s, s, s); | ||
212 | |||
213 | default: | ||
214 | - return NULL; | ||
215 | + g_assert_not_reached(); | ||
216 | } | ||
217 | } | ||
218 | 335 | ||
219 | -- | 336 | -- |
220 | 2.25.1 | 337 | 2.34.1 |
221 | 338 | ||
222 | 339 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | When called from syscall(), we are not within a TB and pc == 0. |
---|---|---|---|
2 | We can skip the check for invalidating the current TB. | ||
3 | |||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 6 | --- |
4 | tcg/s390/tcg-target-con-str.h | 28 ++++++++++++++++++ | 7 | accel/tcg/tb-maint.c | 78 ++++++++++++++++++++++++-------------------- |
5 | tcg/s390/tcg-target.h | 1 + | 8 | 1 file changed, 43 insertions(+), 35 deletions(-) |
6 | tcg/s390/tcg-target.c.inc | 53 +++++++++-------------------------- | ||
7 | 3 files changed, 42 insertions(+), 40 deletions(-) | ||
8 | create mode 100644 tcg/s390/tcg-target-con-str.h | ||
9 | 9 | ||
10 | diff --git a/tcg/s390/tcg-target-con-str.h b/tcg/s390/tcg-target-con-str.h | 10 | diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c |
11 | new file mode 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
12 | index XXXXXXX..XXXXXXX | 12 | --- a/accel/tcg/tb-maint.c |
13 | --- /dev/null | 13 | +++ b/accel/tcg/tb-maint.c |
14 | +++ b/tcg/s390/tcg-target-con-str.h | 14 | @@ -XXX,XX +XXX,XX @@ void tb_invalidate_phys_page(tb_page_addr_t addr) |
15 | @@ -XXX,XX +XXX,XX @@ | 15 | */ |
16 | +/* SPDX-License-Identifier: MIT */ | 16 | bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc) |
17 | +/* | 17 | { |
18 | + * Define S390 target-specific operand constraints. | 18 | - assert(pc != 0); |
19 | + * Copyright (c) 2021 Linaro | 19 | -#ifdef TARGET_HAS_PRECISE_SMC |
20 | + */ | 20 | - assert_memory_lock(); |
21 | - { | ||
22 | - TranslationBlock *current_tb = tcg_tb_lookup(pc); | ||
23 | - bool current_tb_modified = false; | ||
24 | - TranslationBlock *tb; | ||
25 | - PageForEachNext n; | ||
26 | + TranslationBlock *current_tb; | ||
27 | + bool current_tb_modified; | ||
28 | + TranslationBlock *tb; | ||
29 | + PageForEachNext n; | ||
30 | |||
31 | - addr &= TARGET_PAGE_MASK; | ||
32 | - | ||
33 | - PAGE_FOR_EACH_TB(addr, addr + TARGET_PAGE_SIZE, unused, tb, n) { | ||
34 | - if (current_tb == tb && | ||
35 | - (tb_cflags(current_tb) & CF_COUNT_MASK) != 1) { | ||
36 | - /* | ||
37 | - * If we are modifying the current TB, we must stop its | ||
38 | - * execution. We could be more precise by checking that | ||
39 | - * the modification is after the current PC, but it would | ||
40 | - * require a specialized function to partially restore | ||
41 | - * the CPU state. | ||
42 | - */ | ||
43 | - current_tb_modified = true; | ||
44 | - cpu_restore_state_from_tb(current_cpu, current_tb, pc); | ||
45 | - } | ||
46 | - tb_phys_invalidate__locked(tb); | ||
47 | - } | ||
48 | - | ||
49 | - if (current_tb_modified) { | ||
50 | - /* Force execution of one insn next time. */ | ||
51 | - CPUState *cpu = current_cpu; | ||
52 | - cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu); | ||
53 | - return true; | ||
54 | - } | ||
55 | + /* | ||
56 | + * Without precise smc semantics, or when outside of a TB, | ||
57 | + * we can skip to invalidate. | ||
58 | + */ | ||
59 | +#ifndef TARGET_HAS_PRECISE_SMC | ||
60 | + pc = 0; | ||
61 | +#endif | ||
62 | + if (!pc) { | ||
63 | + tb_invalidate_phys_page(addr); | ||
64 | + return false; | ||
65 | + } | ||
21 | + | 66 | + |
22 | +/* | 67 | + assert_memory_lock(); |
23 | + * Define constraint letters for register sets: | 68 | + current_tb = tcg_tb_lookup(pc); |
24 | + * REGS(letter, register_mask) | ||
25 | + */ | ||
26 | +REGS('r', ALL_GENERAL_REGS) | ||
27 | +REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) | ||
28 | +/* | ||
29 | + * A (single) even/odd pair for division. | ||
30 | + * TODO: Add something to the register allocator to allow | ||
31 | + * this kind of regno+1 pairing to be done more generally. | ||
32 | + */ | ||
33 | +REGS('a', 1u << TCG_REG_R2) | ||
34 | +REGS('b', 1u << TCG_REG_R3) | ||
35 | + | 69 | + |
36 | +/* | 70 | + addr &= TARGET_PAGE_MASK; |
37 | + * Define constraint letters for constants: | 71 | + current_tb_modified = false; |
38 | + * CONST(letter, TCG_CT_CONST_* bit set) | ||
39 | + */ | ||
40 | +CONST('A', TCG_CT_CONST_S33) | ||
41 | +CONST('I', TCG_CT_CONST_S16) | ||
42 | +CONST('J', TCG_CT_CONST_S32) | ||
43 | +CONST('Z', TCG_CT_CONST_ZERO) | ||
44 | diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/tcg/s390/tcg-target.h | ||
47 | +++ b/tcg/s390/tcg-target.h | ||
48 | @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, | ||
49 | #define TCG_TARGET_NEED_LDST_LABELS | ||
50 | #endif | ||
51 | #define TCG_TARGET_NEED_POOL_LABELS | ||
52 | +#define TCG_TARGET_CON_STR_H | ||
53 | |||
54 | #endif | ||
55 | diff --git a/tcg/s390/tcg-target.c.inc b/tcg/s390/tcg-target.c.inc | ||
56 | index XXXXXXX..XXXXXXX 100644 | ||
57 | --- a/tcg/s390/tcg-target.c.inc | ||
58 | +++ b/tcg/s390/tcg-target.c.inc | ||
59 | @@ -XXX,XX +XXX,XX @@ | ||
60 | #define TCG_CT_CONST_S33 0x400 | ||
61 | #define TCG_CT_CONST_ZERO 0x800 | ||
62 | |||
63 | +#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 16) | ||
64 | +/* | ||
65 | + * For softmmu, we need to avoid conflicts with the first 3 | ||
66 | + * argument registers to perform the tlb lookup, and to call | ||
67 | + * the helper function. | ||
68 | + */ | ||
69 | +#ifdef CONFIG_SOFTMMU | ||
70 | +#define SOFTMMU_RESERVE_REGS MAKE_64BIT_MASK(TCG_REG_R2, 3) | ||
71 | +#else | ||
72 | +#define SOFTMMU_RESERVE_REGS 0 | ||
73 | +#endif | ||
74 | + | 72 | + |
73 | + PAGE_FOR_EACH_TB(addr, addr + TARGET_PAGE_SIZE, unused, tb, n) { | ||
74 | + if (current_tb == tb && | ||
75 | + (tb_cflags(current_tb) & CF_COUNT_MASK) != 1) { | ||
76 | + /* | ||
77 | + * If we are modifying the current TB, we must stop its | ||
78 | + * execution. We could be more precise by checking that | ||
79 | + * the modification is after the current PC, but it would | ||
80 | + * require a specialized function to partially restore | ||
81 | + * the CPU state. | ||
82 | + */ | ||
83 | + current_tb_modified = true; | ||
84 | + cpu_restore_state_from_tb(current_cpu, current_tb, pc); | ||
85 | + } | ||
86 | + tb_phys_invalidate__locked(tb); | ||
87 | + } | ||
75 | + | 88 | + |
76 | /* Several places within the instruction set 0 means "no register" | 89 | + if (current_tb_modified) { |
77 | rather than TCG_REG_R0. */ | 90 | + /* Force execution of one insn next time. */ |
78 | #define TCG_REG_NONE 0 | 91 | + CPUState *cpu = current_cpu; |
79 | @@ -XXX,XX +XXX,XX @@ static bool patch_reloc(tcg_insn_unit *src_rw, int type, | 92 | + cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu); |
93 | + return true; | ||
94 | } | ||
95 | -#else | ||
96 | - tb_invalidate_phys_page(addr); | ||
97 | -#endif /* TARGET_HAS_PRECISE_SMC */ | ||
80 | return false; | 98 | return false; |
81 | } | 99 | } |
82 | 100 | #else | |
83 | -/* parse target specific constraints */ | ||
84 | -static const char *target_parse_constraint(TCGArgConstraint *ct, | ||
85 | - const char *ct_str, TCGType type) | ||
86 | -{ | ||
87 | - switch (*ct_str++) { | ||
88 | - case 'r': /* all registers */ | ||
89 | - ct->regs = 0xffff; | ||
90 | - break; | ||
91 | - case 'L': /* qemu_ld/st constraint */ | ||
92 | - ct->regs = 0xffff; | ||
93 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R2); | ||
94 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R3); | ||
95 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R4); | ||
96 | - break; | ||
97 | - case 'a': /* force R2 for division */ | ||
98 | - ct->regs = 0; | ||
99 | - tcg_regset_set_reg(ct->regs, TCG_REG_R2); | ||
100 | - break; | ||
101 | - case 'b': /* force R3 for division */ | ||
102 | - ct->regs = 0; | ||
103 | - tcg_regset_set_reg(ct->regs, TCG_REG_R3); | ||
104 | - break; | ||
105 | - case 'A': | ||
106 | - ct->ct |= TCG_CT_CONST_S33; | ||
107 | - break; | ||
108 | - case 'I': | ||
109 | - ct->ct |= TCG_CT_CONST_S16; | ||
110 | - break; | ||
111 | - case 'J': | ||
112 | - ct->ct |= TCG_CT_CONST_S32; | ||
113 | - break; | ||
114 | - case 'Z': | ||
115 | - ct->ct |= TCG_CT_CONST_ZERO; | ||
116 | - break; | ||
117 | - default: | ||
118 | - return NULL; | ||
119 | - } | ||
120 | - return ct_str; | ||
121 | -} | ||
122 | - | ||
123 | /* Test if a constant matches the constraint. */ | ||
124 | static int tcg_target_const_match(tcg_target_long val, TCGType type, | ||
125 | const TCGArgConstraint *arg_ct) | ||
126 | -- | 101 | -- |
127 | 2.25.1 | 102 | 2.34.1 |
128 | 103 | ||
129 | 104 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | Because we allow lockless lookups, we have to be careful |
---|---|---|---|
2 | when it is freed. Use rcu to delay the free until safe. | ||
3 | |||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 6 | --- |
4 | tcg/ppc/tcg-target-con-set.h | 42 +++++++++++ | 7 | accel/tcg/user-exec.c | 18 ++++++++++-------- |
5 | tcg/ppc/tcg-target.h | 1 + | 8 | 1 file changed, 10 insertions(+), 8 deletions(-) |
6 | tcg/ppc/tcg-target.c.inc | 136 +++++++++++++++-------------------- | ||
7 | 3 files changed, 99 insertions(+), 80 deletions(-) | ||
8 | create mode 100644 tcg/ppc/tcg-target-con-set.h | ||
9 | 9 | ||
10 | diff --git a/tcg/ppc/tcg-target-con-set.h b/tcg/ppc/tcg-target-con-set.h | 10 | diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c |
11 | new file mode 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
12 | index XXXXXXX..XXXXXXX | 12 | --- a/accel/tcg/user-exec.c |
13 | --- /dev/null | 13 | +++ b/accel/tcg/user-exec.c |
14 | +++ b/tcg/ppc/tcg-target-con-set.h | ||
15 | @@ -XXX,XX +XXX,XX @@ | 14 | @@ -XXX,XX +XXX,XX @@ |
16 | +/* SPDX-License-Identifier: MIT */ | 15 | #include "exec/exec-all.h" |
17 | +/* | 16 | #include "tcg/tcg.h" |
18 | + * Define PowerPC target-specific constraint sets. | 17 | #include "qemu/bitops.h" |
19 | + * Copyright (c) 2021 Linaro | 18 | +#include "qemu/rcu.h" |
20 | + */ | 19 | #include "exec/cpu_ldst.h" |
21 | + | 20 | #include "exec/translate-all.h" |
22 | +/* | 21 | #include "exec/helper-proto.h" |
23 | + * C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs. | 22 | @@ -XXX,XX +XXX,XX @@ bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set, |
24 | + * Each operand should be a sequence of constraint letters as defined by | ||
25 | + * tcg-target-con-str.h; the constraint combination is inclusive or. | ||
26 | + */ | ||
27 | +C_O0_I1(r) | ||
28 | +C_O0_I2(r, r) | ||
29 | +C_O0_I2(r, ri) | ||
30 | +C_O0_I2(S, S) | ||
31 | +C_O0_I2(v, r) | ||
32 | +C_O0_I3(S, S, S) | ||
33 | +C_O0_I4(r, r, ri, ri) | ||
34 | +C_O0_I4(S, S, S, S) | ||
35 | +C_O1_I1(r, L) | ||
36 | +C_O1_I1(r, r) | ||
37 | +C_O1_I1(v, r) | ||
38 | +C_O1_I1(v, v) | ||
39 | +C_O1_I1(v, vr) | ||
40 | +C_O1_I2(r, 0, rZ) | ||
41 | +C_O1_I2(r, L, L) | ||
42 | +C_O1_I2(r, rI, ri) | ||
43 | +C_O1_I2(r, rI, rT) | ||
44 | +C_O1_I2(r, r, r) | ||
45 | +C_O1_I2(r, r, ri) | ||
46 | +C_O1_I2(r, r, rI) | ||
47 | +C_O1_I2(r, r, rT) | ||
48 | +C_O1_I2(r, r, rU) | ||
49 | +C_O1_I2(r, r, rZW) | ||
50 | +C_O1_I2(v, v, v) | ||
51 | +C_O1_I3(v, v, v, v) | ||
52 | +C_O1_I4(r, r, ri, rZ, rZ) | ||
53 | +C_O1_I4(r, r, r, ri, ri) | ||
54 | +C_O2_I1(L, L, L) | ||
55 | +C_O2_I2(L, L, L, L) | ||
56 | +C_O2_I4(r, r, rI, rZM, r, r) | ||
57 | +C_O2_I4(r, r, r, r, rI, rZM) | ||
58 | diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h | ||
59 | index XXXXXXX..XXXXXXX 100644 | ||
60 | --- a/tcg/ppc/tcg-target.h | ||
61 | +++ b/tcg/ppc/tcg-target.h | ||
62 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | ||
63 | #define TCG_TARGET_NEED_LDST_LABELS | ||
64 | #endif | ||
65 | #define TCG_TARGET_NEED_POOL_LABELS | ||
66 | +#define TCG_TARGET_CON_SET_H | ||
67 | |||
68 | #endif | ||
69 | diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc | ||
70 | index XXXXXXX..XXXXXXX 100644 | ||
71 | --- a/tcg/ppc/tcg-target.c.inc | ||
72 | +++ b/tcg/ppc/tcg-target.c.inc | ||
73 | @@ -XXX,XX +XXX,XX @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece, | ||
74 | va_end(va); | ||
75 | } | 23 | } |
76 | 24 | ||
77 | -static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | 25 | typedef struct PageFlagsNode { |
78 | +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) | 26 | + struct rcu_head rcu; |
79 | { | 27 | IntervalTreeNode itree; |
80 | - static const TCGTargetOpDef r = { .args_ct_str = { "r" } }; | 28 | int flags; |
81 | - static const TCGTargetOpDef r_r = { .args_ct_str = { "r", "r" } }; | 29 | } PageFlagsNode; |
82 | - static const TCGTargetOpDef r_L = { .args_ct_str = { "r", "L" } }; | 30 | @@ -XXX,XX +XXX,XX @@ static bool pageflags_unset(target_ulong start, target_ulong last) |
83 | - static const TCGTargetOpDef S_S = { .args_ct_str = { "S", "S" } }; | 31 | } |
84 | - static const TCGTargetOpDef r_ri = { .args_ct_str = { "r", "ri" } }; | 32 | } else if (p_last <= last) { |
85 | - static const TCGTargetOpDef r_r_r = { .args_ct_str = { "r", "r", "r" } }; | 33 | /* Range completely covers node -- remove it. */ |
86 | - static const TCGTargetOpDef r_L_L = { .args_ct_str = { "r", "L", "L" } }; | 34 | - g_free(p); |
87 | - static const TCGTargetOpDef L_L_L = { .args_ct_str = { "L", "L", "L" } }; | 35 | + g_free_rcu(p, rcu); |
88 | - static const TCGTargetOpDef S_S_S = { .args_ct_str = { "S", "S", "S" } }; | 36 | } else { |
89 | - static const TCGTargetOpDef r_r_ri = { .args_ct_str = { "r", "r", "ri" } }; | 37 | /* Truncate the node from the start. */ |
90 | - static const TCGTargetOpDef r_r_rI = { .args_ct_str = { "r", "r", "rI" } }; | 38 | p->itree.start = last + 1; |
91 | - static const TCGTargetOpDef r_r_rT = { .args_ct_str = { "r", "r", "rT" } }; | 39 | @@ -XXX,XX +XXX,XX @@ static void pageflags_create_merge(target_ulong start, target_ulong last, |
92 | - static const TCGTargetOpDef r_r_rU = { .args_ct_str = { "r", "r", "rU" } }; | 40 | if (prev) { |
93 | - static const TCGTargetOpDef r_rI_ri | 41 | if (next) { |
94 | - = { .args_ct_str = { "r", "rI", "ri" } }; | 42 | prev->itree.last = next->itree.last; |
95 | - static const TCGTargetOpDef r_rI_rT | 43 | - g_free(next); |
96 | - = { .args_ct_str = { "r", "rI", "rT" } }; | 44 | + g_free_rcu(next, rcu); |
97 | - static const TCGTargetOpDef r_r_rZW | 45 | } else { |
98 | - = { .args_ct_str = { "r", "r", "rZW" } }; | 46 | prev->itree.last = last; |
99 | - static const TCGTargetOpDef L_L_L_L | 47 | } |
100 | - = { .args_ct_str = { "L", "L", "L", "L" } }; | 48 | @@ -XXX,XX +XXX,XX @@ static bool pageflags_set_clear(target_ulong start, target_ulong last, |
101 | - static const TCGTargetOpDef S_S_S_S | 49 | p->flags = merge_flags; |
102 | - = { .args_ct_str = { "S", "S", "S", "S" } }; | 50 | } else { |
103 | - static const TCGTargetOpDef movc | 51 | interval_tree_remove(&p->itree, &pageflags_root); |
104 | - = { .args_ct_str = { "r", "r", "ri", "rZ", "rZ" } }; | 52 | - g_free(p); |
105 | - static const TCGTargetOpDef dep | 53 | + g_free_rcu(p, rcu); |
106 | - = { .args_ct_str = { "r", "0", "rZ" } }; | 54 | } |
107 | - static const TCGTargetOpDef br2 | 55 | goto done; |
108 | - = { .args_ct_str = { "r", "r", "ri", "ri" } }; | 56 | } |
109 | - static const TCGTargetOpDef setc2 | 57 | @@ -XXX,XX +XXX,XX @@ static bool pageflags_set_clear(target_ulong start, target_ulong last, |
110 | - = { .args_ct_str = { "r", "r", "r", "ri", "ri" } }; | 58 | p->flags = merge_flags; |
111 | - static const TCGTargetOpDef add2 | 59 | } else { |
112 | - = { .args_ct_str = { "r", "r", "r", "r", "rI", "rZM" } }; | 60 | interval_tree_remove(&p->itree, &pageflags_root); |
113 | - static const TCGTargetOpDef sub2 | 61 | - g_free(p); |
114 | - = { .args_ct_str = { "r", "r", "rI", "rZM", "r", "r" } }; | 62 | + g_free_rcu(p, rcu); |
115 | - static const TCGTargetOpDef v_r = { .args_ct_str = { "v", "r" } }; | 63 | } |
116 | - static const TCGTargetOpDef v_vr = { .args_ct_str = { "v", "vr" } }; | 64 | if (p_last < last) { |
117 | - static const TCGTargetOpDef v_v = { .args_ct_str = { "v", "v" } }; | 65 | start = p_last + 1; |
118 | - static const TCGTargetOpDef v_v_v = { .args_ct_str = { "v", "v", "v" } }; | 66 | @@ -XXX,XX +XXX,XX @@ static bool pageflags_set_clear(target_ulong start, target_ulong last, |
119 | - static const TCGTargetOpDef v_v_v_v | 67 | p->itree.start = last + 1; |
120 | - = { .args_ct_str = { "v", "v", "v", "v" } }; | 68 | interval_tree_insert(&p->itree, &pageflags_root); |
121 | - | 69 | } else { |
122 | switch (op) { | 70 | - g_free(p); |
123 | case INDEX_op_goto_ptr: | 71 | + g_free_rcu(p, rcu); |
124 | - return &r; | 72 | goto restart; |
125 | + return C_O0_I1(r); | 73 | } |
126 | 74 | if (set_flags) { | |
127 | case INDEX_op_ld8u_i32: | 75 | @@ -XXX,XX +XXX,XX @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, |
128 | case INDEX_op_ld8s_i32: | 76 | #define TBD_MASK (TARGET_PAGE_MASK * TPD_PAGES) |
129 | case INDEX_op_ld16u_i32: | 77 | |
130 | case INDEX_op_ld16s_i32: | 78 | typedef struct TargetPageDataNode { |
131 | case INDEX_op_ld_i32: | 79 | + struct rcu_head rcu; |
132 | - case INDEX_op_st8_i32: | 80 | IntervalTreeNode itree; |
133 | - case INDEX_op_st16_i32: | 81 | char data[TPD_PAGES][TARGET_PAGE_DATA_SIZE] __attribute__((aligned)); |
134 | - case INDEX_op_st_i32: | 82 | } TargetPageDataNode; |
135 | case INDEX_op_ctpop_i32: | 83 | @@ -XXX,XX +XXX,XX @@ void page_reset_target_data(target_ulong start, target_ulong end) |
136 | case INDEX_op_neg_i32: | 84 | n = next, |
137 | case INDEX_op_not_i32: | 85 | next = next ? interval_tree_iter_next(n, start, last) : NULL) { |
138 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | 86 | target_ulong n_start, n_last, p_ofs, p_len; |
139 | case INDEX_op_ld32u_i64: | 87 | - TargetPageDataNode *t; |
140 | case INDEX_op_ld32s_i64: | 88 | + TargetPageDataNode *t = container_of(n, TargetPageDataNode, itree); |
141 | case INDEX_op_ld_i64: | 89 | |
142 | - case INDEX_op_st8_i64: | 90 | if (n->start >= start && n->last <= last) { |
143 | - case INDEX_op_st16_i64: | 91 | interval_tree_remove(n, &targetdata_root); |
144 | - case INDEX_op_st32_i64: | 92 | - g_free(n); |
145 | - case INDEX_op_st_i64: | 93 | + g_free_rcu(t, rcu); |
146 | case INDEX_op_ctpop_i64: | 94 | continue; |
147 | case INDEX_op_neg_i64: | 95 | } |
148 | case INDEX_op_not_i64: | 96 | |
149 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | 97 | @@ -XXX,XX +XXX,XX @@ void page_reset_target_data(target_ulong start, target_ulong end) |
150 | case INDEX_op_bswap32_i64: | 98 | n_last = MIN(last, n->last); |
151 | case INDEX_op_bswap64_i64: | 99 | p_len = (n_last + 1 - n_start) >> TARGET_PAGE_BITS; |
152 | case INDEX_op_extract_i64: | 100 | |
153 | - return &r_r; | 101 | - t = container_of(n, TargetPageDataNode, itree); |
154 | + return C_O1_I1(r, r); | 102 | memset(t->data[p_ofs], 0, p_len * TARGET_PAGE_DATA_SIZE); |
155 | + | ||
156 | + case INDEX_op_st8_i32: | ||
157 | + case INDEX_op_st16_i32: | ||
158 | + case INDEX_op_st_i32: | ||
159 | + case INDEX_op_st8_i64: | ||
160 | + case INDEX_op_st16_i64: | ||
161 | + case INDEX_op_st32_i64: | ||
162 | + case INDEX_op_st_i64: | ||
163 | + return C_O0_I2(r, r); | ||
164 | |||
165 | case INDEX_op_add_i32: | ||
166 | case INDEX_op_and_i32: | ||
167 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
168 | case INDEX_op_rotl_i64: | ||
169 | case INDEX_op_rotr_i64: | ||
170 | case INDEX_op_setcond_i64: | ||
171 | - return &r_r_ri; | ||
172 | + return C_O1_I2(r, r, ri); | ||
173 | + | ||
174 | case INDEX_op_mul_i32: | ||
175 | case INDEX_op_mul_i64: | ||
176 | - return &r_r_rI; | ||
177 | + return C_O1_I2(r, r, rI); | ||
178 | + | ||
179 | case INDEX_op_div_i32: | ||
180 | case INDEX_op_divu_i32: | ||
181 | case INDEX_op_nand_i32: | ||
182 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
183 | case INDEX_op_divu_i64: | ||
184 | case INDEX_op_mulsh_i64: | ||
185 | case INDEX_op_muluh_i64: | ||
186 | - return &r_r_r; | ||
187 | + return C_O1_I2(r, r, r); | ||
188 | + | ||
189 | case INDEX_op_sub_i32: | ||
190 | - return &r_rI_ri; | ||
191 | + return C_O1_I2(r, rI, ri); | ||
192 | case INDEX_op_add_i64: | ||
193 | - return &r_r_rT; | ||
194 | + return C_O1_I2(r, r, rT); | ||
195 | case INDEX_op_or_i64: | ||
196 | case INDEX_op_xor_i64: | ||
197 | - return &r_r_rU; | ||
198 | + return C_O1_I2(r, r, rU); | ||
199 | case INDEX_op_sub_i64: | ||
200 | - return &r_rI_rT; | ||
201 | + return C_O1_I2(r, rI, rT); | ||
202 | case INDEX_op_clz_i32: | ||
203 | case INDEX_op_ctz_i32: | ||
204 | case INDEX_op_clz_i64: | ||
205 | case INDEX_op_ctz_i64: | ||
206 | - return &r_r_rZW; | ||
207 | + return C_O1_I2(r, r, rZW); | ||
208 | |||
209 | case INDEX_op_brcond_i32: | ||
210 | case INDEX_op_brcond_i64: | ||
211 | - return &r_ri; | ||
212 | + return C_O0_I2(r, ri); | ||
213 | |||
214 | case INDEX_op_movcond_i32: | ||
215 | case INDEX_op_movcond_i64: | ||
216 | - return &movc; | ||
217 | + return C_O1_I4(r, r, ri, rZ, rZ); | ||
218 | case INDEX_op_deposit_i32: | ||
219 | case INDEX_op_deposit_i64: | ||
220 | - return &dep; | ||
221 | + return C_O1_I2(r, 0, rZ); | ||
222 | case INDEX_op_brcond2_i32: | ||
223 | - return &br2; | ||
224 | + return C_O0_I4(r, r, ri, ri); | ||
225 | case INDEX_op_setcond2_i32: | ||
226 | - return &setc2; | ||
227 | + return C_O1_I4(r, r, r, ri, ri); | ||
228 | case INDEX_op_add2_i64: | ||
229 | case INDEX_op_add2_i32: | ||
230 | - return &add2; | ||
231 | + return C_O2_I4(r, r, r, r, rI, rZM); | ||
232 | case INDEX_op_sub2_i64: | ||
233 | case INDEX_op_sub2_i32: | ||
234 | - return &sub2; | ||
235 | + return C_O2_I4(r, r, rI, rZM, r, r); | ||
236 | |||
237 | case INDEX_op_qemu_ld_i32: | ||
238 | return (TCG_TARGET_REG_BITS == 64 || TARGET_LONG_BITS == 32 | ||
239 | - ? &r_L : &r_L_L); | ||
240 | + ? C_O1_I1(r, L) | ||
241 | + : C_O1_I2(r, L, L)); | ||
242 | + | ||
243 | case INDEX_op_qemu_st_i32: | ||
244 | return (TCG_TARGET_REG_BITS == 64 || TARGET_LONG_BITS == 32 | ||
245 | - ? &S_S : &S_S_S); | ||
246 | + ? C_O0_I2(S, S) | ||
247 | + : C_O0_I3(S, S, S)); | ||
248 | + | ||
249 | case INDEX_op_qemu_ld_i64: | ||
250 | - return (TCG_TARGET_REG_BITS == 64 ? &r_L | ||
251 | - : TARGET_LONG_BITS == 32 ? &L_L_L : &L_L_L_L); | ||
252 | + return (TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, L) | ||
253 | + : TARGET_LONG_BITS == 32 ? C_O2_I1(L, L, L) | ||
254 | + : C_O2_I2(L, L, L, L)); | ||
255 | + | ||
256 | case INDEX_op_qemu_st_i64: | ||
257 | - return (TCG_TARGET_REG_BITS == 64 ? &S_S | ||
258 | - : TARGET_LONG_BITS == 32 ? &S_S_S : &S_S_S_S); | ||
259 | + return (TCG_TARGET_REG_BITS == 64 ? C_O0_I2(S, S) | ||
260 | + : TARGET_LONG_BITS == 32 ? C_O0_I3(S, S, S) | ||
261 | + : C_O0_I4(S, S, S, S)); | ||
262 | |||
263 | case INDEX_op_add_vec: | ||
264 | case INDEX_op_sub_vec: | ||
265 | @@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) | ||
266 | case INDEX_op_ppc_mulou_vec: | ||
267 | case INDEX_op_ppc_pkum_vec: | ||
268 | case INDEX_op_dup2_vec: | ||
269 | - return &v_v_v; | ||
270 | + return C_O1_I2(v, v, v); | ||
271 | + | ||
272 | case INDEX_op_not_vec: | ||
273 | case INDEX_op_neg_vec: | ||
274 | - return &v_v; | ||
275 | + return C_O1_I1(v, v); | ||
276 | + | ||
277 | case INDEX_op_dup_vec: | ||
278 | - return have_isa_3_00 ? &v_vr : &v_v; | ||
279 | + return have_isa_3_00 ? C_O1_I1(v, vr) : C_O1_I1(v, v); | ||
280 | + | ||
281 | case INDEX_op_ld_vec: | ||
282 | - case INDEX_op_st_vec: | ||
283 | case INDEX_op_dupm_vec: | ||
284 | - return &v_r; | ||
285 | + return C_O1_I1(v, r); | ||
286 | + | ||
287 | + case INDEX_op_st_vec: | ||
288 | + return C_O0_I2(v, r); | ||
289 | + | ||
290 | case INDEX_op_bitsel_vec: | ||
291 | case INDEX_op_ppc_msum_vec: | ||
292 | - return &v_v_v_v; | ||
293 | + return C_O1_I3(v, v, v, v); | ||
294 | |||
295 | default: | ||
296 | - return NULL; | ||
297 | + g_assert_not_reached(); | ||
298 | } | 103 | } |
299 | } | 104 | } |
300 | |||
301 | -- | 105 | -- |
302 | 2.25.1 | 106 | 2.34.1 |
303 | 107 | ||
304 | 108 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | As in page_get_flags, we need to try again with the mmap |
---|---|---|---|
2 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | 2 | lock held if we fail a page lookup. |
3 | |||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
3 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
4 | --- | 6 | --- |
5 | tcg/mips/tcg-target-con-str.h | 24 +++++++++++ | 7 | accel/tcg/user-exec.c | 41 ++++++++++++++++++++++++++++++++++------- |
6 | tcg/mips/tcg-target.h | 1 + | 8 | 1 file changed, 34 insertions(+), 7 deletions(-) |
7 | tcg/mips/tcg-target.c.inc | 77 ++++++++++------------------------- | ||
8 | 3 files changed, 46 insertions(+), 56 deletions(-) | ||
9 | create mode 100644 tcg/mips/tcg-target-con-str.h | ||
10 | 9 | ||
11 | diff --git a/tcg/mips/tcg-target-con-str.h b/tcg/mips/tcg-target-con-str.h | 10 | diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c |
12 | new file mode 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
13 | index XXXXXXX..XXXXXXX | 12 | --- a/accel/tcg/user-exec.c |
14 | --- /dev/null | 13 | +++ b/accel/tcg/user-exec.c |
15 | +++ b/tcg/mips/tcg-target-con-str.h | 14 | @@ -XXX,XX +XXX,XX @@ void page_set_flags(target_ulong start, target_ulong end, int flags) |
16 | @@ -XXX,XX +XXX,XX @@ | 15 | int page_check_range(target_ulong start, target_ulong len, int flags) |
17 | +/* SPDX-License-Identifier: MIT */ | 16 | { |
18 | +/* | 17 | target_ulong last; |
19 | + * Define MIPS target-specific operand constraints. | 18 | + int locked; /* tri-state: =0: unlocked, +1: global, -1: local */ |
20 | + * Copyright (c) 2021 Linaro | 19 | + int ret; |
21 | + */ | 20 | |
21 | if (len == 0) { | ||
22 | return 0; /* trivial length */ | ||
23 | @@ -XXX,XX +XXX,XX @@ int page_check_range(target_ulong start, target_ulong len, int flags) | ||
24 | return -1; /* wrap around */ | ||
25 | } | ||
26 | |||
27 | + locked = have_mmap_lock(); | ||
28 | while (true) { | ||
29 | PageFlagsNode *p = pageflags_find(start, last); | ||
30 | int missing; | ||
31 | |||
32 | if (!p) { | ||
33 | - return -1; /* entire region invalid */ | ||
34 | + if (!locked) { | ||
35 | + /* | ||
36 | + * Lockless lookups have false negatives. | ||
37 | + * Retry with the lock held. | ||
38 | + */ | ||
39 | + mmap_lock(); | ||
40 | + locked = -1; | ||
41 | + p = pageflags_find(start, last); | ||
42 | + } | ||
43 | + if (!p) { | ||
44 | + ret = -1; /* entire region invalid */ | ||
45 | + break; | ||
46 | + } | ||
47 | } | ||
48 | if (start < p->itree.start) { | ||
49 | - return -1; /* initial bytes invalid */ | ||
50 | + ret = -1; /* initial bytes invalid */ | ||
51 | + break; | ||
52 | } | ||
53 | |||
54 | missing = flags & ~p->flags; | ||
55 | if (missing & PAGE_READ) { | ||
56 | - return -1; /* page not readable */ | ||
57 | + ret = -1; /* page not readable */ | ||
58 | + break; | ||
59 | } | ||
60 | if (missing & PAGE_WRITE) { | ||
61 | if (!(p->flags & PAGE_WRITE_ORG)) { | ||
62 | - return -1; /* page not writable */ | ||
63 | + ret = -1; /* page not writable */ | ||
64 | + break; | ||
65 | } | ||
66 | /* Asking about writable, but has been protected: undo. */ | ||
67 | if (!page_unprotect(start, 0)) { | ||
68 | - return -1; | ||
69 | + ret = -1; | ||
70 | + break; | ||
71 | } | ||
72 | /* TODO: page_unprotect should take a range, not a single page. */ | ||
73 | if (last - start < TARGET_PAGE_SIZE) { | ||
74 | - return 0; /* ok */ | ||
75 | + ret = 0; /* ok */ | ||
76 | + break; | ||
77 | } | ||
78 | start += TARGET_PAGE_SIZE; | ||
79 | continue; | ||
80 | } | ||
81 | |||
82 | if (last <= p->itree.last) { | ||
83 | - return 0; /* ok */ | ||
84 | + ret = 0; /* ok */ | ||
85 | + break; | ||
86 | } | ||
87 | start = p->itree.last + 1; | ||
88 | } | ||
22 | + | 89 | + |
23 | +/* | 90 | + /* Release the lock if acquired locally. */ |
24 | + * Define constraint letters for register sets: | 91 | + if (locked < 0) { |
25 | + * REGS(letter, register_mask) | 92 | + mmap_unlock(); |
26 | + */ | 93 | + } |
27 | +REGS('r', ALL_GENERAL_REGS) | 94 | + return ret; |
28 | +REGS('L', ALL_QLOAD_REGS) | ||
29 | +REGS('S', ALL_QSTORE_REGS) | ||
30 | + | ||
31 | +/* | ||
32 | + * Define constraint letters for constants: | ||
33 | + * CONST(letter, TCG_CT_CONST_* bit set) | ||
34 | + */ | ||
35 | +CONST('I', TCG_CT_CONST_U16) | ||
36 | +CONST('J', TCG_CT_CONST_S16) | ||
37 | +CONST('K', TCG_CT_CONST_P2M1) | ||
38 | +CONST('N', TCG_CT_CONST_N16) | ||
39 | +CONST('W', TCG_CT_CONST_WSZ) | ||
40 | +CONST('Z', TCG_CT_CONST_ZERO) | ||
41 | diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h | ||
42 | index XXXXXXX..XXXXXXX 100644 | ||
43 | --- a/tcg/mips/tcg-target.h | ||
44 | +++ b/tcg/mips/tcg-target.h | ||
45 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | ||
46 | #ifdef CONFIG_SOFTMMU | ||
47 | #define TCG_TARGET_NEED_LDST_LABELS | ||
48 | #endif | ||
49 | +#define TCG_TARGET_CON_STR_H | ||
50 | |||
51 | #endif | ||
52 | diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc | ||
53 | index XXXXXXX..XXXXXXX 100644 | ||
54 | --- a/tcg/mips/tcg-target.c.inc | ||
55 | +++ b/tcg/mips/tcg-target.c.inc | ||
56 | @@ -XXX,XX +XXX,XX @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, | ||
57 | #define TCG_CT_CONST_N16 0x1000 /* "Negatable" 16-bit: -32767 - 32767 */ | ||
58 | #define TCG_CT_CONST_WSZ 0x2000 /* word size */ | ||
59 | |||
60 | +#define ALL_GENERAL_REGS 0xffffffffu | ||
61 | +#define NOA0_REGS (ALL_GENERAL_REGS & ~(1 << TCG_REG_A0)) | ||
62 | + | ||
63 | +#ifdef CONFIG_SOFTMMU | ||
64 | +#define ALL_QLOAD_REGS \ | ||
65 | + (NOA0_REGS & ~((TCG_TARGET_REG_BITS < TARGET_LONG_BITS) << TCG_REG_A2)) | ||
66 | +#define ALL_QSTORE_REGS \ | ||
67 | + (NOA0_REGS & ~(TCG_TARGET_REG_BITS < TARGET_LONG_BITS \ | ||
68 | + ? (1 << TCG_REG_A2) | (1 << TCG_REG_A3) \ | ||
69 | + : (1 << TCG_REG_A1))) | ||
70 | +#else | ||
71 | +#define ALL_QLOAD_REGS NOA0_REGS | ||
72 | +#define ALL_QSTORE_REGS NOA0_REGS | ||
73 | +#endif | ||
74 | + | ||
75 | + | ||
76 | static inline bool is_p2m1(tcg_target_long val) | ||
77 | { | ||
78 | return val && ((val + 1) & val) == 0; | ||
79 | } | 95 | } |
80 | 96 | ||
81 | -/* parse target specific constraints */ | 97 | void page_protect(tb_page_addr_t address) |
82 | -static const char *target_parse_constraint(TCGArgConstraint *ct, | ||
83 | - const char *ct_str, TCGType type) | ||
84 | -{ | ||
85 | - switch(*ct_str++) { | ||
86 | - case 'r': | ||
87 | - ct->regs = 0xffffffff; | ||
88 | - break; | ||
89 | - case 'L': /* qemu_ld input arg constraint */ | ||
90 | - ct->regs = 0xffffffff; | ||
91 | - tcg_regset_reset_reg(ct->regs, TCG_REG_A0); | ||
92 | -#if defined(CONFIG_SOFTMMU) | ||
93 | - if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { | ||
94 | - tcg_regset_reset_reg(ct->regs, TCG_REG_A2); | ||
95 | - } | ||
96 | -#endif | ||
97 | - break; | ||
98 | - case 'S': /* qemu_st constraint */ | ||
99 | - ct->regs = 0xffffffff; | ||
100 | - tcg_regset_reset_reg(ct->regs, TCG_REG_A0); | ||
101 | -#if defined(CONFIG_SOFTMMU) | ||
102 | - if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { | ||
103 | - tcg_regset_reset_reg(ct->regs, TCG_REG_A2); | ||
104 | - tcg_regset_reset_reg(ct->regs, TCG_REG_A3); | ||
105 | - } else { | ||
106 | - tcg_regset_reset_reg(ct->regs, TCG_REG_A1); | ||
107 | - } | ||
108 | -#endif | ||
109 | - break; | ||
110 | - case 'I': | ||
111 | - ct->ct |= TCG_CT_CONST_U16; | ||
112 | - break; | ||
113 | - case 'J': | ||
114 | - ct->ct |= TCG_CT_CONST_S16; | ||
115 | - break; | ||
116 | - case 'K': | ||
117 | - ct->ct |= TCG_CT_CONST_P2M1; | ||
118 | - break; | ||
119 | - case 'N': | ||
120 | - ct->ct |= TCG_CT_CONST_N16; | ||
121 | - break; | ||
122 | - case 'W': | ||
123 | - ct->ct |= TCG_CT_CONST_WSZ; | ||
124 | - break; | ||
125 | - case 'Z': | ||
126 | - /* We are cheating a bit here, using the fact that the register | ||
127 | - ZERO is also the register number 0. Hence there is no need | ||
128 | - to check for const_args in each instruction. */ | ||
129 | - ct->ct |= TCG_CT_CONST_ZERO; | ||
130 | - break; | ||
131 | - default: | ||
132 | - return NULL; | ||
133 | - } | ||
134 | - return ct_str; | ||
135 | -} | ||
136 | - | ||
137 | /* test if a constant matches the constraint */ | ||
138 | static inline int tcg_target_const_match(tcg_target_long val, TCGType type, | ||
139 | const TCGArgConstraint *arg_ct) | ||
140 | @@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, | ||
141 | TCGArg a0, a1, a2; | ||
142 | int c2; | ||
143 | |||
144 | + /* | ||
145 | + * Note that many operands use the constraint set "rZ". | ||
146 | + * We make use of the fact that 0 is the ZERO register, | ||
147 | + * and hence such cases need not check for const_args. | ||
148 | + */ | ||
149 | a0 = args[0]; | ||
150 | a1 = args[1]; | ||
151 | a2 = args[2]; | ||
152 | -- | 98 | -- |
153 | 2.25.1 | 99 | 2.34.1 |
154 | 100 | ||
155 | 101 | diff view generated by jsdifflib |
1 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 1 | From: Ilya Leoshkevich <iii@linux.ibm.com> |
---|---|---|---|
2 | |||
3 | Add a test that locklessly changes and exercises page protection bits | ||
4 | from various threads. This helps catch race conditions in the VMA | ||
5 | handling. | ||
6 | |||
7 | Acked-by: Alex Bennée <alex.bennee@linaro.org> | ||
8 | Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> | ||
9 | Message-Id: <20221223120252.513319-1-iii@linux.ibm.com> | ||
2 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | 10 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
3 | --- | 11 | --- |
4 | tcg/arm/tcg-target-con-str.h | 22 +++++++++++ | 12 | tests/tcg/multiarch/nop_func.h | 25 ++++ |
5 | tcg/arm/tcg-target.h | 1 + | 13 | tests/tcg/multiarch/munmap-pthread.c | 16 +-- |
6 | tcg/arm/tcg-target.c.inc | 74 +++++++++--------------------------- | 14 | tests/tcg/multiarch/vma-pthread.c | 207 +++++++++++++++++++++++++++ |
7 | 3 files changed, 41 insertions(+), 56 deletions(-) | 15 | tests/tcg/multiarch/Makefile.target | 3 + |
8 | create mode 100644 tcg/arm/tcg-target-con-str.h | 16 | 4 files changed, 236 insertions(+), 15 deletions(-) |
9 | 17 | create mode 100644 tests/tcg/multiarch/nop_func.h | |
10 | diff --git a/tcg/arm/tcg-target-con-str.h b/tcg/arm/tcg-target-con-str.h | 18 | create mode 100644 tests/tcg/multiarch/vma-pthread.c |
19 | |||
20 | diff --git a/tests/tcg/multiarch/nop_func.h b/tests/tcg/multiarch/nop_func.h | ||
11 | new file mode 100644 | 21 | new file mode 100644 |
12 | index XXXXXXX..XXXXXXX | 22 | index XXXXXXX..XXXXXXX |
13 | --- /dev/null | 23 | --- /dev/null |
14 | +++ b/tcg/arm/tcg-target-con-str.h | 24 | +++ b/tests/tcg/multiarch/nop_func.h |
15 | @@ -XXX,XX +XXX,XX @@ | 25 | @@ -XXX,XX +XXX,XX @@ |
16 | +/* SPDX-License-Identifier: MIT */ | ||
17 | +/* | 26 | +/* |
18 | + * Define Arm target-specific operand constraints. | 27 | + * No-op functions that can be safely copied. |
19 | + * Copyright (c) 2021 Linaro | 28 | + * |
29 | + * SPDX-License-Identifier: GPL-2.0-or-later | ||
20 | + */ | 30 | + */ |
21 | + | 31 | +#ifndef NOP_FUNC_H |
32 | +#define NOP_FUNC_H | ||
33 | + | ||
34 | +static const char nop_func[] = { | ||
35 | +#if defined(__aarch64__) | ||
36 | + 0xc0, 0x03, 0x5f, 0xd6, /* ret */ | ||
37 | +#elif defined(__alpha__) | ||
38 | + 0x01, 0x80, 0xFA, 0x6B, /* ret */ | ||
39 | +#elif defined(__arm__) | ||
40 | + 0x1e, 0xff, 0x2f, 0xe1, /* bx lr */ | ||
41 | +#elif defined(__riscv) | ||
42 | + 0x67, 0x80, 0x00, 0x00, /* ret */ | ||
43 | +#elif defined(__s390__) | ||
44 | + 0x07, 0xfe, /* br %r14 */ | ||
45 | +#elif defined(__i386__) || defined(__x86_64__) | ||
46 | + 0xc3, /* ret */ | ||
47 | +#endif | ||
48 | +}; | ||
49 | + | ||
50 | +#endif | ||
51 | diff --git a/tests/tcg/multiarch/munmap-pthread.c b/tests/tcg/multiarch/munmap-pthread.c | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/tests/tcg/multiarch/munmap-pthread.c | ||
54 | +++ b/tests/tcg/multiarch/munmap-pthread.c | ||
55 | @@ -XXX,XX +XXX,XX @@ | ||
56 | #include <sys/mman.h> | ||
57 | #include <unistd.h> | ||
58 | |||
59 | -static const char nop_func[] = { | ||
60 | -#if defined(__aarch64__) | ||
61 | - 0xc0, 0x03, 0x5f, 0xd6, /* ret */ | ||
62 | -#elif defined(__alpha__) | ||
63 | - 0x01, 0x80, 0xFA, 0x6B, /* ret */ | ||
64 | -#elif defined(__arm__) | ||
65 | - 0x1e, 0xff, 0x2f, 0xe1, /* bx lr */ | ||
66 | -#elif defined(__riscv) | ||
67 | - 0x67, 0x80, 0x00, 0x00, /* ret */ | ||
68 | -#elif defined(__s390__) | ||
69 | - 0x07, 0xfe, /* br %r14 */ | ||
70 | -#elif defined(__i386__) || defined(__x86_64__) | ||
71 | - 0xc3, /* ret */ | ||
72 | -#endif | ||
73 | -}; | ||
74 | +#include "nop_func.h" | ||
75 | |||
76 | static void *thread_mmap_munmap(void *arg) | ||
77 | { | ||
78 | diff --git a/tests/tcg/multiarch/vma-pthread.c b/tests/tcg/multiarch/vma-pthread.c | ||
79 | new file mode 100644 | ||
80 | index XXXXXXX..XXXXXXX | ||
81 | --- /dev/null | ||
82 | +++ b/tests/tcg/multiarch/vma-pthread.c | ||
83 | @@ -XXX,XX +XXX,XX @@ | ||
22 | +/* | 84 | +/* |
23 | + * Define constraint letters for register sets: | 85 | + * Test that VMA updates do not race. |
24 | + * REGS(letter, register_mask) | 86 | + * |
87 | + * SPDX-License-Identifier: GPL-2.0-or-later | ||
88 | + * | ||
89 | + * Map a contiguous chunk of RWX memory. Split it into 8 equally sized | ||
90 | + * regions, each of which is guaranteed to have a certain combination of | ||
91 | + * protection bits set. | ||
92 | + * | ||
93 | + * Reader, writer and executor threads perform the respective operations on | ||
94 | + * pages, which are guaranteed to have the respective protection bit set. | ||
95 | + * Two mutator threads change the non-fixed protection bits randomly. | ||
25 | + */ | 96 | + */ |
26 | +REGS('r', ALL_GENERAL_REGS) | 97 | +#include <assert.h> |
27 | +REGS('l', ALL_QLOAD_REGS) | 98 | +#include <fcntl.h> |
28 | +REGS('s', ALL_QSTORE_REGS) | 99 | +#include <pthread.h> |
29 | + | 100 | +#include <stdbool.h> |
30 | +/* | 101 | +#include <stdlib.h> |
31 | + * Define constraint letters for constants: | 102 | +#include <string.h> |
32 | + * CONST(letter, TCG_CT_CONST_* bit set) | 103 | +#include <stdio.h> |
33 | + */ | 104 | +#include <sys/mman.h> |
34 | +CONST('I', TCG_CT_CONST_ARM) | 105 | +#include <unistd.h> |
35 | +CONST('K', TCG_CT_CONST_INV) | 106 | + |
36 | +CONST('N', TCG_CT_CONST_NEG) | 107 | +#include "nop_func.h" |
37 | +CONST('Z', TCG_CT_CONST_ZERO) | 108 | + |
38 | diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h | 109 | +#define PAGE_IDX_BITS 10 |
110 | +#define PAGE_COUNT (1 << PAGE_IDX_BITS) | ||
111 | +#define PAGE_IDX_MASK (PAGE_COUNT - 1) | ||
112 | +#define REGION_IDX_BITS 3 | ||
113 | +#define PAGE_IDX_R_MASK (1 << 7) | ||
114 | +#define PAGE_IDX_W_MASK (1 << 8) | ||
115 | +#define PAGE_IDX_X_MASK (1 << 9) | ||
116 | +#define REGION_MASK (PAGE_IDX_R_MASK | PAGE_IDX_W_MASK | PAGE_IDX_X_MASK) | ||
117 | +#define PAGES_PER_REGION (1 << (PAGE_IDX_BITS - REGION_IDX_BITS)) | ||
118 | + | ||
119 | +struct context { | ||
120 | + int pagesize; | ||
121 | + char *ptr; | ||
122 | + int dev_null_fd; | ||
123 | + volatile int mutator_count; | ||
124 | +}; | ||
125 | + | ||
126 | +static void *thread_read(void *arg) | ||
127 | +{ | ||
128 | + struct context *ctx = arg; | ||
129 | + ssize_t sret; | ||
130 | + size_t i, j; | ||
131 | + int ret; | ||
132 | + | ||
133 | + for (i = 0; ctx->mutator_count; i++) { | ||
134 | + char *p; | ||
135 | + | ||
136 | + j = (i & PAGE_IDX_MASK) | PAGE_IDX_R_MASK; | ||
137 | + p = &ctx->ptr[j * ctx->pagesize]; | ||
138 | + | ||
139 | + /* Read directly. */ | ||
140 | + ret = memcmp(p, nop_func, sizeof(nop_func)); | ||
141 | + if (ret != 0) { | ||
142 | + fprintf(stderr, "fail direct read %p\n", p); | ||
143 | + abort(); | ||
144 | + } | ||
145 | + | ||
146 | + /* Read indirectly. */ | ||
147 | + sret = write(ctx->dev_null_fd, p, 1); | ||
148 | + if (sret != 1) { | ||
149 | + if (sret < 0) { | ||
150 | + fprintf(stderr, "fail indirect read %p (%m)\n", p); | ||
151 | + } else { | ||
152 | + fprintf(stderr, "fail indirect read %p (%zd)\n", p, sret); | ||
153 | + } | ||
154 | + abort(); | ||
155 | + } | ||
156 | + } | ||
157 | + | ||
158 | + return NULL; | ||
159 | +} | ||
160 | + | ||
161 | +static void *thread_write(void *arg) | ||
162 | +{ | ||
163 | + struct context *ctx = arg; | ||
164 | + struct timespec *ts; | ||
165 | + size_t i, j; | ||
166 | + int ret; | ||
167 | + | ||
168 | + for (i = 0; ctx->mutator_count; i++) { | ||
169 | + j = (i & PAGE_IDX_MASK) | PAGE_IDX_W_MASK; | ||
170 | + | ||
171 | + /* Write directly. */ | ||
172 | + memcpy(&ctx->ptr[j * ctx->pagesize], nop_func, sizeof(nop_func)); | ||
173 | + | ||
174 | + /* Write using a syscall. */ | ||
175 | + ts = (struct timespec *)(&ctx->ptr[(j + 1) * ctx->pagesize] - | ||
176 | + sizeof(struct timespec)); | ||
177 | + ret = clock_gettime(CLOCK_REALTIME, ts); | ||
178 | + if (ret != 0) { | ||
179 | + fprintf(stderr, "fail indirect write %p (%m)\n", ts); | ||
180 | + abort(); | ||
181 | + } | ||
182 | + } | ||
183 | + | ||
184 | + return NULL; | ||
185 | +} | ||
186 | + | ||
187 | +static void *thread_execute(void *arg) | ||
188 | +{ | ||
189 | + struct context *ctx = arg; | ||
190 | + size_t i, j; | ||
191 | + | ||
192 | + for (i = 0; ctx->mutator_count; i++) { | ||
193 | + j = (i & PAGE_IDX_MASK) | PAGE_IDX_X_MASK; | ||
194 | + ((void(*)(void))&ctx->ptr[j * ctx->pagesize])(); | ||
195 | + } | ||
196 | + | ||
197 | + return NULL; | ||
198 | +} | ||
199 | + | ||
200 | +static void *thread_mutate(void *arg) | ||
201 | +{ | ||
202 | + size_t i, start_idx, end_idx, page_idx, tmp; | ||
203 | + struct context *ctx = arg; | ||
204 | + unsigned int seed; | ||
205 | + int prot, ret; | ||
206 | + | ||
207 | + seed = (unsigned int)time(NULL); | ||
208 | + for (i = 0; i < 50000; i++) { | ||
209 | + start_idx = rand_r(&seed) & PAGE_IDX_MASK; | ||
210 | + end_idx = rand_r(&seed) & PAGE_IDX_MASK; | ||
211 | + if (start_idx > end_idx) { | ||
212 | + tmp = start_idx; | ||
213 | + start_idx = end_idx; | ||
214 | + end_idx = tmp; | ||
215 | + } | ||
216 | + prot = rand_r(&seed) & (PROT_READ | PROT_WRITE | PROT_EXEC); | ||
217 | + for (page_idx = start_idx & REGION_MASK; page_idx <= end_idx; | ||
218 | + page_idx += PAGES_PER_REGION) { | ||
219 | + if (page_idx & PAGE_IDX_R_MASK) { | ||
220 | + prot |= PROT_READ; | ||
221 | + } | ||
222 | + if (page_idx & PAGE_IDX_W_MASK) { | ||
223 | + /* FIXME: qemu syscalls check for both read+write. */ | ||
224 | + prot |= PROT_WRITE | PROT_READ; | ||
225 | + } | ||
226 | + if (page_idx & PAGE_IDX_X_MASK) { | ||
227 | + prot |= PROT_EXEC; | ||
228 | + } | ||
229 | + } | ||
230 | + ret = mprotect(&ctx->ptr[start_idx * ctx->pagesize], | ||
231 | + (end_idx - start_idx + 1) * ctx->pagesize, prot); | ||
232 | + assert(ret == 0); | ||
233 | + } | ||
234 | + | ||
235 | + __atomic_fetch_sub(&ctx->mutator_count, 1, __ATOMIC_SEQ_CST); | ||
236 | + | ||
237 | + return NULL; | ||
238 | +} | ||
239 | + | ||
240 | +int main(void) | ||
241 | +{ | ||
242 | + pthread_t threads[5]; | ||
243 | + struct context ctx; | ||
244 | + size_t i; | ||
245 | + int ret; | ||
246 | + | ||
247 | + /* Without a template, nothing to test. */ | ||
248 | + if (sizeof(nop_func) == 0) { | ||
249 | + return EXIT_SUCCESS; | ||
250 | + } | ||
251 | + | ||
252 | + /* Initialize memory chunk. */ | ||
253 | + ctx.pagesize = getpagesize(); | ||
254 | + ctx.ptr = mmap(NULL, PAGE_COUNT * ctx.pagesize, | ||
255 | + PROT_READ | PROT_WRITE | PROT_EXEC, | ||
256 | + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
257 | + assert(ctx.ptr != MAP_FAILED); | ||
258 | + for (i = 0; i < PAGE_COUNT; i++) { | ||
259 | + memcpy(&ctx.ptr[i * ctx.pagesize], nop_func, sizeof(nop_func)); | ||
260 | + } | ||
261 | + ctx.dev_null_fd = open("/dev/null", O_WRONLY); | ||
262 | + assert(ctx.dev_null_fd >= 0); | ||
263 | + ctx.mutator_count = 2; | ||
264 | + | ||
265 | + /* Start threads. */ | ||
266 | + ret = pthread_create(&threads[0], NULL, thread_read, &ctx); | ||
267 | + assert(ret == 0); | ||
268 | + ret = pthread_create(&threads[1], NULL, thread_write, &ctx); | ||
269 | + assert(ret == 0); | ||
270 | + ret = pthread_create(&threads[2], NULL, thread_execute, &ctx); | ||
271 | + assert(ret == 0); | ||
272 | + for (i = 3; i <= 4; i++) { | ||
273 | + ret = pthread_create(&threads[i], NULL, thread_mutate, &ctx); | ||
274 | + assert(ret == 0); | ||
275 | + } | ||
276 | + | ||
277 | + /* Wait for threads to stop. */ | ||
278 | + for (i = 0; i < sizeof(threads) / sizeof(threads[0]); i++) { | ||
279 | + ret = pthread_join(threads[i], NULL); | ||
280 | + assert(ret == 0); | ||
281 | + } | ||
282 | + | ||
283 | + /* Destroy memory chunk. */ | ||
284 | + ret = close(ctx.dev_null_fd); | ||
285 | + assert(ret == 0); | ||
286 | + ret = munmap(ctx.ptr, PAGE_COUNT * ctx.pagesize); | ||
287 | + assert(ret == 0); | ||
288 | + | ||
289 | + return EXIT_SUCCESS; | ||
290 | +} | ||
291 | diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target | ||
39 | index XXXXXXX..XXXXXXX 100644 | 292 | index XXXXXXX..XXXXXXX 100644 |
40 | --- a/tcg/arm/tcg-target.h | 293 | --- a/tests/tcg/multiarch/Makefile.target |
41 | +++ b/tcg/arm/tcg-target.h | 294 | +++ b/tests/tcg/multiarch/Makefile.target |
42 | @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); | 295 | @@ -XXX,XX +XXX,XX @@ signals: LDFLAGS+=-lrt -lpthread |
43 | #define TCG_TARGET_NEED_LDST_LABELS | 296 | munmap-pthread: CFLAGS+=-pthread |
44 | #endif | 297 | munmap-pthread: LDFLAGS+=-pthread |
45 | #define TCG_TARGET_NEED_POOL_LABELS | 298 | |
46 | +#define TCG_TARGET_CON_STR_H | 299 | +vma-pthread: CFLAGS+=-pthread |
47 | 300 | +vma-pthread: LDFLAGS+=-pthread | |
48 | #endif | 301 | + |
49 | diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc | 302 | # We define the runner for test-mmap after the individual |
50 | index XXXXXXX..XXXXXXX 100644 | 303 | # architectures have defined their supported pages sizes. If no |
51 | --- a/tcg/arm/tcg-target.c.inc | 304 | # additional page sizes are defined we only run the default test. |
52 | +++ b/tcg/arm/tcg-target.c.inc | ||
53 | @@ -XXX,XX +XXX,XX @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, | ||
54 | #define TCG_CT_CONST_NEG 0x400 | ||
55 | #define TCG_CT_CONST_ZERO 0x800 | ||
56 | |||
57 | -/* parse target specific constraints */ | ||
58 | -static const char *target_parse_constraint(TCGArgConstraint *ct, | ||
59 | - const char *ct_str, TCGType type) | ||
60 | -{ | ||
61 | - switch (*ct_str++) { | ||
62 | - case 'I': | ||
63 | - ct->ct |= TCG_CT_CONST_ARM; | ||
64 | - break; | ||
65 | - case 'K': | ||
66 | - ct->ct |= TCG_CT_CONST_INV; | ||
67 | - break; | ||
68 | - case 'N': /* The gcc constraint letter is L, already used here. */ | ||
69 | - ct->ct |= TCG_CT_CONST_NEG; | ||
70 | - break; | ||
71 | - case 'Z': | ||
72 | - ct->ct |= TCG_CT_CONST_ZERO; | ||
73 | - break; | ||
74 | +#define ALL_GENERAL_REGS 0xffffu | ||
75 | |||
76 | - case 'r': | ||
77 | - ct->regs = 0xffff; | ||
78 | - break; | ||
79 | - | ||
80 | - /* qemu_ld address */ | ||
81 | - case 'l': | ||
82 | - ct->regs = 0xffff; | ||
83 | +/* | ||
84 | + * r0-r2 will be overwritten when reading the tlb entry (softmmu only) | ||
85 | + * and r0-r1 doing the byte swapping, so don't use these. | ||
86 | + * r3 is removed for softmmu to avoid clashes with helper arguments. | ||
87 | + */ | ||
88 | #ifdef CONFIG_SOFTMMU | ||
89 | - /* r0-r2,lr will be overwritten when reading the tlb entry, | ||
90 | - so don't use these. */ | ||
91 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R0); | ||
92 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R1); | ||
93 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R2); | ||
94 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R3); | ||
95 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R14); | ||
96 | +#define ALL_QLOAD_REGS \ | ||
97 | + (ALL_GENERAL_REGS & ~((1 << TCG_REG_R0) | (1 << TCG_REG_R1) | \ | ||
98 | + (1 << TCG_REG_R2) | (1 << TCG_REG_R3) | \ | ||
99 | + (1 << TCG_REG_R14))) | ||
100 | +#define ALL_QSTORE_REGS \ | ||
101 | + (ALL_GENERAL_REGS & ~((1 << TCG_REG_R0) | (1 << TCG_REG_R1) | \ | ||
102 | + (1 << TCG_REG_R2) | (1 << TCG_REG_R14) | \ | ||
103 | + ((TARGET_LONG_BITS == 64) << TCG_REG_R3))) | ||
104 | +#else | ||
105 | +#define ALL_QLOAD_REGS ALL_GENERAL_REGS | ||
106 | +#define ALL_QSTORE_REGS \ | ||
107 | + (ALL_GENERAL_REGS & ~((1 << TCG_REG_R0) | (1 << TCG_REG_R1))) | ||
108 | #endif | ||
109 | - break; | ||
110 | - | ||
111 | - /* qemu_st address & data */ | ||
112 | - case 's': | ||
113 | - ct->regs = 0xffff; | ||
114 | - /* r0-r2 will be overwritten when reading the tlb entry (softmmu only) | ||
115 | - and r0-r1 doing the byte swapping, so don't use these. */ | ||
116 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R0); | ||
117 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R1); | ||
118 | -#if defined(CONFIG_SOFTMMU) | ||
119 | - /* Avoid clashes with registers being used for helper args */ | ||
120 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R2); | ||
121 | -#if TARGET_LONG_BITS == 64 | ||
122 | - /* Avoid clashes with registers being used for helper args */ | ||
123 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R3); | ||
124 | -#endif | ||
125 | - tcg_regset_reset_reg(ct->regs, TCG_REG_R14); | ||
126 | -#endif | ||
127 | - break; | ||
128 | - | ||
129 | - default: | ||
130 | - return NULL; | ||
131 | - } | ||
132 | - return ct_str; | ||
133 | -} | ||
134 | |||
135 | static inline uint32_t rotl(uint32_t val, int n) | ||
136 | { | ||
137 | -- | 305 | -- |
138 | 2.25.1 | 306 | 2.34.1 |
139 | 307 | ||
140 | 308 | diff view generated by jsdifflib |