blob: fd446fc47d5a80642a03278f37466a6603ab685b [file] [log] [blame]
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +04001/*
2 * Optimizations for Tiny Code Generator for QEMU
3 *
4 * Copyright (c) 2010 Samsung Electronics.
5 * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
Peter Maydell757e7252016-01-26 18:17:08 +000026#include "qemu/osdep.h"
Richard Henderson9531c072021-08-26 06:51:39 -070027#include "qemu/int128.h"
Richard Hendersonab84dc32023-08-23 23:04:24 -070028#include "qemu/interval-tree.h"
Richard Hendersonad3d0e42023-03-28 18:17:24 -070029#include "tcg/tcg-op-common.h"
Richard Henderson90163902021-03-18 10:21:45 -060030#include "tcg-internal.h"
Richard Henderson93280b62025-01-08 22:51:55 +010031#include "tcg-has.h"
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +040032
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +040033#define CASE_OP_32_64(x) \
34 glue(glue(case INDEX_op_, x), _i32): \
35 glue(glue(case INDEX_op_, x), _i64)
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +040036
Richard Henderson170ba882017-11-22 09:07:11 +010037#define CASE_OP_32_64_VEC(x) \
38 glue(glue(case INDEX_op_, x), _i32): \
39 glue(glue(case INDEX_op_, x), _i64): \
40 glue(glue(case INDEX_op_, x), _vec)
41
Richard Hendersonab84dc32023-08-23 23:04:24 -070042typedef struct MemCopyInfo {
43 IntervalTreeNode itree;
44 QSIMPLEQ_ENTRY (MemCopyInfo) next;
45 TCGTemp *ts;
46 TCGType type;
47} MemCopyInfo;
48
Richard Henderson6fcb98e2020-03-30 17:44:30 -070049typedef struct TempOptInfo {
Aurelien Jarnob41059d2015-07-27 12:41:44 +020050 bool is_const;
Richard Henderson63490392017-06-20 13:43:15 -070051 TCGTemp *prev_copy;
52 TCGTemp *next_copy;
Richard Hendersonab84dc32023-08-23 23:04:24 -070053 QSIMPLEQ_HEAD(, MemCopyInfo) mem_copy;
Richard Henderson54795542020-09-06 16:21:32 -070054 uint64_t val;
Richard Hendersonb1fde412021-08-23 13:07:49 -070055 uint64_t z_mask; /* mask bit is 0 if and only if value bit is 0 */
Richard Henderson6d70ddc2024-12-21 21:08:10 -080056 uint64_t s_mask; /* mask bit is 1 if value bit matches msb */
Richard Henderson6fcb98e2020-03-30 17:44:30 -070057} TempOptInfo;
Kirill Batuzov22613af2011-07-07 16:37:13 +040058
Richard Henderson3b3f8472021-08-23 22:06:31 -070059typedef struct OptContext {
Richard Hendersondc849882021-08-24 07:13:45 -070060 TCGContext *tcg;
Richard Hendersond0ed5152021-08-24 07:38:39 -070061 TCGOp *prev_mb;
Richard Henderson3b3f8472021-08-23 22:06:31 -070062 TCGTempSet temps_used;
Richard Henderson137f1f42021-08-24 08:49:25 -070063
Richard Hendersonab84dc32023-08-23 23:04:24 -070064 IntervalTreeRoot mem_copy;
65 QSIMPLEQ_HEAD(, MemCopyInfo) mem_free;
66
Richard Henderson137f1f42021-08-24 08:49:25 -070067 /* In flight values from optimization. */
Richard Henderson67f84c92021-08-25 08:00:20 -070068 TCGType type;
Richard Henderson3b3f8472021-08-23 22:06:31 -070069} OptContext;
70
Richard Henderson6fcb98e2020-03-30 17:44:30 -070071static inline TempOptInfo *ts_info(TCGTemp *ts)
Aurelien Jarnod9c769c2015-07-27 12:41:44 +020072{
Richard Henderson63490392017-06-20 13:43:15 -070073 return ts->state_ptr;
Aurelien Jarnod9c769c2015-07-27 12:41:44 +020074}
75
Richard Henderson6fcb98e2020-03-30 17:44:30 -070076static inline TempOptInfo *arg_info(TCGArg arg)
Aurelien Jarnod9c769c2015-07-27 12:41:44 +020077{
Richard Henderson63490392017-06-20 13:43:15 -070078 return ts_info(arg_temp(arg));
79}
80
Richard Hendersone1b6c142024-12-22 10:26:14 -080081static inline bool ti_is_const(TempOptInfo *ti)
82{
83 return ti->is_const;
84}
85
86static inline uint64_t ti_const_val(TempOptInfo *ti)
87{
88 return ti->val;
89}
90
91static inline bool ti_is_const_val(TempOptInfo *ti, uint64_t val)
92{
93 return ti_is_const(ti) && ti_const_val(ti) == val;
94}
95
Richard Henderson63490392017-06-20 13:43:15 -070096static inline bool ts_is_const(TCGTemp *ts)
97{
Richard Hendersone1b6c142024-12-22 10:26:14 -080098 return ti_is_const(ts_info(ts));
Richard Henderson63490392017-06-20 13:43:15 -070099}
100
Richard Henderson27cdb852023-10-23 11:38:00 -0700101static inline bool ts_is_const_val(TCGTemp *ts, uint64_t val)
102{
Richard Hendersone1b6c142024-12-22 10:26:14 -0800103 return ti_is_const_val(ts_info(ts), val);
Richard Henderson27cdb852023-10-23 11:38:00 -0700104}
105
Richard Henderson63490392017-06-20 13:43:15 -0700106static inline bool arg_is_const(TCGArg arg)
107{
108 return ts_is_const(arg_temp(arg));
109}
110
Richard Henderson27cdb852023-10-23 11:38:00 -0700111static inline bool arg_is_const_val(TCGArg arg, uint64_t val)
112{
113 return ts_is_const_val(arg_temp(arg), val);
114}
115
Richard Henderson63490392017-06-20 13:43:15 -0700116static inline bool ts_is_copy(TCGTemp *ts)
117{
118 return ts_info(ts)->next_copy != ts;
Aurelien Jarnod9c769c2015-07-27 12:41:44 +0200119}
120
Richard Henderson9f75e522023-11-02 13:37:46 -0700121static TCGTemp *cmp_better_copy(TCGTemp *a, TCGTemp *b)
122{
123 return a->kind < b->kind ? b : a;
124}
125
Aurelien Jarno1208d7d2015-07-27 12:41:44 +0200126/* Initialize and activate a temporary. */
Richard Henderson3b3f8472021-08-23 22:06:31 -0700127static void init_ts_info(OptContext *ctx, TCGTemp *ts)
Aurelien Jarno1208d7d2015-07-27 12:41:44 +0200128{
Richard Henderson63490392017-06-20 13:43:15 -0700129 size_t idx = temp_idx(ts);
Richard Henderson8f17a972020-03-30 19:52:02 -0700130 TempOptInfo *ti;
Richard Henderson63490392017-06-20 13:43:15 -0700131
Richard Henderson3b3f8472021-08-23 22:06:31 -0700132 if (test_bit(idx, ctx->temps_used.l)) {
Richard Henderson8f17a972020-03-30 19:52:02 -0700133 return;
134 }
Richard Henderson3b3f8472021-08-23 22:06:31 -0700135 set_bit(idx, ctx->temps_used.l);
Richard Henderson8f17a972020-03-30 19:52:02 -0700136
137 ti = ts->state_ptr;
138 if (ti == NULL) {
139 ti = tcg_malloc(sizeof(TempOptInfo));
Richard Henderson63490392017-06-20 13:43:15 -0700140 ts->state_ptr = ti;
Richard Henderson8f17a972020-03-30 19:52:02 -0700141 }
142
143 ti->next_copy = ts;
144 ti->prev_copy = ts;
Richard Hendersonab84dc32023-08-23 23:04:24 -0700145 QSIMPLEQ_INIT(&ti->mem_copy);
Richard Henderson8f17a972020-03-30 19:52:02 -0700146 if (ts->kind == TEMP_CONST) {
147 ti->is_const = true;
148 ti->val = ts->val;
Richard Hendersonb1fde412021-08-23 13:07:49 -0700149 ti->z_mask = ts->val;
Richard Henderson6d70ddc2024-12-21 21:08:10 -0800150 ti->s_mask = INT64_MIN >> clrsb64(ts->val);
Richard Henderson8f17a972020-03-30 19:52:02 -0700151 } else {
152 ti->is_const = false;
Richard Hendersonb1fde412021-08-23 13:07:49 -0700153 ti->z_mask = -1;
Richard Henderson57fe5c62021-08-26 12:04:46 -0700154 ti->s_mask = 0;
Aurelien Jarno1208d7d2015-07-27 12:41:44 +0200155 }
156}
157
Richard Hendersonab84dc32023-08-23 23:04:24 -0700158static MemCopyInfo *mem_copy_first(OptContext *ctx, intptr_t s, intptr_t l)
159{
160 IntervalTreeNode *r = interval_tree_iter_first(&ctx->mem_copy, s, l);
161 return r ? container_of(r, MemCopyInfo, itree) : NULL;
162}
163
164static MemCopyInfo *mem_copy_next(MemCopyInfo *mem, intptr_t s, intptr_t l)
165{
166 IntervalTreeNode *r = interval_tree_iter_next(&mem->itree, s, l);
167 return r ? container_of(r, MemCopyInfo, itree) : NULL;
168}
169
170static void remove_mem_copy(OptContext *ctx, MemCopyInfo *mc)
171{
172 TCGTemp *ts = mc->ts;
173 TempOptInfo *ti = ts_info(ts);
174
175 interval_tree_remove(&mc->itree, &ctx->mem_copy);
176 QSIMPLEQ_REMOVE(&ti->mem_copy, mc, MemCopyInfo, next);
177 QSIMPLEQ_INSERT_TAIL(&ctx->mem_free, mc, next);
178}
179
180static void remove_mem_copy_in(OptContext *ctx, intptr_t s, intptr_t l)
181{
182 while (true) {
183 MemCopyInfo *mc = mem_copy_first(ctx, s, l);
184 if (!mc) {
185 break;
186 }
187 remove_mem_copy(ctx, mc);
188 }
189}
190
191static void remove_mem_copy_all(OptContext *ctx)
192{
193 remove_mem_copy_in(ctx, 0, -1);
194 tcg_debug_assert(interval_tree_is_empty(&ctx->mem_copy));
195}
196
Richard Henderson9f75e522023-11-02 13:37:46 -0700197static TCGTemp *find_better_copy(TCGTemp *ts)
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +0200198{
Richard Henderson9f75e522023-11-02 13:37:46 -0700199 TCGTemp *i, *ret;
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +0200200
Richard Henderson4c868ce2020-04-23 09:02:23 -0700201 /* If this is already readonly, we can't do better. */
202 if (temp_readonly(ts)) {
Richard Henderson63490392017-06-20 13:43:15 -0700203 return ts;
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +0200204 }
205
Richard Henderson9f75e522023-11-02 13:37:46 -0700206 ret = ts;
Richard Henderson63490392017-06-20 13:43:15 -0700207 for (i = ts_info(ts)->next_copy; i != ts; i = ts_info(i)->next_copy) {
Richard Henderson9f75e522023-11-02 13:37:46 -0700208 ret = cmp_better_copy(ret, i);
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +0200209 }
Richard Henderson9f75e522023-11-02 13:37:46 -0700210 return ret;
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +0200211}
212
Richard Hendersonab84dc32023-08-23 23:04:24 -0700213static void move_mem_copies(TCGTemp *dst_ts, TCGTemp *src_ts)
214{
215 TempOptInfo *si = ts_info(src_ts);
216 TempOptInfo *di = ts_info(dst_ts);
217 MemCopyInfo *mc;
218
219 QSIMPLEQ_FOREACH(mc, &si->mem_copy, next) {
220 tcg_debug_assert(mc->ts == src_ts);
221 mc->ts = dst_ts;
222 }
223 QSIMPLEQ_CONCAT(&di->mem_copy, &si->mem_copy);
224}
225
226/* Reset TEMP's state, possibly removing the temp for the list of copies. */
227static void reset_ts(OptContext *ctx, TCGTemp *ts)
228{
229 TempOptInfo *ti = ts_info(ts);
230 TCGTemp *pts = ti->prev_copy;
231 TCGTemp *nts = ti->next_copy;
232 TempOptInfo *pi = ts_info(pts);
233 TempOptInfo *ni = ts_info(nts);
234
235 ni->prev_copy = ti->prev_copy;
236 pi->next_copy = ti->next_copy;
237 ti->next_copy = ts;
238 ti->prev_copy = ts;
239 ti->is_const = false;
240 ti->z_mask = -1;
241 ti->s_mask = 0;
242
243 if (!QSIMPLEQ_EMPTY(&ti->mem_copy)) {
244 if (ts == nts) {
245 /* Last temp copy being removed, the mem copies die. */
246 MemCopyInfo *mc;
247 QSIMPLEQ_FOREACH(mc, &ti->mem_copy, next) {
248 interval_tree_remove(&mc->itree, &ctx->mem_copy);
249 }
250 QSIMPLEQ_CONCAT(&ctx->mem_free, &ti->mem_copy);
251 } else {
252 move_mem_copies(find_better_copy(nts), ts);
253 }
254 }
255}
256
257static void reset_temp(OptContext *ctx, TCGArg arg)
258{
259 reset_ts(ctx, arg_temp(arg));
260}
261
262static void record_mem_copy(OptContext *ctx, TCGType type,
263 TCGTemp *ts, intptr_t start, intptr_t last)
264{
265 MemCopyInfo *mc;
266 TempOptInfo *ti;
267
268 mc = QSIMPLEQ_FIRST(&ctx->mem_free);
269 if (mc) {
270 QSIMPLEQ_REMOVE_HEAD(&ctx->mem_free, next);
271 } else {
272 mc = tcg_malloc(sizeof(*mc));
273 }
274
275 memset(mc, 0, sizeof(*mc));
276 mc->itree.start = start;
277 mc->itree.last = last;
278 mc->type = type;
279 interval_tree_insert(&mc->itree, &ctx->mem_copy);
280
281 ts = find_better_copy(ts);
282 ti = ts_info(ts);
283 mc->ts = ts;
284 QSIMPLEQ_INSERT_TAIL(&ti->mem_copy, mc, next);
285}
286
Richard Henderson63490392017-06-20 13:43:15 -0700287static bool ts_are_copies(TCGTemp *ts1, TCGTemp *ts2)
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +0200288{
Richard Henderson63490392017-06-20 13:43:15 -0700289 TCGTemp *i;
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +0200290
Richard Henderson63490392017-06-20 13:43:15 -0700291 if (ts1 == ts2) {
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +0200292 return true;
293 }
294
Richard Henderson63490392017-06-20 13:43:15 -0700295 if (!ts_is_copy(ts1) || !ts_is_copy(ts2)) {
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +0200296 return false;
297 }
298
Richard Henderson63490392017-06-20 13:43:15 -0700299 for (i = ts_info(ts1)->next_copy; i != ts1; i = ts_info(i)->next_copy) {
300 if (i == ts2) {
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +0200301 return true;
302 }
303 }
304
305 return false;
306}
307
Richard Henderson63490392017-06-20 13:43:15 -0700308static bool args_are_copies(TCGArg arg1, TCGArg arg2)
309{
310 return ts_are_copies(arg_temp(arg1), arg_temp(arg2));
311}
312
Richard Hendersonab84dc32023-08-23 23:04:24 -0700313static TCGTemp *find_mem_copy_for(OptContext *ctx, TCGType type, intptr_t s)
314{
315 MemCopyInfo *mc;
316
317 for (mc = mem_copy_first(ctx, s, s); mc; mc = mem_copy_next(mc, s, s)) {
318 if (mc->itree.start == s && mc->type == type) {
319 return find_better_copy(mc->ts);
320 }
321 }
322 return NULL;
323}
324
Richard Henderson26aac972023-10-23 12:31:57 -0700325static TCGArg arg_new_constant(OptContext *ctx, uint64_t val)
326{
327 TCGType type = ctx->type;
328 TCGTemp *ts;
329
330 if (type == TCG_TYPE_I32) {
331 val = (int32_t)val;
332 }
333
334 ts = tcg_constant_internal(type, val);
335 init_ts_info(ctx, ts);
336
337 return temp_arg(ts);
338}
339
Richard Hendersonfb04ab72024-01-10 18:21:58 +1100340static TCGArg arg_new_temp(OptContext *ctx)
341{
342 TCGTemp *ts = tcg_temp_new_internal(ctx->type, TEMP_EBB);
343 init_ts_info(ctx, ts);
344 return temp_arg(ts);
345}
346
Richard Hendersona3c1c572025-04-21 11:05:29 -0700347static TCGOp *opt_insert_after(OptContext *ctx, TCGOp *op,
348 TCGOpcode opc, unsigned narg)
349{
Richard Hendersoncf5c9f62025-01-21 20:34:41 -0800350 return tcg_op_insert_after(ctx->tcg, op, opc, ctx->type, narg);
Richard Hendersona3c1c572025-04-21 11:05:29 -0700351}
352
353static TCGOp *opt_insert_before(OptContext *ctx, TCGOp *op,
354 TCGOpcode opc, unsigned narg)
355{
Richard Hendersoncf5c9f62025-01-21 20:34:41 -0800356 return tcg_op_insert_before(ctx->tcg, op, opc, ctx->type, narg);
Richard Hendersona3c1c572025-04-21 11:05:29 -0700357}
358
Richard Henderson6b99d5b2021-08-24 10:57:56 -0700359static bool tcg_opt_gen_mov(OptContext *ctx, TCGOp *op, TCGArg dst, TCGArg src)
Kirill Batuzov22613af2011-07-07 16:37:13 +0400360{
Richard Henderson63490392017-06-20 13:43:15 -0700361 TCGTemp *dst_ts = arg_temp(dst);
362 TCGTemp *src_ts = arg_temp(src);
Richard Henderson6fcb98e2020-03-30 17:44:30 -0700363 TempOptInfo *di;
364 TempOptInfo *si;
Richard Henderson63490392017-06-20 13:43:15 -0700365 TCGOpcode new_op;
366
367 if (ts_are_copies(dst_ts, src_ts)) {
Richard Hendersondc849882021-08-24 07:13:45 -0700368 tcg_op_remove(ctx->tcg, op);
Richard Henderson6b99d5b2021-08-24 10:57:56 -0700369 return true;
Aurelien Jarno53657182015-06-04 21:53:25 +0200370 }
371
Richard Henderson986cac12023-01-09 13:59:35 -0800372 reset_ts(ctx, dst_ts);
Richard Henderson63490392017-06-20 13:43:15 -0700373 di = ts_info(dst_ts);
374 si = ts_info(src_ts);
Richard Henderson67f84c92021-08-25 08:00:20 -0700375
376 switch (ctx->type) {
377 case TCG_TYPE_I32:
Richard Henderson67f84c92021-08-25 08:00:20 -0700378 case TCG_TYPE_I64:
Richard Hendersonb5701262024-12-28 15:58:24 -0800379 new_op = INDEX_op_mov;
Richard Henderson67f84c92021-08-25 08:00:20 -0700380 break;
381 case TCG_TYPE_V64:
382 case TCG_TYPE_V128:
383 case TCG_TYPE_V256:
Richard Henderson4d872212025-01-02 19:43:06 -0800384 /* TCGOP_TYPE and TCGOP_VECE remain unchanged. */
Richard Henderson67f84c92021-08-25 08:00:20 -0700385 new_op = INDEX_op_mov_vec;
386 break;
387 default:
388 g_assert_not_reached();
Richard Henderson170ba882017-11-22 09:07:11 +0100389 }
Richard Hendersonc45cb8b2014-09-19 13:49:15 -0700390 op->opc = new_op;
Richard Henderson63490392017-06-20 13:43:15 -0700391 op->args[0] = dst;
392 op->args[1] = src;
Richard Hendersona62f6f52014-05-22 10:59:12 -0700393
Richard Hendersonfaa2e102021-08-26 09:03:59 -0700394 di->z_mask = si->z_mask;
Richard Henderson57fe5c62021-08-26 12:04:46 -0700395 di->s_mask = si->s_mask;
Richard Henderson24666ba2014-05-22 11:14:10 -0700396
Richard Henderson63490392017-06-20 13:43:15 -0700397 if (src_ts->type == dst_ts->type) {
Richard Henderson6fcb98e2020-03-30 17:44:30 -0700398 TempOptInfo *ni = ts_info(si->next_copy);
Richard Henderson63490392017-06-20 13:43:15 -0700399
400 di->next_copy = si->next_copy;
401 di->prev_copy = src_ts;
402 ni->prev_copy = dst_ts;
403 si->next_copy = dst_ts;
404 di->is_const = si->is_const;
405 di->val = si->val;
Richard Hendersonab84dc32023-08-23 23:04:24 -0700406
407 if (!QSIMPLEQ_EMPTY(&si->mem_copy)
408 && cmp_better_copy(src_ts, dst_ts) == dst_ts) {
409 move_mem_copies(dst_ts, src_ts);
410 }
Paolo Bonzini3a9d8b12013-01-11 15:42:52 -0800411 }
Richard Henderson6b99d5b2021-08-24 10:57:56 -0700412 return true;
Kirill Batuzov22613af2011-07-07 16:37:13 +0400413}
414
Richard Henderson6b99d5b2021-08-24 10:57:56 -0700415static bool tcg_opt_gen_movi(OptContext *ctx, TCGOp *op,
Richard Hendersondc849882021-08-24 07:13:45 -0700416 TCGArg dst, uint64_t val)
Richard Henderson8fe35e02020-03-30 20:42:43 -0700417{
Richard Hendersonfaa2e102021-08-26 09:03:59 -0700418 /* Convert movi to mov with constant temp. */
Richard Henderson26aac972023-10-23 12:31:57 -0700419 return tcg_opt_gen_mov(ctx, op, dst, arg_new_constant(ctx, val));
Richard Henderson8fe35e02020-03-30 20:42:43 -0700420}
421
Richard Hendersonaa28c9e2025-01-07 10:36:24 -0800422static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type,
423 uint64_t x, uint64_t y)
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400424{
Richard Henderson03271522013-08-14 14:35:56 -0700425 uint64_t l64, h64;
426
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400427 switch (op) {
Richard Henderson79602f62025-01-06 09:11:39 -0800428 case INDEX_op_add:
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400429 return x + y;
430
Richard Henderson60f34f52025-01-06 22:06:32 -0800431 case INDEX_op_sub:
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400432 return x - y;
433
Richard Hendersond2c3eca2025-01-07 09:32:18 -0800434 case INDEX_op_mul:
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400435 return x * y;
436
Richard Hendersonc3b920b2025-01-06 10:32:44 -0800437 case INDEX_op_and:
438 case INDEX_op_and_vec:
Kirill Batuzov9a810902011-07-07 16:37:15 +0400439 return x & y;
440
Richard Henderson49bd7512025-01-06 14:00:40 -0800441 case INDEX_op_or:
442 case INDEX_op_or_vec:
Kirill Batuzov9a810902011-07-07 16:37:15 +0400443 return x | y;
444
Richard Hendersonfffd3dc2025-01-06 15:18:35 -0800445 case INDEX_op_xor:
446 case INDEX_op_xor_vec:
Kirill Batuzov9a810902011-07-07 16:37:15 +0400447 return x ^ y;
448
Kirill Batuzov55c09752011-07-07 16:37:16 +0400449 case INDEX_op_shl_i32:
Richard Henderson50c5c4d2014-03-18 07:45:39 -0700450 return (uint32_t)x << (y & 31);
Kirill Batuzov55c09752011-07-07 16:37:16 +0400451
Kirill Batuzov55c09752011-07-07 16:37:16 +0400452 case INDEX_op_shl_i64:
Richard Henderson50c5c4d2014-03-18 07:45:39 -0700453 return (uint64_t)x << (y & 63);
Kirill Batuzov55c09752011-07-07 16:37:16 +0400454
455 case INDEX_op_shr_i32:
Richard Henderson50c5c4d2014-03-18 07:45:39 -0700456 return (uint32_t)x >> (y & 31);
Kirill Batuzov55c09752011-07-07 16:37:16 +0400457
Kirill Batuzov55c09752011-07-07 16:37:16 +0400458 case INDEX_op_shr_i64:
Richard Henderson50c5c4d2014-03-18 07:45:39 -0700459 return (uint64_t)x >> (y & 63);
Kirill Batuzov55c09752011-07-07 16:37:16 +0400460
461 case INDEX_op_sar_i32:
Richard Henderson50c5c4d2014-03-18 07:45:39 -0700462 return (int32_t)x >> (y & 31);
Kirill Batuzov55c09752011-07-07 16:37:16 +0400463
Kirill Batuzov55c09752011-07-07 16:37:16 +0400464 case INDEX_op_sar_i64:
Richard Henderson50c5c4d2014-03-18 07:45:39 -0700465 return (int64_t)x >> (y & 63);
Kirill Batuzov55c09752011-07-07 16:37:16 +0400466
467 case INDEX_op_rotr_i32:
Richard Henderson50c5c4d2014-03-18 07:45:39 -0700468 return ror32(x, y & 31);
Kirill Batuzov55c09752011-07-07 16:37:16 +0400469
Kirill Batuzov55c09752011-07-07 16:37:16 +0400470 case INDEX_op_rotr_i64:
Richard Henderson50c5c4d2014-03-18 07:45:39 -0700471 return ror64(x, y & 63);
Kirill Batuzov55c09752011-07-07 16:37:16 +0400472
473 case INDEX_op_rotl_i32:
Richard Henderson50c5c4d2014-03-18 07:45:39 -0700474 return rol32(x, y & 31);
Kirill Batuzov55c09752011-07-07 16:37:16 +0400475
Kirill Batuzov55c09752011-07-07 16:37:16 +0400476 case INDEX_op_rotl_i64:
Richard Henderson50c5c4d2014-03-18 07:45:39 -0700477 return rol64(x, y & 63);
Kirill Batuzov55c09752011-07-07 16:37:16 +0400478
Richard Henderson5c62d372025-01-06 23:46:47 -0800479 case INDEX_op_not:
480 case INDEX_op_not_vec:
Kirill Batuzova640f032011-07-07 16:37:17 +0400481 return ~x;
482
Richard Henderson69713582025-01-06 22:48:57 -0800483 case INDEX_op_neg:
Richard Hendersoncb25c802011-08-17 14:11:47 -0700484 return -x;
485
Richard Henderson46f96bf2025-01-06 12:37:02 -0800486 case INDEX_op_andc:
487 case INDEX_op_andc_vec:
Richard Hendersoncb25c802011-08-17 14:11:47 -0700488 return x & ~y;
489
Richard Henderson6aba25e2025-01-06 14:46:26 -0800490 case INDEX_op_orc:
491 case INDEX_op_orc_vec:
Richard Hendersoncb25c802011-08-17 14:11:47 -0700492 return x | ~y;
493
Richard Henderson5c0968a2025-01-06 15:47:53 -0800494 case INDEX_op_eqv:
495 case INDEX_op_eqv_vec:
Richard Hendersoncb25c802011-08-17 14:11:47 -0700496 return ~(x ^ y);
497
Richard Henderson59379a42025-01-06 20:32:54 -0800498 case INDEX_op_nand:
499 case INDEX_op_nand_vec:
Richard Hendersoncb25c802011-08-17 14:11:47 -0700500 return ~(x & y);
501
Richard Henderson3a8c4e92025-01-06 21:02:17 -0800502 case INDEX_op_nor:
503 case INDEX_op_nor_vec:
Richard Hendersoncb25c802011-08-17 14:11:47 -0700504 return ~(x | y);
505
Richard Henderson0e28d002016-11-16 09:23:28 +0100506 case INDEX_op_clz_i32:
507 return (uint32_t)x ? clz32(x) : y;
508
509 case INDEX_op_clz_i64:
510 return x ? clz64(x) : y;
511
512 case INDEX_op_ctz_i32:
513 return (uint32_t)x ? ctz32(x) : y;
514
515 case INDEX_op_ctz_i64:
516 return x ? ctz64(x) : y;
517
Richard Hendersona768e4e2016-11-21 11:13:39 +0100518 case INDEX_op_ctpop_i32:
519 return ctpop32(x);
520
521 case INDEX_op_ctpop_i64:
522 return ctpop64(x);
523
Richard Henderson64985942018-11-20 08:53:34 +0100524 CASE_OP_32_64(bswap16):
Richard Henderson0b76ff82021-06-13 13:04:00 -0700525 x = bswap16(x);
526 return y & TCG_BSWAP_OS ? (int16_t)x : x;
Richard Henderson64985942018-11-20 08:53:34 +0100527
528 CASE_OP_32_64(bswap32):
Richard Henderson0b76ff82021-06-13 13:04:00 -0700529 x = bswap32(x);
530 return y & TCG_BSWAP_OS ? (int32_t)x : x;
Richard Henderson64985942018-11-20 08:53:34 +0100531
532 case INDEX_op_bswap64_i64:
533 return bswap64(x);
534
Aurelien Jarno8bcb5c82015-07-27 12:41:45 +0200535 case INDEX_op_ext_i32_i64:
Kirill Batuzova640f032011-07-07 16:37:17 +0400536 return (int32_t)x;
537
Aurelien Jarno8bcb5c82015-07-27 12:41:45 +0200538 case INDEX_op_extu_i32_i64:
Richard Henderson609ad702015-07-24 07:16:00 -0700539 case INDEX_op_extrl_i64_i32:
Kirill Batuzova640f032011-07-07 16:37:17 +0400540 return (uint32_t)x;
Kirill Batuzova640f032011-07-07 16:37:17 +0400541
Richard Henderson609ad702015-07-24 07:16:00 -0700542 case INDEX_op_extrh_i64_i32:
543 return (uint64_t)x >> 32;
544
Richard Hendersonaa28c9e2025-01-07 10:36:24 -0800545 case INDEX_op_muluh:
546 if (type == TCG_TYPE_I32) {
547 return ((uint64_t)(uint32_t)x * (uint32_t)y) >> 32;
548 }
549 mulu64(&l64, &h64, x, y);
550 return h64;
551
Richard Hendersonc7428242025-01-07 11:19:29 -0800552 case INDEX_op_mulsh:
553 if (type == TCG_TYPE_I32) {
554 return ((int64_t)(int32_t)x * (int32_t)y) >> 32;
555 }
Richard Henderson03271522013-08-14 14:35:56 -0700556 muls64(&l64, &h64, x, y);
557 return h64;
558
Richard Henderson01547f72013-08-14 15:22:46 -0700559 case INDEX_op_div_i32:
560 /* Avoid crashing on divide by zero, otherwise undefined. */
561 return (int32_t)x / ((int32_t)y ? : 1);
562 case INDEX_op_divu_i32:
563 return (uint32_t)x / ((uint32_t)y ? : 1);
564 case INDEX_op_div_i64:
565 return (int64_t)x / ((int64_t)y ? : 1);
566 case INDEX_op_divu_i64:
567 return (uint64_t)x / ((uint64_t)y ? : 1);
568
569 case INDEX_op_rem_i32:
570 return (int32_t)x % ((int32_t)y ? : 1);
571 case INDEX_op_remu_i32:
572 return (uint32_t)x % ((uint32_t)y ? : 1);
573 case INDEX_op_rem_i64:
574 return (int64_t)x % ((int64_t)y ? : 1);
575 case INDEX_op_remu_i64:
576 return (uint64_t)x % ((uint64_t)y ? : 1);
577
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400578 default:
Richard Henderson732e89f2023-04-05 12:09:14 -0700579 g_assert_not_reached();
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400580 }
581}
582
Richard Henderson67f84c92021-08-25 08:00:20 -0700583static uint64_t do_constant_folding(TCGOpcode op, TCGType type,
584 uint64_t x, uint64_t y)
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400585{
Richard Hendersonaa28c9e2025-01-07 10:36:24 -0800586 uint64_t res = do_constant_folding_2(op, type, x, y);
Richard Henderson67f84c92021-08-25 08:00:20 -0700587 if (type == TCG_TYPE_I32) {
Aurelien Jarno29f3ff82015-07-10 18:03:31 +0200588 res = (int32_t)res;
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400589 }
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400590 return res;
591}
592
Richard Henderson9519da72012-10-02 11:32:26 -0700593static bool do_constant_folding_cond_32(uint32_t x, uint32_t y, TCGCond c)
594{
595 switch (c) {
596 case TCG_COND_EQ:
597 return x == y;
598 case TCG_COND_NE:
599 return x != y;
600 case TCG_COND_LT:
601 return (int32_t)x < (int32_t)y;
602 case TCG_COND_GE:
603 return (int32_t)x >= (int32_t)y;
604 case TCG_COND_LE:
605 return (int32_t)x <= (int32_t)y;
606 case TCG_COND_GT:
607 return (int32_t)x > (int32_t)y;
608 case TCG_COND_LTU:
609 return x < y;
610 case TCG_COND_GEU:
611 return x >= y;
612 case TCG_COND_LEU:
613 return x <= y;
614 case TCG_COND_GTU:
615 return x > y;
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700616 case TCG_COND_TSTEQ:
617 return (x & y) == 0;
618 case TCG_COND_TSTNE:
619 return (x & y) != 0;
620 case TCG_COND_ALWAYS:
621 case TCG_COND_NEVER:
622 break;
Richard Henderson9519da72012-10-02 11:32:26 -0700623 }
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700624 g_assert_not_reached();
Richard Henderson9519da72012-10-02 11:32:26 -0700625}
626
627static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c)
628{
629 switch (c) {
630 case TCG_COND_EQ:
631 return x == y;
632 case TCG_COND_NE:
633 return x != y;
634 case TCG_COND_LT:
635 return (int64_t)x < (int64_t)y;
636 case TCG_COND_GE:
637 return (int64_t)x >= (int64_t)y;
638 case TCG_COND_LE:
639 return (int64_t)x <= (int64_t)y;
640 case TCG_COND_GT:
641 return (int64_t)x > (int64_t)y;
642 case TCG_COND_LTU:
643 return x < y;
644 case TCG_COND_GEU:
645 return x >= y;
646 case TCG_COND_LEU:
647 return x <= y;
648 case TCG_COND_GTU:
649 return x > y;
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700650 case TCG_COND_TSTEQ:
651 return (x & y) == 0;
652 case TCG_COND_TSTNE:
653 return (x & y) != 0;
654 case TCG_COND_ALWAYS:
655 case TCG_COND_NEVER:
656 break;
Richard Henderson9519da72012-10-02 11:32:26 -0700657 }
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700658 g_assert_not_reached();
Richard Henderson9519da72012-10-02 11:32:26 -0700659}
660
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700661static int do_constant_folding_cond_eq(TCGCond c)
Richard Henderson9519da72012-10-02 11:32:26 -0700662{
663 switch (c) {
664 case TCG_COND_GT:
665 case TCG_COND_LTU:
666 case TCG_COND_LT:
667 case TCG_COND_GTU:
668 case TCG_COND_NE:
669 return 0;
670 case TCG_COND_GE:
671 case TCG_COND_GEU:
672 case TCG_COND_LE:
673 case TCG_COND_LEU:
674 case TCG_COND_EQ:
675 return 1;
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700676 case TCG_COND_TSTEQ:
677 case TCG_COND_TSTNE:
678 return -1;
679 case TCG_COND_ALWAYS:
680 case TCG_COND_NEVER:
681 break;
Richard Henderson9519da72012-10-02 11:32:26 -0700682 }
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700683 g_assert_not_reached();
Richard Henderson9519da72012-10-02 11:32:26 -0700684}
685
Richard Henderson8d57bf12021-08-24 08:34:27 -0700686/*
687 * Return -1 if the condition can't be simplified,
688 * and the result of the condition (0 or 1) if it can.
689 */
Richard Henderson67f84c92021-08-25 08:00:20 -0700690static int do_constant_folding_cond(TCGType type, TCGArg x,
Richard Henderson8d57bf12021-08-24 08:34:27 -0700691 TCGArg y, TCGCond c)
Aurelien Jarnof8dd19e2012-09-06 16:47:14 +0200692{
Richard Henderson63490392017-06-20 13:43:15 -0700693 if (arg_is_const(x) && arg_is_const(y)) {
Alex Bennée9becc362022-02-09 11:21:42 +0000694 uint64_t xv = arg_info(x)->val;
695 uint64_t yv = arg_info(y)->val;
696
Richard Henderson67f84c92021-08-25 08:00:20 -0700697 switch (type) {
698 case TCG_TYPE_I32:
Richard Henderson170ba882017-11-22 09:07:11 +0100699 return do_constant_folding_cond_32(xv, yv, c);
Richard Henderson67f84c92021-08-25 08:00:20 -0700700 case TCG_TYPE_I64:
701 return do_constant_folding_cond_64(xv, yv, c);
702 default:
703 /* Only scalar comparisons are optimizable */
704 return -1;
Aurelien Jarnof8dd19e2012-09-06 16:47:14 +0200705 }
Richard Henderson63490392017-06-20 13:43:15 -0700706 } else if (args_are_copies(x, y)) {
Richard Henderson9519da72012-10-02 11:32:26 -0700707 return do_constant_folding_cond_eq(c);
Richard Henderson27cdb852023-10-23 11:38:00 -0700708 } else if (arg_is_const_val(y, 0)) {
Aurelien Jarnob336ceb2012-09-18 19:37:00 +0200709 switch (c) {
710 case TCG_COND_LTU:
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700711 case TCG_COND_TSTNE:
Aurelien Jarnob336ceb2012-09-18 19:37:00 +0200712 return 0;
713 case TCG_COND_GEU:
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700714 case TCG_COND_TSTEQ:
Aurelien Jarnob336ceb2012-09-18 19:37:00 +0200715 return 1;
716 default:
Richard Henderson8d57bf12021-08-24 08:34:27 -0700717 return -1;
Aurelien Jarnob336ceb2012-09-18 19:37:00 +0200718 }
Aurelien Jarnof8dd19e2012-09-06 16:47:14 +0200719 }
Richard Henderson8d57bf12021-08-24 08:34:27 -0700720 return -1;
Aurelien Jarnof8dd19e2012-09-06 16:47:14 +0200721}
722
Richard Henderson7a2f7082021-08-26 07:06:39 -0700723/**
724 * swap_commutative:
725 * @dest: TCGArg of the destination argument, or NO_DEST.
726 * @p1: first paired argument
727 * @p2: second paired argument
728 *
729 * If *@p1 is a constant and *@p2 is not, swap.
730 * If *@p2 matches @dest, swap.
731 * Return true if a swap was performed.
732 */
733
734#define NO_DEST temp_arg(NULL)
735
Richard Henderson24c9ae42012-10-02 11:32:21 -0700736static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2)
737{
738 TCGArg a1 = *p1, a2 = *p2;
739 int sum = 0;
Richard Henderson63490392017-06-20 13:43:15 -0700740 sum += arg_is_const(a1);
741 sum -= arg_is_const(a2);
Richard Henderson24c9ae42012-10-02 11:32:21 -0700742
743 /* Prefer the constant in second argument, and then the form
744 op a, a, b, which is better handled on non-RISC hosts. */
745 if (sum > 0 || (sum == 0 && dest == a2)) {
746 *p1 = a2;
747 *p2 = a1;
748 return true;
749 }
750 return false;
751}
752
Richard Henderson0bfcb862012-10-02 11:32:23 -0700753static bool swap_commutative2(TCGArg *p1, TCGArg *p2)
754{
755 int sum = 0;
Richard Henderson63490392017-06-20 13:43:15 -0700756 sum += arg_is_const(p1[0]);
757 sum += arg_is_const(p1[1]);
758 sum -= arg_is_const(p2[0]);
759 sum -= arg_is_const(p2[1]);
Richard Henderson0bfcb862012-10-02 11:32:23 -0700760 if (sum > 0) {
761 TCGArg t;
762 t = p1[0], p1[0] = p2[0], p2[0] = t;
763 t = p1[1], p1[1] = p2[1], p2[1] = t;
764 return true;
765 }
766 return false;
767}
768
Richard Henderson7e64b112023-10-24 16:53:56 -0700769/*
770 * Return -1 if the condition can't be simplified,
771 * and the result of the condition (0 or 1) if it can.
772 */
Richard Hendersonfb04ab72024-01-10 18:21:58 +1100773static int do_constant_folding_cond1(OptContext *ctx, TCGOp *op, TCGArg dest,
Richard Henderson246c4b72023-10-24 16:36:50 -0700774 TCGArg *p1, TCGArg *p2, TCGArg *pcond)
775{
776 TCGCond cond;
Paolo Bonzini35020622024-01-22 10:48:11 +0100777 TempOptInfo *i1;
Richard Henderson246c4b72023-10-24 16:36:50 -0700778 bool swap;
779 int r;
780
781 swap = swap_commutative(dest, p1, p2);
782 cond = *pcond;
783 if (swap) {
784 *pcond = cond = tcg_swap_cond(cond);
785 }
786
787 r = do_constant_folding_cond(ctx->type, *p1, *p2, cond);
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700788 if (r >= 0) {
789 return r;
790 }
791 if (!is_tst_cond(cond)) {
792 return -1;
793 }
794
Paolo Bonzini35020622024-01-22 10:48:11 +0100795 i1 = arg_info(*p1);
796
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700797 /*
798 * TSTNE x,x -> NE x,0
Paolo Bonzini35020622024-01-22 10:48:11 +0100799 * TSTNE x,i -> NE x,0 if i includes all nonzero bits of x
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700800 */
Paolo Bonzini35020622024-01-22 10:48:11 +0100801 if (args_are_copies(*p1, *p2) ||
802 (arg_is_const(*p2) && (i1->z_mask & ~arg_info(*p2)->val) == 0)) {
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700803 *p2 = arg_new_constant(ctx, 0);
804 *pcond = tcg_tst_eqne_cond(cond);
805 return -1;
806 }
807
Paolo Bonzini35020622024-01-22 10:48:11 +0100808 /* TSTNE x,i -> LT x,0 if i only includes sign bit copies */
809 if (arg_is_const(*p2) && (arg_info(*p2)->val & ~i1->s_mask) == 0) {
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700810 *p2 = arg_new_constant(ctx, 0);
811 *pcond = tcg_tst_ltge_cond(cond);
Richard Hendersonfb04ab72024-01-10 18:21:58 +1100812 return -1;
813 }
814
815 /* Expand to AND with a temporary if no backend support. */
816 if (!TCG_TARGET_HAS_tst) {
Richard Hendersonc3b920b2025-01-06 10:32:44 -0800817 TCGOp *op2 = opt_insert_before(ctx, op, INDEX_op_and, 3);
Richard Hendersonfb04ab72024-01-10 18:21:58 +1100818 TCGArg tmp = arg_new_temp(ctx);
819
820 op2->args[0] = tmp;
821 op2->args[1] = *p1;
822 op2->args[2] = *p2;
823
824 *p1 = tmp;
825 *p2 = arg_new_constant(ctx, 0);
826 *pcond = tcg_tst_eqne_cond(cond);
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700827 }
828 return -1;
Richard Henderson246c4b72023-10-24 16:36:50 -0700829}
830
Richard Hendersonfb04ab72024-01-10 18:21:58 +1100831static int do_constant_folding_cond2(OptContext *ctx, TCGOp *op, TCGArg *args)
Richard Henderson7e64b112023-10-24 16:53:56 -0700832{
833 TCGArg al, ah, bl, bh;
834 TCGCond c;
835 bool swap;
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700836 int r;
Richard Henderson7e64b112023-10-24 16:53:56 -0700837
838 swap = swap_commutative2(args, args + 2);
839 c = args[4];
840 if (swap) {
841 args[4] = c = tcg_swap_cond(c);
842 }
843
844 al = args[0];
845 ah = args[1];
846 bl = args[2];
847 bh = args[3];
848
849 if (arg_is_const(bl) && arg_is_const(bh)) {
850 tcg_target_ulong blv = arg_info(bl)->val;
851 tcg_target_ulong bhv = arg_info(bh)->val;
852 uint64_t b = deposit64(blv, 32, 32, bhv);
853
854 if (arg_is_const(al) && arg_is_const(ah)) {
855 tcg_target_ulong alv = arg_info(al)->val;
856 tcg_target_ulong ahv = arg_info(ah)->val;
857 uint64_t a = deposit64(alv, 32, 32, ahv);
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700858
859 r = do_constant_folding_cond_64(a, b, c);
860 if (r >= 0) {
861 return r;
862 }
Richard Henderson7e64b112023-10-24 16:53:56 -0700863 }
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700864
Richard Henderson7e64b112023-10-24 16:53:56 -0700865 if (b == 0) {
866 switch (c) {
867 case TCG_COND_LTU:
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700868 case TCG_COND_TSTNE:
Richard Henderson7e64b112023-10-24 16:53:56 -0700869 return 0;
870 case TCG_COND_GEU:
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700871 case TCG_COND_TSTEQ:
Richard Henderson7e64b112023-10-24 16:53:56 -0700872 return 1;
873 default:
874 break;
875 }
876 }
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700877
878 /* TSTNE x,-1 -> NE x,0 */
879 if (b == -1 && is_tst_cond(c)) {
880 args[3] = args[2] = arg_new_constant(ctx, 0);
881 args[4] = tcg_tst_eqne_cond(c);
882 return -1;
883 }
884
885 /* TSTNE x,sign -> LT x,0 */
886 if (b == INT64_MIN && is_tst_cond(c)) {
887 /* bl must be 0, so copy that to bh */
888 args[3] = bl;
889 args[4] = tcg_tst_ltge_cond(c);
890 return -1;
891 }
Richard Henderson7e64b112023-10-24 16:53:56 -0700892 }
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700893
Richard Henderson7e64b112023-10-24 16:53:56 -0700894 if (args_are_copies(al, bl) && args_are_copies(ah, bh)) {
Richard Hendersonceb9ee02023-10-23 23:44:27 -0700895 r = do_constant_folding_cond_eq(c);
896 if (r >= 0) {
897 return r;
898 }
899
900 /* TSTNE x,x -> NE x,0 */
901 if (is_tst_cond(c)) {
902 args[3] = args[2] = arg_new_constant(ctx, 0);
903 args[4] = tcg_tst_eqne_cond(c);
904 return -1;
905 }
Richard Henderson7e64b112023-10-24 16:53:56 -0700906 }
Richard Hendersonfb04ab72024-01-10 18:21:58 +1100907
908 /* Expand to AND with a temporary if no backend support. */
909 if (!TCG_TARGET_HAS_tst && is_tst_cond(c)) {
Richard Hendersonc3b920b2025-01-06 10:32:44 -0800910 TCGOp *op1 = opt_insert_before(ctx, op, INDEX_op_and, 3);
911 TCGOp *op2 = opt_insert_before(ctx, op, INDEX_op_and, 3);
Richard Hendersonfb04ab72024-01-10 18:21:58 +1100912 TCGArg t1 = arg_new_temp(ctx);
913 TCGArg t2 = arg_new_temp(ctx);
914
915 op1->args[0] = t1;
916 op1->args[1] = al;
917 op1->args[2] = bl;
918 op2->args[0] = t2;
919 op2->args[1] = ah;
920 op2->args[2] = bh;
921
922 args[0] = t1;
923 args[1] = t2;
924 args[3] = args[2] = arg_new_constant(ctx, 0);
925 args[4] = tcg_tst_eqne_cond(c);
926 }
Richard Henderson7e64b112023-10-24 16:53:56 -0700927 return -1;
928}
929
Richard Hendersone2577ea2021-08-24 08:00:48 -0700930static void init_arguments(OptContext *ctx, TCGOp *op, int nb_args)
931{
932 for (int i = 0; i < nb_args; i++) {
933 TCGTemp *ts = arg_temp(op->args[i]);
Richard Henderson39004a72022-11-11 10:09:37 +1000934 init_ts_info(ctx, ts);
Richard Hendersone2577ea2021-08-24 08:00:48 -0700935 }
936}
937
Richard Henderson8774dde2021-08-24 08:04:47 -0700938static void copy_propagate(OptContext *ctx, TCGOp *op,
939 int nb_oargs, int nb_iargs)
940{
Richard Henderson8774dde2021-08-24 08:04:47 -0700941 for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
942 TCGTemp *ts = arg_temp(op->args[i]);
Richard Henderson39004a72022-11-11 10:09:37 +1000943 if (ts_is_copy(ts)) {
Richard Henderson9f75e522023-11-02 13:37:46 -0700944 op->args[i] = temp_arg(find_better_copy(ts));
Richard Henderson8774dde2021-08-24 08:04:47 -0700945 }
946 }
947}
948
Richard Henderson15268552024-12-08 07:45:11 -0600949static void finish_bb(OptContext *ctx)
950{
951 /* We only optimize memory barriers across basic blocks. */
952 ctx->prev_mb = NULL;
953}
954
955static void finish_ebb(OptContext *ctx)
956{
957 finish_bb(ctx);
958 /* We only optimize across extended basic blocks. */
959 memset(&ctx->temps_used, 0, sizeof(ctx->temps_used));
960 remove_mem_copy_all(ctx);
961}
962
Richard Hendersonf3ed3cf2024-12-08 18:39:47 -0600963static bool finish_folding(OptContext *ctx, TCGOp *op)
Richard Henderson137f1f42021-08-24 08:49:25 -0700964{
965 const TCGOpDef *def = &tcg_op_defs[op->opc];
966 int i, nb_oargs;
967
Richard Henderson137f1f42021-08-24 08:49:25 -0700968 nb_oargs = def->nb_oargs;
969 for (i = 0; i < nb_oargs; i++) {
Richard Henderson57fe5c62021-08-26 12:04:46 -0700970 TCGTemp *ts = arg_temp(op->args[i]);
Richard Henderson986cac12023-01-09 13:59:35 -0800971 reset_ts(ctx, ts);
Richard Henderson137f1f42021-08-24 08:49:25 -0700972 }
Richard Hendersonf3ed3cf2024-12-08 18:39:47 -0600973 return true;
Richard Henderson137f1f42021-08-24 08:49:25 -0700974}
975
Richard Henderson2f9f08b2021-08-25 12:03:48 -0700976/*
977 * The fold_* functions return true when processing is complete,
978 * usually by folding the operation to a constant or to a copy,
979 * and calling tcg_opt_gen_{mov,movi}. They may do other things,
980 * like collect information about the value produced, for use in
981 * optimizing a subsequent operation.
982 *
983 * These first fold_* functions are all helpers, used by other
984 * folders for more specific operations.
985 */
986
987static bool fold_const1(OptContext *ctx, TCGOp *op)
988{
989 if (arg_is_const(op->args[1])) {
990 uint64_t t;
991
992 t = arg_info(op->args[1])->val;
Richard Henderson67f84c92021-08-25 08:00:20 -0700993 t = do_constant_folding(op->opc, ctx->type, t, 0);
Richard Henderson2f9f08b2021-08-25 12:03:48 -0700994 return tcg_opt_gen_movi(ctx, op, op->args[0], t);
995 }
996 return false;
997}
998
999static bool fold_const2(OptContext *ctx, TCGOp *op)
1000{
1001 if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
1002 uint64_t t1 = arg_info(op->args[1])->val;
1003 uint64_t t2 = arg_info(op->args[2])->val;
1004
Richard Henderson67f84c92021-08-25 08:00:20 -07001005 t1 = do_constant_folding(op->opc, ctx->type, t1, t2);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001006 return tcg_opt_gen_movi(ctx, op, op->args[0], t1);
1007 }
1008 return false;
1009}
1010
Richard Hendersonc578ff12021-12-16 06:07:25 -08001011static bool fold_commutative(OptContext *ctx, TCGOp *op)
1012{
1013 swap_commutative(op->args[0], &op->args[1], &op->args[2]);
1014 return false;
1015}
1016
Richard Henderson7a2f7082021-08-26 07:06:39 -07001017static bool fold_const2_commutative(OptContext *ctx, TCGOp *op)
1018{
1019 swap_commutative(op->args[0], &op->args[1], &op->args[2]);
1020 return fold_const2(ctx, op);
1021}
1022
Richard Hendersond582b142024-12-19 10:43:26 -08001023/*
1024 * Record "zero" and "sign" masks for the single output of @op.
1025 * See TempOptInfo definition of z_mask and s_mask.
1026 * If z_mask allows, fold the output to constant zero.
Richard Henderson75c3bf32024-12-19 10:50:40 -08001027 * The passed s_mask may be augmented by z_mask.
Richard Hendersond582b142024-12-19 10:43:26 -08001028 */
1029static bool fold_masks_zs(OptContext *ctx, TCGOp *op,
Richard Henderson6d70ddc2024-12-21 21:08:10 -08001030 uint64_t z_mask, int64_t s_mask)
Richard Hendersonfae450b2021-08-25 22:42:19 -07001031{
Richard Henderson56e06ec2024-12-08 18:26:48 -06001032 const TCGOpDef *def = &tcg_op_defs[op->opc];
1033 TCGTemp *ts;
1034 TempOptInfo *ti;
Richard Henderson6d70ddc2024-12-21 21:08:10 -08001035 int rep;
Richard Henderson56e06ec2024-12-08 18:26:48 -06001036
1037 /* Only single-output opcodes are supported here. */
1038 tcg_debug_assert(def->nb_oargs == 1);
Richard Hendersonfae450b2021-08-25 22:42:19 -07001039
1040 /*
Richard Hendersonfaa2e102021-08-26 09:03:59 -07001041 * 32-bit ops generate 32-bit results, which for the purpose of
1042 * simplifying tcg are sign-extended. Certainly that's how we
1043 * represent our constants elsewhere. Note that the bits will
1044 * be reset properly for a 64-bit value when encountering the
1045 * type changing opcodes.
Richard Hendersonfae450b2021-08-25 22:42:19 -07001046 */
1047 if (ctx->type == TCG_TYPE_I32) {
Richard Hendersonfaa2e102021-08-26 09:03:59 -07001048 z_mask = (int32_t)z_mask;
Richard Henderson6d70ddc2024-12-21 21:08:10 -08001049 s_mask |= INT32_MIN;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001050 }
1051
1052 if (z_mask == 0) {
1053 return tcg_opt_gen_movi(ctx, op, op->args[0], 0);
1054 }
Richard Henderson56e06ec2024-12-08 18:26:48 -06001055
1056 ts = arg_temp(op->args[0]);
1057 reset_ts(ctx, ts);
1058
1059 ti = ts_info(ts);
1060 ti->z_mask = z_mask;
Richard Henderson6d70ddc2024-12-21 21:08:10 -08001061
1062 /* Canonicalize s_mask and incorporate data from z_mask. */
1063 rep = clz64(~s_mask);
1064 rep = MAX(rep, clz64(z_mask));
1065 rep = MAX(rep - 1, 0);
1066 ti->s_mask = INT64_MIN >> rep;
1067
Richard Henderson56e06ec2024-12-08 18:26:48 -06001068 return true;
Richard Henderson045ace32024-12-19 10:33:51 -08001069}
1070
Richard Henderson81be07f2024-12-08 19:49:17 -06001071static bool fold_masks_z(OptContext *ctx, TCGOp *op, uint64_t z_mask)
1072{
1073 return fold_masks_zs(ctx, op, z_mask, 0);
1074}
1075
Richard Hendersonef6be622024-12-08 20:03:15 -06001076static bool fold_masks_s(OptContext *ctx, TCGOp *op, uint64_t s_mask)
1077{
1078 return fold_masks_zs(ctx, op, -1, s_mask);
1079}
1080
Richard Henderson045ace32024-12-19 10:33:51 -08001081/*
1082 * An "affected" mask bit is 0 if and only if the result is identical
1083 * to the first input. Thus if the entire mask is 0, the operation
1084 * is equivalent to a copy.
1085 */
1086static bool fold_affected_mask(OptContext *ctx, TCGOp *op, uint64_t a_mask)
1087{
1088 if (ctx->type == TCG_TYPE_I32) {
1089 a_mask = (uint32_t)a_mask;
1090 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07001091 if (a_mask == 0) {
1092 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
1093 }
1094 return false;
1095}
1096
Richard Henderson0e0a32b2021-08-24 13:18:01 -07001097/*
1098 * Convert @op to NOT, if NOT is supported by the host.
1099 * Return true f the conversion is successful, which will still
1100 * indicate that the processing is complete.
1101 */
1102static bool fold_not(OptContext *ctx, TCGOp *op);
1103static bool fold_to_not(OptContext *ctx, TCGOp *op, int idx)
1104{
1105 TCGOpcode not_op;
1106 bool have_not;
1107
1108 switch (ctx->type) {
1109 case TCG_TYPE_I32:
Richard Henderson0e0a32b2021-08-24 13:18:01 -07001110 case TCG_TYPE_I64:
Richard Henderson5c62d372025-01-06 23:46:47 -08001111 not_op = INDEX_op_not;
1112 have_not = tcg_op_supported(INDEX_op_not, ctx->type, 0);
Richard Henderson0e0a32b2021-08-24 13:18:01 -07001113 break;
1114 case TCG_TYPE_V64:
1115 case TCG_TYPE_V128:
1116 case TCG_TYPE_V256:
1117 not_op = INDEX_op_not_vec;
1118 have_not = TCG_TARGET_HAS_not_vec;
1119 break;
1120 default:
1121 g_assert_not_reached();
1122 }
1123 if (have_not) {
1124 op->opc = not_op;
1125 op->args[1] = op->args[idx];
1126 return fold_not(ctx, op);
1127 }
1128 return false;
1129}
1130
Richard Hendersonda48e272021-08-25 20:42:04 -07001131/* If the binary operation has first argument @i, fold to @i. */
1132static bool fold_ix_to_i(OptContext *ctx, TCGOp *op, uint64_t i)
1133{
Richard Henderson27cdb852023-10-23 11:38:00 -07001134 if (arg_is_const_val(op->args[1], i)) {
Richard Hendersonda48e272021-08-25 20:42:04 -07001135 return tcg_opt_gen_movi(ctx, op, op->args[0], i);
1136 }
1137 return false;
1138}
1139
Richard Henderson0e0a32b2021-08-24 13:18:01 -07001140/* If the binary operation has first argument @i, fold to NOT. */
1141static bool fold_ix_to_not(OptContext *ctx, TCGOp *op, uint64_t i)
1142{
Richard Henderson27cdb852023-10-23 11:38:00 -07001143 if (arg_is_const_val(op->args[1], i)) {
Richard Henderson0e0a32b2021-08-24 13:18:01 -07001144 return fold_to_not(ctx, op, 2);
1145 }
1146 return false;
1147}
1148
Richard Hendersone8679952021-08-25 13:19:52 -07001149/* If the binary operation has second argument @i, fold to @i. */
1150static bool fold_xi_to_i(OptContext *ctx, TCGOp *op, uint64_t i)
1151{
Richard Henderson27cdb852023-10-23 11:38:00 -07001152 if (arg_is_const_val(op->args[2], i)) {
Richard Hendersone8679952021-08-25 13:19:52 -07001153 return tcg_opt_gen_movi(ctx, op, op->args[0], i);
1154 }
1155 return false;
1156}
1157
Richard Hendersona63ce0e2021-08-25 20:28:53 -07001158/* If the binary operation has second argument @i, fold to identity. */
1159static bool fold_xi_to_x(OptContext *ctx, TCGOp *op, uint64_t i)
1160{
Richard Henderson27cdb852023-10-23 11:38:00 -07001161 if (arg_is_const_val(op->args[2], i)) {
Richard Hendersona63ce0e2021-08-25 20:28:53 -07001162 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
1163 }
1164 return false;
1165}
1166
Richard Henderson0e0a32b2021-08-24 13:18:01 -07001167/* If the binary operation has second argument @i, fold to NOT. */
1168static bool fold_xi_to_not(OptContext *ctx, TCGOp *op, uint64_t i)
1169{
Richard Henderson27cdb852023-10-23 11:38:00 -07001170 if (arg_is_const_val(op->args[2], i)) {
Richard Henderson0e0a32b2021-08-24 13:18:01 -07001171 return fold_to_not(ctx, op, 1);
1172 }
1173 return false;
1174}
1175
Richard Hendersoncbe42fb2021-08-25 13:02:00 -07001176/* If the binary operation has both arguments equal, fold to @i. */
1177static bool fold_xx_to_i(OptContext *ctx, TCGOp *op, uint64_t i)
1178{
1179 if (args_are_copies(op->args[1], op->args[2])) {
1180 return tcg_opt_gen_movi(ctx, op, op->args[0], i);
1181 }
1182 return false;
1183}
1184
Richard Hendersonca7bb042021-08-25 13:14:21 -07001185/* If the binary operation has both arguments equal, fold to identity. */
1186static bool fold_xx_to_x(OptContext *ctx, TCGOp *op)
1187{
1188 if (args_are_copies(op->args[1], op->args[2])) {
1189 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
1190 }
1191 return false;
1192}
1193
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001194/*
1195 * These outermost fold_<op> functions are sorted alphabetically.
Richard Hendersonca7bb042021-08-25 13:14:21 -07001196 *
1197 * The ordering of the transformations should be:
1198 * 1) those that produce a constant
1199 * 2) those that produce a copy
1200 * 3) those that produce information about the result value.
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001201 */
1202
Richard Henderson7d3c63a2024-12-09 14:06:08 -06001203static bool fold_or(OptContext *ctx, TCGOp *op);
1204static bool fold_orc(OptContext *ctx, TCGOp *op);
1205static bool fold_xor(OptContext *ctx, TCGOp *op);
1206
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001207static bool fold_add(OptContext *ctx, TCGOp *op)
1208{
Richard Henderson7a2f7082021-08-26 07:06:39 -07001209 if (fold_const2_commutative(ctx, op) ||
Richard Hendersona63ce0e2021-08-25 20:28:53 -07001210 fold_xi_to_x(ctx, op, 0)) {
1211 return true;
1212 }
Richard Hendersonf3ed3cf2024-12-08 18:39:47 -06001213 return finish_folding(ctx, op);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001214}
1215
Richard Hendersonc578ff12021-12-16 06:07:25 -08001216/* We cannot as yet do_constant_folding with vectors. */
1217static bool fold_add_vec(OptContext *ctx, TCGOp *op)
1218{
1219 if (fold_commutative(ctx, op) ||
1220 fold_xi_to_x(ctx, op, 0)) {
1221 return true;
1222 }
Richard Hendersonf3ed3cf2024-12-08 18:39:47 -06001223 return finish_folding(ctx, op);
Richard Hendersonc578ff12021-12-16 06:07:25 -08001224}
1225
Richard Henderson9531c072021-08-26 06:51:39 -07001226static bool fold_addsub2(OptContext *ctx, TCGOp *op, bool add)
Richard Hendersone3f7dc22021-08-24 10:30:38 -07001227{
Richard Hendersonf2457572023-10-25 18:39:44 -07001228 bool a_const = arg_is_const(op->args[2]) && arg_is_const(op->args[3]);
1229 bool b_const = arg_is_const(op->args[4]) && arg_is_const(op->args[5]);
1230
1231 if (a_const && b_const) {
Richard Henderson9531c072021-08-26 06:51:39 -07001232 uint64_t al = arg_info(op->args[2])->val;
1233 uint64_t ah = arg_info(op->args[3])->val;
1234 uint64_t bl = arg_info(op->args[4])->val;
1235 uint64_t bh = arg_info(op->args[5])->val;
Richard Hendersone3f7dc22021-08-24 10:30:38 -07001236 TCGArg rl, rh;
Richard Henderson9531c072021-08-26 06:51:39 -07001237 TCGOp *op2;
Richard Hendersone3f7dc22021-08-24 10:30:38 -07001238
Richard Henderson9531c072021-08-26 06:51:39 -07001239 if (ctx->type == TCG_TYPE_I32) {
1240 uint64_t a = deposit64(al, 32, 32, ah);
1241 uint64_t b = deposit64(bl, 32, 32, bh);
1242
1243 if (add) {
1244 a += b;
1245 } else {
1246 a -= b;
1247 }
1248
1249 al = sextract64(a, 0, 32);
1250 ah = sextract64(a, 32, 32);
Richard Hendersone3f7dc22021-08-24 10:30:38 -07001251 } else {
Richard Henderson9531c072021-08-26 06:51:39 -07001252 Int128 a = int128_make128(al, ah);
1253 Int128 b = int128_make128(bl, bh);
1254
1255 if (add) {
1256 a = int128_add(a, b);
1257 } else {
1258 a = int128_sub(a, b);
1259 }
1260
1261 al = int128_getlo(a);
1262 ah = int128_gethi(a);
Richard Hendersone3f7dc22021-08-24 10:30:38 -07001263 }
1264
1265 rl = op->args[0];
1266 rh = op->args[1];
Richard Henderson9531c072021-08-26 06:51:39 -07001267
1268 /* The proper opcode is supplied by tcg_opt_gen_mov. */
Richard Hendersona3c1c572025-04-21 11:05:29 -07001269 op2 = opt_insert_before(ctx, op, 0, 2);
Richard Henderson9531c072021-08-26 06:51:39 -07001270
1271 tcg_opt_gen_movi(ctx, op, rl, al);
1272 tcg_opt_gen_movi(ctx, op2, rh, ah);
Richard Hendersone3f7dc22021-08-24 10:30:38 -07001273 return true;
1274 }
Richard Hendersonf2457572023-10-25 18:39:44 -07001275
1276 /* Fold sub2 r,x,i to add2 r,x,-i */
1277 if (!add && b_const) {
1278 uint64_t bl = arg_info(op->args[4])->val;
1279 uint64_t bh = arg_info(op->args[5])->val;
1280
1281 /* Negate the two parts without assembling and disassembling. */
1282 bl = -bl;
1283 bh = ~bh + !bl;
1284
1285 op->opc = (ctx->type == TCG_TYPE_I32
1286 ? INDEX_op_add2_i32 : INDEX_op_add2_i64);
1287 op->args[4] = arg_new_constant(ctx, bl);
1288 op->args[5] = arg_new_constant(ctx, bh);
1289 }
Richard Hendersonf3ed3cf2024-12-08 18:39:47 -06001290 return finish_folding(ctx, op);
Richard Hendersone3f7dc22021-08-24 10:30:38 -07001291}
1292
Richard Henderson9531c072021-08-26 06:51:39 -07001293static bool fold_add2(OptContext *ctx, TCGOp *op)
Richard Hendersone3f7dc22021-08-24 10:30:38 -07001294{
Richard Henderson7a2f7082021-08-26 07:06:39 -07001295 /* Note that the high and low parts may be independently swapped. */
1296 swap_commutative(op->args[0], &op->args[2], &op->args[4]);
1297 swap_commutative(op->args[1], &op->args[3], &op->args[5]);
1298
Richard Henderson9531c072021-08-26 06:51:39 -07001299 return fold_addsub2(ctx, op, true);
Richard Hendersone3f7dc22021-08-24 10:30:38 -07001300}
1301
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001302static bool fold_and(OptContext *ctx, TCGOp *op)
1303{
Richard Henderson1ca73722024-12-08 18:47:15 -06001304 uint64_t z1, z2, z_mask, s_mask;
1305 TempOptInfo *t1, *t2;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001306
Richard Henderson7a2f7082021-08-26 07:06:39 -07001307 if (fold_const2_commutative(ctx, op) ||
Richard Hendersone8679952021-08-25 13:19:52 -07001308 fold_xi_to_i(ctx, op, 0) ||
Richard Hendersona63ce0e2021-08-25 20:28:53 -07001309 fold_xi_to_x(ctx, op, -1) ||
Richard Hendersonca7bb042021-08-25 13:14:21 -07001310 fold_xx_to_x(ctx, op)) {
1311 return true;
1312 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07001313
Richard Henderson1ca73722024-12-08 18:47:15 -06001314 t1 = arg_info(op->args[1]);
1315 t2 = arg_info(op->args[2]);
1316 z1 = t1->z_mask;
1317 z2 = t2->z_mask;
Richard Henderson3f2b1f82021-08-26 13:08:54 -07001318
1319 /*
Richard Hendersonfae450b2021-08-25 22:42:19 -07001320 * Known-zeros does not imply known-ones. Therefore unless
1321 * arg2 is constant, we can't infer affected bits from it.
1322 */
Richard Henderson1ca73722024-12-08 18:47:15 -06001323 if (ti_is_const(t2) && fold_affected_mask(ctx, op, z1 & ~z2)) {
Richard Henderson045ace32024-12-19 10:33:51 -08001324 return true;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001325 }
1326
Richard Henderson1ca73722024-12-08 18:47:15 -06001327 z_mask = z1 & z2;
1328
1329 /*
1330 * Sign repetitions are perforce all identical, whether they are 1 or 0.
1331 * Bitwise operations preserve the relative quantity of the repetitions.
1332 */
1333 s_mask = t1->s_mask & t2->s_mask;
1334
1335 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001336}
1337
1338static bool fold_andc(OptContext *ctx, TCGOp *op)
1339{
Richard Henderson21e2b5f2024-12-08 18:56:55 -06001340 uint64_t z_mask, s_mask;
1341 TempOptInfo *t1, *t2;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001342
Richard Hendersoncbe42fb2021-08-25 13:02:00 -07001343 if (fold_const2(ctx, op) ||
Richard Henderson0e0a32b2021-08-24 13:18:01 -07001344 fold_xx_to_i(ctx, op, 0) ||
Richard Hendersona63ce0e2021-08-25 20:28:53 -07001345 fold_xi_to_x(ctx, op, 0) ||
Richard Henderson0e0a32b2021-08-24 13:18:01 -07001346 fold_ix_to_not(ctx, op, -1)) {
Richard Hendersoncbe42fb2021-08-25 13:02:00 -07001347 return true;
1348 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07001349
Richard Henderson21e2b5f2024-12-08 18:56:55 -06001350 t1 = arg_info(op->args[1]);
1351 t2 = arg_info(op->args[2]);
1352 z_mask = t1->z_mask;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001353
Richard Henderson899281c2023-11-15 11:18:55 -08001354 if (ti_is_const(t2)) {
1355 /* Fold andc r,x,i to and r,x,~i. */
1356 switch (ctx->type) {
1357 case TCG_TYPE_I32:
1358 case TCG_TYPE_I64:
1359 op->opc = INDEX_op_and;
1360 break;
1361 case TCG_TYPE_V64:
1362 case TCG_TYPE_V128:
1363 case TCG_TYPE_V256:
1364 op->opc = INDEX_op_and_vec;
1365 break;
1366 default:
1367 g_assert_not_reached();
1368 }
1369 op->args[2] = arg_new_constant(ctx, ~ti_const_val(t2));
1370 return fold_and(ctx, op);
1371 }
1372
Richard Hendersonfae450b2021-08-25 22:42:19 -07001373 /*
1374 * Known-zeros does not imply known-ones. Therefore unless
1375 * arg2 is constant, we can't infer anything from it.
1376 */
Richard Henderson21e2b5f2024-12-08 18:56:55 -06001377 if (ti_is_const(t2)) {
1378 uint64_t v2 = ti_const_val(t2);
1379 if (fold_affected_mask(ctx, op, z_mask & v2)) {
Richard Henderson045ace32024-12-19 10:33:51 -08001380 return true;
1381 }
Richard Henderson21e2b5f2024-12-08 18:56:55 -06001382 z_mask &= ~v2;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001383 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07001384
Richard Henderson21e2b5f2024-12-08 18:56:55 -06001385 s_mask = t1->s_mask & t2->s_mask;
1386 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001387}
1388
Richard Henderson7d3c63a2024-12-09 14:06:08 -06001389static bool fold_bitsel_vec(OptContext *ctx, TCGOp *op)
1390{
1391 /* If true and false values are the same, eliminate the cmp. */
1392 if (args_are_copies(op->args[2], op->args[3])) {
1393 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[2]);
1394 }
1395
1396 if (arg_is_const(op->args[2]) && arg_is_const(op->args[3])) {
1397 uint64_t tv = arg_info(op->args[2])->val;
1398 uint64_t fv = arg_info(op->args[3])->val;
1399
1400 if (tv == -1 && fv == 0) {
1401 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
1402 }
1403 if (tv == 0 && fv == -1) {
1404 if (TCG_TARGET_HAS_not_vec) {
1405 op->opc = INDEX_op_not_vec;
1406 return fold_not(ctx, op);
1407 } else {
1408 op->opc = INDEX_op_xor_vec;
1409 op->args[2] = arg_new_constant(ctx, -1);
1410 return fold_xor(ctx, op);
1411 }
1412 }
1413 }
1414 if (arg_is_const(op->args[2])) {
1415 uint64_t tv = arg_info(op->args[2])->val;
1416 if (tv == -1) {
1417 op->opc = INDEX_op_or_vec;
1418 op->args[2] = op->args[3];
1419 return fold_or(ctx, op);
1420 }
1421 if (tv == 0 && TCG_TARGET_HAS_andc_vec) {
1422 op->opc = INDEX_op_andc_vec;
1423 op->args[2] = op->args[1];
1424 op->args[1] = op->args[3];
1425 return fold_andc(ctx, op);
1426 }
1427 }
1428 if (arg_is_const(op->args[3])) {
1429 uint64_t fv = arg_info(op->args[3])->val;
1430 if (fv == 0) {
1431 op->opc = INDEX_op_and_vec;
1432 return fold_and(ctx, op);
1433 }
1434 if (fv == -1 && TCG_TARGET_HAS_orc_vec) {
1435 op->opc = INDEX_op_orc_vec;
1436 op->args[2] = op->args[1];
1437 op->args[1] = op->args[3];
1438 return fold_orc(ctx, op);
1439 }
1440 }
1441 return finish_folding(ctx, op);
1442}
1443
Richard Henderson079b0802021-08-24 09:30:59 -07001444static bool fold_brcond(OptContext *ctx, TCGOp *op)
1445{
Richard Hendersonfb04ab72024-01-10 18:21:58 +11001446 int i = do_constant_folding_cond1(ctx, op, NO_DEST, &op->args[0],
Richard Henderson246c4b72023-10-24 16:36:50 -07001447 &op->args[1], &op->args[2]);
Richard Henderson079b0802021-08-24 09:30:59 -07001448 if (i == 0) {
1449 tcg_op_remove(ctx->tcg, op);
1450 return true;
1451 }
1452 if (i > 0) {
1453 op->opc = INDEX_op_br;
1454 op->args[0] = op->args[3];
Richard Henderson15268552024-12-08 07:45:11 -06001455 finish_ebb(ctx);
1456 } else {
1457 finish_bb(ctx);
Richard Henderson079b0802021-08-24 09:30:59 -07001458 }
Richard Henderson15268552024-12-08 07:45:11 -06001459 return true;
Richard Henderson079b0802021-08-24 09:30:59 -07001460}
1461
Richard Henderson764d2ab2021-08-24 09:22:11 -07001462static bool fold_brcond2(OptContext *ctx, TCGOp *op)
1463{
Richard Henderson7e64b112023-10-24 16:53:56 -07001464 TCGCond cond;
1465 TCGArg label;
Richard Henderson7a2f7082021-08-26 07:06:39 -07001466 int i, inv = 0;
Richard Henderson764d2ab2021-08-24 09:22:11 -07001467
Richard Hendersonfb04ab72024-01-10 18:21:58 +11001468 i = do_constant_folding_cond2(ctx, op, &op->args[0]);
Richard Henderson7e64b112023-10-24 16:53:56 -07001469 cond = op->args[4];
1470 label = op->args[5];
Richard Henderson764d2ab2021-08-24 09:22:11 -07001471 if (i >= 0) {
1472 goto do_brcond_const;
1473 }
1474
1475 switch (cond) {
1476 case TCG_COND_LT:
1477 case TCG_COND_GE:
1478 /*
1479 * Simplify LT/GE comparisons vs zero to a single compare
1480 * vs the high word of the input.
1481 */
Richard Henderson27cdb852023-10-23 11:38:00 -07001482 if (arg_is_const_val(op->args[2], 0) &&
1483 arg_is_const_val(op->args[3], 0)) {
Richard Henderson764d2ab2021-08-24 09:22:11 -07001484 goto do_brcond_high;
1485 }
1486 break;
1487
1488 case TCG_COND_NE:
1489 inv = 1;
1490 QEMU_FALLTHROUGH;
1491 case TCG_COND_EQ:
1492 /*
1493 * Simplify EQ/NE comparisons where one of the pairs
1494 * can be simplified.
1495 */
Richard Henderson67f84c92021-08-25 08:00:20 -07001496 i = do_constant_folding_cond(TCG_TYPE_I32, op->args[0],
Richard Henderson764d2ab2021-08-24 09:22:11 -07001497 op->args[2], cond);
1498 switch (i ^ inv) {
1499 case 0:
1500 goto do_brcond_const;
1501 case 1:
1502 goto do_brcond_high;
1503 }
1504
Richard Henderson67f84c92021-08-25 08:00:20 -07001505 i = do_constant_folding_cond(TCG_TYPE_I32, op->args[1],
Richard Henderson764d2ab2021-08-24 09:22:11 -07001506 op->args[3], cond);
1507 switch (i ^ inv) {
1508 case 0:
1509 goto do_brcond_const;
1510 case 1:
Richard Hendersonceb9ee02023-10-23 23:44:27 -07001511 goto do_brcond_low;
1512 }
1513 break;
1514
1515 case TCG_COND_TSTEQ:
1516 case TCG_COND_TSTNE:
1517 if (arg_is_const_val(op->args[2], 0)) {
1518 goto do_brcond_high;
1519 }
1520 if (arg_is_const_val(op->args[3], 0)) {
1521 goto do_brcond_low;
Richard Henderson764d2ab2021-08-24 09:22:11 -07001522 }
1523 break;
1524
1525 default:
1526 break;
1527
Richard Hendersonceb9ee02023-10-23 23:44:27 -07001528 do_brcond_low:
1529 op->opc = INDEX_op_brcond_i32;
1530 op->args[1] = op->args[2];
1531 op->args[2] = cond;
1532 op->args[3] = label;
1533 return fold_brcond(ctx, op);
1534
Richard Henderson764d2ab2021-08-24 09:22:11 -07001535 do_brcond_high:
1536 op->opc = INDEX_op_brcond_i32;
1537 op->args[0] = op->args[1];
1538 op->args[1] = op->args[3];
1539 op->args[2] = cond;
1540 op->args[3] = label;
Richard Hendersonceb9ee02023-10-23 23:44:27 -07001541 return fold_brcond(ctx, op);
Richard Henderson764d2ab2021-08-24 09:22:11 -07001542
1543 do_brcond_const:
1544 if (i == 0) {
1545 tcg_op_remove(ctx->tcg, op);
1546 return true;
1547 }
1548 op->opc = INDEX_op_br;
1549 op->args[0] = label;
Richard Henderson15268552024-12-08 07:45:11 -06001550 finish_ebb(ctx);
1551 return true;
Richard Henderson764d2ab2021-08-24 09:22:11 -07001552 }
Richard Henderson15268552024-12-08 07:45:11 -06001553
1554 finish_bb(ctx);
1555 return true;
Richard Henderson764d2ab2021-08-24 09:22:11 -07001556}
1557
Richard Henderson09bacdc2021-08-24 11:58:12 -07001558static bool fold_bswap(OptContext *ctx, TCGOp *op)
1559{
Richard Henderson57fe5c62021-08-26 12:04:46 -07001560 uint64_t z_mask, s_mask, sign;
Richard Hendersonc1e7b982024-12-08 19:42:20 -06001561 TempOptInfo *t1 = arg_info(op->args[1]);
Richard Hendersonfae450b2021-08-25 22:42:19 -07001562
Richard Hendersonc1e7b982024-12-08 19:42:20 -06001563 if (ti_is_const(t1)) {
1564 return tcg_opt_gen_movi(ctx, op, op->args[0],
1565 do_constant_folding(op->opc, ctx->type,
1566 ti_const_val(t1),
1567 op->args[2]));
Richard Henderson09bacdc2021-08-24 11:58:12 -07001568 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07001569
Richard Hendersonc1e7b982024-12-08 19:42:20 -06001570 z_mask = t1->z_mask;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001571 switch (op->opc) {
1572 case INDEX_op_bswap16_i32:
1573 case INDEX_op_bswap16_i64:
1574 z_mask = bswap16(z_mask);
1575 sign = INT16_MIN;
1576 break;
1577 case INDEX_op_bswap32_i32:
1578 case INDEX_op_bswap32_i64:
1579 z_mask = bswap32(z_mask);
1580 sign = INT32_MIN;
1581 break;
1582 case INDEX_op_bswap64_i64:
1583 z_mask = bswap64(z_mask);
1584 sign = INT64_MIN;
1585 break;
1586 default:
1587 g_assert_not_reached();
1588 }
1589
Richard Henderson75c3bf32024-12-19 10:50:40 -08001590 s_mask = 0;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001591 switch (op->args[2] & (TCG_BSWAP_OZ | TCG_BSWAP_OS)) {
1592 case TCG_BSWAP_OZ:
1593 break;
1594 case TCG_BSWAP_OS:
1595 /* If the sign bit may be 1, force all the bits above to 1. */
1596 if (z_mask & sign) {
1597 z_mask |= sign;
1598 }
Richard Hendersonc1e7b982024-12-08 19:42:20 -06001599 /* The value and therefore s_mask is explicitly sign-extended. */
1600 s_mask = sign;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001601 break;
1602 default:
1603 /* The high bits are undefined: force all bits above the sign to 1. */
1604 z_mask |= sign << 1;
1605 break;
1606 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07001607
Richard Hendersonc1e7b982024-12-08 19:42:20 -06001608 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Henderson09bacdc2021-08-24 11:58:12 -07001609}
1610
Richard Henderson5cf32be2021-08-24 08:17:08 -07001611static bool fold_call(OptContext *ctx, TCGOp *op)
1612{
1613 TCGContext *s = ctx->tcg;
1614 int nb_oargs = TCGOP_CALLO(op);
1615 int nb_iargs = TCGOP_CALLI(op);
1616 int flags, i;
1617
1618 init_arguments(ctx, op, nb_oargs + nb_iargs);
1619 copy_propagate(ctx, op, nb_oargs, nb_iargs);
1620
1621 /* If the function reads or writes globals, reset temp data. */
1622 flags = tcg_call_flags(op);
1623 if (!(flags & (TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_WRITE_GLOBALS))) {
1624 int nb_globals = s->nb_globals;
1625
1626 for (i = 0; i < nb_globals; i++) {
1627 if (test_bit(i, ctx->temps_used.l)) {
Richard Henderson986cac12023-01-09 13:59:35 -08001628 reset_ts(ctx, &ctx->tcg->temps[i]);
Richard Henderson5cf32be2021-08-24 08:17:08 -07001629 }
1630 }
1631 }
1632
Richard Hendersonab84dc32023-08-23 23:04:24 -07001633 /* If the function has side effects, reset mem data. */
1634 if (!(flags & TCG_CALL_NO_SIDE_EFFECTS)) {
1635 remove_mem_copy_all(ctx);
1636 }
1637
Richard Henderson5cf32be2021-08-24 08:17:08 -07001638 /* Reset temp data for outputs. */
1639 for (i = 0; i < nb_oargs; i++) {
Richard Henderson986cac12023-01-09 13:59:35 -08001640 reset_temp(ctx, op->args[i]);
Richard Henderson5cf32be2021-08-24 08:17:08 -07001641 }
1642
1643 /* Stop optimizing MB across calls. */
1644 ctx->prev_mb = NULL;
1645 return true;
1646}
1647
Richard Henderson29f65862024-12-09 14:09:49 -06001648static bool fold_cmp_vec(OptContext *ctx, TCGOp *op)
1649{
1650 /* Canonicalize the comparison to put immediate second. */
1651 if (swap_commutative(NO_DEST, &op->args[1], &op->args[2])) {
1652 op->args[3] = tcg_swap_cond(op->args[3]);
1653 }
1654 return finish_folding(ctx, op);
1655}
1656
1657static bool fold_cmpsel_vec(OptContext *ctx, TCGOp *op)
1658{
1659 /* If true and false values are the same, eliminate the cmp. */
1660 if (args_are_copies(op->args[3], op->args[4])) {
1661 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[3]);
1662 }
1663
1664 /* Canonicalize the comparison to put immediate second. */
1665 if (swap_commutative(NO_DEST, &op->args[1], &op->args[2])) {
1666 op->args[5] = tcg_swap_cond(op->args[5]);
1667 }
1668 /*
1669 * Canonicalize the "false" input reg to match the destination,
1670 * so that the tcg backend can implement "move if true".
1671 */
1672 if (swap_commutative(op->args[0], &op->args[4], &op->args[3])) {
1673 op->args[5] = tcg_invert_cond(op->args[5]);
1674 }
1675 return finish_folding(ctx, op);
1676}
1677
Richard Henderson30dd0bf2021-08-24 10:51:34 -07001678static bool fold_count_zeros(OptContext *ctx, TCGOp *op)
1679{
Richard Hendersonce1d6632024-12-08 19:47:51 -06001680 uint64_t z_mask, s_mask;
1681 TempOptInfo *t1 = arg_info(op->args[1]);
1682 TempOptInfo *t2 = arg_info(op->args[2]);
Richard Hendersonfae450b2021-08-25 22:42:19 -07001683
Richard Hendersonce1d6632024-12-08 19:47:51 -06001684 if (ti_is_const(t1)) {
1685 uint64_t t = ti_const_val(t1);
Richard Henderson30dd0bf2021-08-24 10:51:34 -07001686
1687 if (t != 0) {
Richard Henderson67f84c92021-08-25 08:00:20 -07001688 t = do_constant_folding(op->opc, ctx->type, t, 0);
Richard Henderson30dd0bf2021-08-24 10:51:34 -07001689 return tcg_opt_gen_movi(ctx, op, op->args[0], t);
1690 }
1691 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[2]);
1692 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07001693
1694 switch (ctx->type) {
1695 case TCG_TYPE_I32:
1696 z_mask = 31;
1697 break;
1698 case TCG_TYPE_I64:
1699 z_mask = 63;
1700 break;
1701 default:
1702 g_assert_not_reached();
1703 }
Richard Hendersonce1d6632024-12-08 19:47:51 -06001704 s_mask = ~z_mask;
1705 z_mask |= t2->z_mask;
1706 s_mask &= t2->s_mask;
1707
1708 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Henderson30dd0bf2021-08-24 10:51:34 -07001709}
1710
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001711static bool fold_ctpop(OptContext *ctx, TCGOp *op)
1712{
Richard Henderson81be07f2024-12-08 19:49:17 -06001713 uint64_t z_mask;
1714
Richard Hendersonfae450b2021-08-25 22:42:19 -07001715 if (fold_const1(ctx, op)) {
1716 return true;
1717 }
1718
1719 switch (ctx->type) {
1720 case TCG_TYPE_I32:
Richard Henderson81be07f2024-12-08 19:49:17 -06001721 z_mask = 32 | 31;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001722 break;
1723 case TCG_TYPE_I64:
Richard Henderson81be07f2024-12-08 19:49:17 -06001724 z_mask = 64 | 63;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001725 break;
1726 default:
1727 g_assert_not_reached();
1728 }
Richard Henderson81be07f2024-12-08 19:49:17 -06001729 return fold_masks_z(ctx, op, z_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001730}
1731
Richard Henderson1b1907b2021-08-24 10:47:04 -07001732static bool fold_deposit(OptContext *ctx, TCGOp *op)
1733{
Richard Hendersonc7739ab2024-12-08 19:57:28 -06001734 TempOptInfo *t1 = arg_info(op->args[1]);
1735 TempOptInfo *t2 = arg_info(op->args[2]);
1736 int ofs = op->args[3];
1737 int len = op->args[4];
Richard Hendersonc3b920b2025-01-06 10:32:44 -08001738 int width = 8 * tcg_type_size(ctx->type);
Richard Hendersonedb832c2024-12-19 17:56:05 -08001739 uint64_t z_mask, s_mask;
Richard Henderson8f7a8402023-08-13 11:03:05 -07001740
Richard Hendersonc7739ab2024-12-08 19:57:28 -06001741 if (ti_is_const(t1) && ti_is_const(t2)) {
1742 return tcg_opt_gen_movi(ctx, op, op->args[0],
1743 deposit64(ti_const_val(t1), ofs, len,
1744 ti_const_val(t2)));
Richard Henderson1b1907b2021-08-24 10:47:04 -07001745 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07001746
Richard Henderson8f7a8402023-08-13 11:03:05 -07001747 /* Inserting a value into zero at offset 0. */
Richard Hendersonc7739ab2024-12-08 19:57:28 -06001748 if (ti_is_const_val(t1, 0) && ofs == 0) {
1749 uint64_t mask = MAKE_64BIT_MASK(0, len);
Richard Henderson8f7a8402023-08-13 11:03:05 -07001750
Richard Hendersonc3b920b2025-01-06 10:32:44 -08001751 op->opc = INDEX_op_and;
Richard Henderson8f7a8402023-08-13 11:03:05 -07001752 op->args[1] = op->args[2];
Richard Henderson26aac972023-10-23 12:31:57 -07001753 op->args[2] = arg_new_constant(ctx, mask);
Richard Hendersonc7739ab2024-12-08 19:57:28 -06001754 return fold_and(ctx, op);
Richard Henderson8f7a8402023-08-13 11:03:05 -07001755 }
1756
1757 /* Inserting zero into a value. */
Richard Hendersonc7739ab2024-12-08 19:57:28 -06001758 if (ti_is_const_val(t2, 0)) {
1759 uint64_t mask = deposit64(-1, ofs, len, 0);
Richard Henderson8f7a8402023-08-13 11:03:05 -07001760
Richard Hendersonc3b920b2025-01-06 10:32:44 -08001761 op->opc = INDEX_op_and;
Richard Henderson26aac972023-10-23 12:31:57 -07001762 op->args[2] = arg_new_constant(ctx, mask);
Richard Hendersonc7739ab2024-12-08 19:57:28 -06001763 return fold_and(ctx, op);
Richard Henderson8f7a8402023-08-13 11:03:05 -07001764 }
1765
Richard Hendersonedb832c2024-12-19 17:56:05 -08001766 /* The s_mask from the top portion of the deposit is still valid. */
1767 if (ofs + len == width) {
1768 s_mask = t2->s_mask << ofs;
1769 } else {
1770 s_mask = t1->s_mask & ~MAKE_64BIT_MASK(0, ofs + len);
1771 }
1772
Richard Hendersonc7739ab2024-12-08 19:57:28 -06001773 z_mask = deposit64(t1->z_mask, ofs, len, t2->z_mask);
Richard Hendersonedb832c2024-12-19 17:56:05 -08001774 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Henderson1b1907b2021-08-24 10:47:04 -07001775}
1776
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001777static bool fold_divide(OptContext *ctx, TCGOp *op)
1778{
Richard Henderson2f9d9a32021-10-25 11:30:14 -07001779 if (fold_const2(ctx, op) ||
1780 fold_xi_to_x(ctx, op, 1)) {
1781 return true;
1782 }
Richard Henderson3d5ec802024-12-08 19:59:15 -06001783 return finish_folding(ctx, op);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001784}
1785
Richard Henderson8cdb3fc2021-08-24 12:06:33 -07001786static bool fold_dup(OptContext *ctx, TCGOp *op)
1787{
1788 if (arg_is_const(op->args[1])) {
1789 uint64_t t = arg_info(op->args[1])->val;
1790 t = dup_const(TCGOP_VECE(op), t);
1791 return tcg_opt_gen_movi(ctx, op, op->args[0], t);
1792 }
Richard Hendersone089d692024-12-08 20:00:51 -06001793 return finish_folding(ctx, op);
Richard Henderson8cdb3fc2021-08-24 12:06:33 -07001794}
1795
1796static bool fold_dup2(OptContext *ctx, TCGOp *op)
1797{
1798 if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
1799 uint64_t t = deposit64(arg_info(op->args[1])->val, 32, 32,
1800 arg_info(op->args[2])->val);
1801 return tcg_opt_gen_movi(ctx, op, op->args[0], t);
1802 }
1803
1804 if (args_are_copies(op->args[1], op->args[2])) {
1805 op->opc = INDEX_op_dup_vec;
1806 TCGOP_VECE(op) = MO_32;
1807 }
Richard Hendersone089d692024-12-08 20:00:51 -06001808 return finish_folding(ctx, op);
Richard Henderson8cdb3fc2021-08-24 12:06:33 -07001809}
1810
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001811static bool fold_eqv(OptContext *ctx, TCGOp *op)
1812{
Richard Hendersonef6be622024-12-08 20:03:15 -06001813 uint64_t s_mask;
Richard Henderson46c68d72023-11-15 11:51:28 -08001814 TempOptInfo *t1, *t2;
Richard Hendersonef6be622024-12-08 20:03:15 -06001815
Richard Henderson7a2f7082021-08-26 07:06:39 -07001816 if (fold_const2_commutative(ctx, op) ||
Richard Hendersona63ce0e2021-08-25 20:28:53 -07001817 fold_xi_to_x(ctx, op, -1) ||
Richard Henderson0e0a32b2021-08-24 13:18:01 -07001818 fold_xi_to_not(ctx, op, 0)) {
1819 return true;
1820 }
Richard Henderson3f2b1f82021-08-26 13:08:54 -07001821
Richard Henderson46c68d72023-11-15 11:51:28 -08001822 t2 = arg_info(op->args[2]);
1823 if (ti_is_const(t2)) {
1824 /* Fold eqv r,x,i to xor r,x,~i. */
1825 switch (ctx->type) {
1826 case TCG_TYPE_I32:
1827 case TCG_TYPE_I64:
1828 op->opc = INDEX_op_xor;
1829 break;
1830 case TCG_TYPE_V64:
1831 case TCG_TYPE_V128:
1832 case TCG_TYPE_V256:
1833 op->opc = INDEX_op_xor_vec;
1834 break;
1835 default:
1836 g_assert_not_reached();
1837 }
1838 op->args[2] = arg_new_constant(ctx, ~ti_const_val(t2));
1839 return fold_xor(ctx, op);
1840 }
1841
1842 t1 = arg_info(op->args[1]);
1843 s_mask = t1->s_mask & t2->s_mask;
Richard Hendersonef6be622024-12-08 20:03:15 -06001844 return fold_masks_s(ctx, op, s_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001845}
1846
Richard Hendersonb6617c82021-08-24 10:44:53 -07001847static bool fold_extract(OptContext *ctx, TCGOp *op)
1848{
Richard Hendersonfae450b2021-08-25 22:42:19 -07001849 uint64_t z_mask_old, z_mask;
Richard Hendersonb6cd00f2024-12-08 20:05:11 -06001850 TempOptInfo *t1 = arg_info(op->args[1]);
Richard Henderson57fe5c62021-08-26 12:04:46 -07001851 int pos = op->args[2];
1852 int len = op->args[3];
Richard Hendersonfae450b2021-08-25 22:42:19 -07001853
Richard Hendersonb6cd00f2024-12-08 20:05:11 -06001854 if (ti_is_const(t1)) {
1855 return tcg_opt_gen_movi(ctx, op, op->args[0],
1856 extract64(ti_const_val(t1), pos, len));
Richard Hendersonb6617c82021-08-24 10:44:53 -07001857 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07001858
Richard Hendersonb6cd00f2024-12-08 20:05:11 -06001859 z_mask_old = t1->z_mask;
Richard Henderson57fe5c62021-08-26 12:04:46 -07001860 z_mask = extract64(z_mask_old, pos, len);
Richard Henderson045ace32024-12-19 10:33:51 -08001861 if (pos == 0 && fold_affected_mask(ctx, op, z_mask_old ^ z_mask)) {
1862 return true;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001863 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07001864
Richard Hendersonb6cd00f2024-12-08 20:05:11 -06001865 return fold_masks_z(ctx, op, z_mask);
Richard Hendersonb6617c82021-08-24 10:44:53 -07001866}
1867
Richard Hendersondcd08992021-08-24 10:41:39 -07001868static bool fold_extract2(OptContext *ctx, TCGOp *op)
1869{
1870 if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
1871 uint64_t v1 = arg_info(op->args[1])->val;
1872 uint64_t v2 = arg_info(op->args[2])->val;
1873 int shr = op->args[3];
1874
1875 if (op->opc == INDEX_op_extract2_i64) {
1876 v1 >>= shr;
1877 v2 <<= 64 - shr;
1878 } else {
1879 v1 = (uint32_t)v1 >> shr;
Richard Henderson225bec02021-11-09 23:17:59 +01001880 v2 = (uint64_t)((int32_t)v2 << (32 - shr));
Richard Hendersondcd08992021-08-24 10:41:39 -07001881 }
1882 return tcg_opt_gen_movi(ctx, op, op->args[0], v1 | v2);
1883 }
Richard Hendersonc9df99e2024-12-08 20:06:42 -06001884 return finish_folding(ctx, op);
Richard Hendersondcd08992021-08-24 10:41:39 -07001885}
1886
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001887static bool fold_exts(OptContext *ctx, TCGOp *op)
1888{
Richard Henderson48e8de62024-12-26 12:01:57 -08001889 uint64_t s_mask, z_mask;
Richard Hendersona9621922024-12-08 20:08:46 -06001890 TempOptInfo *t1;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001891
1892 if (fold_const1(ctx, op)) {
1893 return true;
1894 }
1895
Richard Hendersona9621922024-12-08 20:08:46 -06001896 t1 = arg_info(op->args[1]);
1897 z_mask = t1->z_mask;
1898 s_mask = t1->s_mask;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001899
1900 switch (op->opc) {
Richard Hendersonfae450b2021-08-25 22:42:19 -07001901 case INDEX_op_ext_i32_i64:
Richard Hendersona9621922024-12-08 20:08:46 -06001902 s_mask |= INT32_MIN;
1903 z_mask = (int32_t)z_mask;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001904 break;
1905 default:
1906 g_assert_not_reached();
1907 }
Richard Hendersona9621922024-12-08 20:08:46 -06001908 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001909}
1910
1911static bool fold_extu(OptContext *ctx, TCGOp *op)
1912{
Richard Henderson48e8de62024-12-26 12:01:57 -08001913 uint64_t z_mask;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001914
1915 if (fold_const1(ctx, op)) {
1916 return true;
1917 }
1918
Richard Henderson48e8de62024-12-26 12:01:57 -08001919 z_mask = arg_info(op->args[1])->z_mask;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001920 switch (op->opc) {
Richard Hendersonfae450b2021-08-25 22:42:19 -07001921 case INDEX_op_extrl_i64_i32:
1922 case INDEX_op_extu_i32_i64:
Richard Hendersonfae450b2021-08-25 22:42:19 -07001923 z_mask = (uint32_t)z_mask;
1924 break;
1925 case INDEX_op_extrh_i64_i32:
Richard Hendersonfae450b2021-08-25 22:42:19 -07001926 z_mask >>= 32;
1927 break;
1928 default:
1929 g_assert_not_reached();
1930 }
Richard Henderson08abe292024-12-08 20:11:44 -06001931 return fold_masks_z(ctx, op, z_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07001932}
1933
Richard Henderson3eefdf22021-08-25 11:06:43 -07001934static bool fold_mb(OptContext *ctx, TCGOp *op)
1935{
1936 /* Eliminate duplicate and redundant fence instructions. */
1937 if (ctx->prev_mb) {
1938 /*
1939 * Merge two barriers of the same type into one,
1940 * or a weaker barrier into a stronger one,
1941 * or two weaker barriers into a stronger one.
1942 * mb X; mb Y => mb X|Y
1943 * mb; strl => mb; st
1944 * ldaq; mb => ld; mb
1945 * ldaq; strl => ld; mb; st
1946 * Other combinations are also merged into a strong
1947 * barrier. This is stricter than specified but for
1948 * the purposes of TCG is better than not optimizing.
1949 */
1950 ctx->prev_mb->args[0] |= op->args[0];
1951 tcg_op_remove(ctx->tcg, op);
1952 } else {
1953 ctx->prev_mb = op;
1954 }
1955 return true;
1956}
1957
Richard Henderson2cfac7f2021-08-25 13:05:43 -07001958static bool fold_mov(OptContext *ctx, TCGOp *op)
1959{
1960 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
1961}
1962
Richard Henderson0c310a32021-08-24 10:37:24 -07001963static bool fold_movcond(OptContext *ctx, TCGOp *op)
1964{
Richard Henderson32202782024-12-08 20:16:38 -06001965 uint64_t z_mask, s_mask;
1966 TempOptInfo *tt, *ft;
Richard Henderson7a2f7082021-08-26 07:06:39 -07001967 int i;
Richard Henderson0c310a32021-08-24 10:37:24 -07001968
Richard Henderson141125e2024-09-06 21:00:10 -07001969 /* If true and false values are the same, eliminate the cmp. */
1970 if (args_are_copies(op->args[3], op->args[4])) {
1971 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[3]);
1972 }
1973
Richard Henderson7a2f7082021-08-26 07:06:39 -07001974 /*
1975 * Canonicalize the "false" input reg to match the destination reg so
1976 * that the tcg backend can implement a "move if true" operation.
1977 */
1978 if (swap_commutative(op->args[0], &op->args[4], &op->args[3])) {
Richard Henderson246c4b72023-10-24 16:36:50 -07001979 op->args[5] = tcg_invert_cond(op->args[5]);
Richard Henderson7a2f7082021-08-26 07:06:39 -07001980 }
1981
Richard Hendersonfb04ab72024-01-10 18:21:58 +11001982 i = do_constant_folding_cond1(ctx, op, NO_DEST, &op->args[1],
Richard Henderson246c4b72023-10-24 16:36:50 -07001983 &op->args[2], &op->args[5]);
Richard Henderson0c310a32021-08-24 10:37:24 -07001984 if (i >= 0) {
1985 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[4 - i]);
1986 }
1987
Richard Henderson32202782024-12-08 20:16:38 -06001988 tt = arg_info(op->args[3]);
1989 ft = arg_info(op->args[4]);
1990 z_mask = tt->z_mask | ft->z_mask;
1991 s_mask = tt->s_mask & ft->s_mask;
Richard Hendersonfae450b2021-08-25 22:42:19 -07001992
Richard Henderson32202782024-12-08 20:16:38 -06001993 if (ti_is_const(tt) && ti_is_const(ft)) {
1994 uint64_t tv = ti_const_val(tt);
1995 uint64_t fv = ti_const_val(ft);
Richard Henderson36355022023-08-04 23:24:04 +00001996 TCGOpcode opc, negopc = 0;
Richard Henderson246c4b72023-10-24 16:36:50 -07001997 TCGCond cond = op->args[5];
Richard Henderson0c310a32021-08-24 10:37:24 -07001998
Richard Henderson67f84c92021-08-25 08:00:20 -07001999 switch (ctx->type) {
2000 case TCG_TYPE_I32:
2001 opc = INDEX_op_setcond_i32;
Richard Henderson36355022023-08-04 23:24:04 +00002002 if (TCG_TARGET_HAS_negsetcond_i32) {
2003 negopc = INDEX_op_negsetcond_i32;
2004 }
2005 tv = (int32_t)tv;
2006 fv = (int32_t)fv;
Richard Henderson67f84c92021-08-25 08:00:20 -07002007 break;
2008 case TCG_TYPE_I64:
2009 opc = INDEX_op_setcond_i64;
Richard Henderson36355022023-08-04 23:24:04 +00002010 if (TCG_TARGET_HAS_negsetcond_i64) {
2011 negopc = INDEX_op_negsetcond_i64;
2012 }
Richard Henderson67f84c92021-08-25 08:00:20 -07002013 break;
2014 default:
2015 g_assert_not_reached();
2016 }
Richard Henderson0c310a32021-08-24 10:37:24 -07002017
2018 if (tv == 1 && fv == 0) {
2019 op->opc = opc;
2020 op->args[3] = cond;
2021 } else if (fv == 1 && tv == 0) {
2022 op->opc = opc;
2023 op->args[3] = tcg_invert_cond(cond);
Richard Henderson36355022023-08-04 23:24:04 +00002024 } else if (negopc) {
2025 if (tv == -1 && fv == 0) {
2026 op->opc = negopc;
2027 op->args[3] = cond;
2028 } else if (fv == -1 && tv == 0) {
2029 op->opc = negopc;
2030 op->args[3] = tcg_invert_cond(cond);
2031 }
Richard Henderson0c310a32021-08-24 10:37:24 -07002032 }
2033 }
Richard Henderson32202782024-12-08 20:16:38 -06002034
2035 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Henderson0c310a32021-08-24 10:37:24 -07002036}
2037
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002038static bool fold_mul(OptContext *ctx, TCGOp *op)
2039{
Richard Hendersone8679952021-08-25 13:19:52 -07002040 if (fold_const2(ctx, op) ||
Richard Henderson5b5cf472021-10-25 11:19:14 -07002041 fold_xi_to_i(ctx, op, 0) ||
2042 fold_xi_to_x(ctx, op, 1)) {
Richard Hendersone8679952021-08-25 13:19:52 -07002043 return true;
2044 }
Richard Hendersoncd9c5832024-12-08 20:18:02 -06002045 return finish_folding(ctx, op);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002046}
2047
2048static bool fold_mul_highpart(OptContext *ctx, TCGOp *op)
2049{
Richard Henderson7a2f7082021-08-26 07:06:39 -07002050 if (fold_const2_commutative(ctx, op) ||
Richard Hendersone8679952021-08-25 13:19:52 -07002051 fold_xi_to_i(ctx, op, 0)) {
2052 return true;
2053 }
Richard Hendersoncd9c5832024-12-08 20:18:02 -06002054 return finish_folding(ctx, op);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002055}
2056
Richard Henderson407112b2021-08-26 06:33:04 -07002057static bool fold_multiply2(OptContext *ctx, TCGOp *op)
Richard Henderson6b8ac0d2021-08-24 10:24:12 -07002058{
Richard Henderson7a2f7082021-08-26 07:06:39 -07002059 swap_commutative(op->args[0], &op->args[2], &op->args[3]);
2060
Richard Henderson6b8ac0d2021-08-24 10:24:12 -07002061 if (arg_is_const(op->args[2]) && arg_is_const(op->args[3])) {
Richard Henderson407112b2021-08-26 06:33:04 -07002062 uint64_t a = arg_info(op->args[2])->val;
2063 uint64_t b = arg_info(op->args[3])->val;
2064 uint64_t h, l;
Richard Henderson6b8ac0d2021-08-24 10:24:12 -07002065 TCGArg rl, rh;
Richard Henderson407112b2021-08-26 06:33:04 -07002066 TCGOp *op2;
2067
2068 switch (op->opc) {
2069 case INDEX_op_mulu2_i32:
2070 l = (uint64_t)(uint32_t)a * (uint32_t)b;
2071 h = (int32_t)(l >> 32);
2072 l = (int32_t)l;
2073 break;
2074 case INDEX_op_muls2_i32:
2075 l = (int64_t)(int32_t)a * (int32_t)b;
2076 h = l >> 32;
2077 l = (int32_t)l;
2078 break;
2079 case INDEX_op_mulu2_i64:
2080 mulu64(&l, &h, a, b);
2081 break;
2082 case INDEX_op_muls2_i64:
2083 muls64(&l, &h, a, b);
2084 break;
2085 default:
2086 g_assert_not_reached();
2087 }
Richard Henderson6b8ac0d2021-08-24 10:24:12 -07002088
2089 rl = op->args[0];
2090 rh = op->args[1];
Richard Henderson407112b2021-08-26 06:33:04 -07002091
2092 /* The proper opcode is supplied by tcg_opt_gen_mov. */
Richard Hendersona3c1c572025-04-21 11:05:29 -07002093 op2 = opt_insert_before(ctx, op, 0, 2);
Richard Henderson407112b2021-08-26 06:33:04 -07002094
2095 tcg_opt_gen_movi(ctx, op, rl, l);
2096 tcg_opt_gen_movi(ctx, op2, rh, h);
Richard Henderson6b8ac0d2021-08-24 10:24:12 -07002097 return true;
2098 }
Richard Hendersoncd9c5832024-12-08 20:18:02 -06002099 return finish_folding(ctx, op);
Richard Henderson6b8ac0d2021-08-24 10:24:12 -07002100}
2101
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002102static bool fold_nand(OptContext *ctx, TCGOp *op)
2103{
Richard Hendersonfa3168e2024-12-08 20:20:40 -06002104 uint64_t s_mask;
2105
Richard Henderson7a2f7082021-08-26 07:06:39 -07002106 if (fold_const2_commutative(ctx, op) ||
Richard Henderson0e0a32b2021-08-24 13:18:01 -07002107 fold_xi_to_not(ctx, op, -1)) {
2108 return true;
2109 }
Richard Henderson3f2b1f82021-08-26 13:08:54 -07002110
Richard Hendersonfa3168e2024-12-08 20:20:40 -06002111 s_mask = arg_info(op->args[1])->s_mask
2112 & arg_info(op->args[2])->s_mask;
2113 return fold_masks_s(ctx, op, s_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002114}
2115
Richard Hendersone25fe882024-04-04 20:53:50 +00002116static bool fold_neg_no_const(OptContext *ctx, TCGOp *op)
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002117{
Richard Hendersonfae450b2021-08-25 22:42:19 -07002118 /* Set to 1 all bits to the left of the rightmost. */
Richard Hendersone25fe882024-04-04 20:53:50 +00002119 uint64_t z_mask = arg_info(op->args[1])->z_mask;
Richard Hendersond151fd32024-12-08 20:23:11 -06002120 z_mask = -(z_mask & -z_mask);
Richard Hendersonfae450b2021-08-25 22:42:19 -07002121
Richard Hendersond151fd32024-12-08 20:23:11 -06002122 return fold_masks_z(ctx, op, z_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002123}
2124
Richard Hendersone25fe882024-04-04 20:53:50 +00002125static bool fold_neg(OptContext *ctx, TCGOp *op)
2126{
2127 return fold_const1(ctx, op) || fold_neg_no_const(ctx, op);
2128}
2129
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002130static bool fold_nor(OptContext *ctx, TCGOp *op)
2131{
Richard Henderson2b7b6952024-12-08 20:25:21 -06002132 uint64_t s_mask;
2133
Richard Henderson7a2f7082021-08-26 07:06:39 -07002134 if (fold_const2_commutative(ctx, op) ||
Richard Henderson0e0a32b2021-08-24 13:18:01 -07002135 fold_xi_to_not(ctx, op, 0)) {
2136 return true;
2137 }
Richard Henderson3f2b1f82021-08-26 13:08:54 -07002138
Richard Henderson2b7b6952024-12-08 20:25:21 -06002139 s_mask = arg_info(op->args[1])->s_mask
2140 & arg_info(op->args[2])->s_mask;
2141 return fold_masks_s(ctx, op, s_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002142}
2143
2144static bool fold_not(OptContext *ctx, TCGOp *op)
2145{
Richard Henderson0e0a32b2021-08-24 13:18:01 -07002146 if (fold_const1(ctx, op)) {
2147 return true;
2148 }
Richard Henderson608e75f2024-12-08 20:27:02 -06002149 return fold_masks_s(ctx, op, arg_info(op->args[1])->s_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002150}
2151
2152static bool fold_or(OptContext *ctx, TCGOp *op)
2153{
Richard Henderson83b1ba32024-12-08 20:28:59 -06002154 uint64_t z_mask, s_mask;
2155 TempOptInfo *t1, *t2;
2156
Richard Henderson7a2f7082021-08-26 07:06:39 -07002157 if (fold_const2_commutative(ctx, op) ||
Richard Hendersona63ce0e2021-08-25 20:28:53 -07002158 fold_xi_to_x(ctx, op, 0) ||
Richard Hendersonca7bb042021-08-25 13:14:21 -07002159 fold_xx_to_x(ctx, op)) {
2160 return true;
2161 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07002162
Richard Henderson83b1ba32024-12-08 20:28:59 -06002163 t1 = arg_info(op->args[1]);
2164 t2 = arg_info(op->args[2]);
2165 z_mask = t1->z_mask | t2->z_mask;
2166 s_mask = t1->s_mask & t2->s_mask;
2167 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002168}
2169
2170static bool fold_orc(OptContext *ctx, TCGOp *op)
2171{
Richard Henderson54e26b22024-12-08 20:30:20 -06002172 uint64_t s_mask;
Richard Henderson50e40ec2024-12-10 08:13:10 -06002173 TempOptInfo *t1, *t2;
Richard Henderson54e26b22024-12-08 20:30:20 -06002174
Richard Henderson0e0a32b2021-08-24 13:18:01 -07002175 if (fold_const2(ctx, op) ||
Richard Henderson4e858d92021-08-26 07:31:13 -07002176 fold_xx_to_i(ctx, op, -1) ||
Richard Hendersona63ce0e2021-08-25 20:28:53 -07002177 fold_xi_to_x(ctx, op, -1) ||
Richard Henderson0e0a32b2021-08-24 13:18:01 -07002178 fold_ix_to_not(ctx, op, 0)) {
2179 return true;
2180 }
Richard Henderson3f2b1f82021-08-26 13:08:54 -07002181
Richard Henderson50e40ec2024-12-10 08:13:10 -06002182 t2 = arg_info(op->args[2]);
2183 if (ti_is_const(t2)) {
2184 /* Fold orc r,x,i to or r,x,~i. */
2185 switch (ctx->type) {
2186 case TCG_TYPE_I32:
2187 case TCG_TYPE_I64:
2188 op->opc = INDEX_op_or;
2189 break;
2190 case TCG_TYPE_V64:
2191 case TCG_TYPE_V128:
2192 case TCG_TYPE_V256:
2193 op->opc = INDEX_op_or_vec;
2194 break;
2195 default:
2196 g_assert_not_reached();
2197 }
2198 op->args[2] = arg_new_constant(ctx, ~ti_const_val(t2));
2199 return fold_or(ctx, op);
2200 }
2201
2202 t1 = arg_info(op->args[1]);
2203 s_mask = t1->s_mask & t2->s_mask;
Richard Henderson54e26b22024-12-08 20:30:20 -06002204 return fold_masks_s(ctx, op, s_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002205}
2206
Richard Henderson6813be92024-12-08 20:33:30 -06002207static bool fold_qemu_ld_1reg(OptContext *ctx, TCGOp *op)
Richard Henderson3eefdf22021-08-25 11:06:43 -07002208{
Richard Hendersonfae450b2021-08-25 22:42:19 -07002209 const TCGOpDef *def = &tcg_op_defs[op->opc];
2210 MemOpIdx oi = op->args[def->nb_oargs + def->nb_iargs];
2211 MemOp mop = get_memop(oi);
2212 int width = 8 * memop_size(mop);
Richard Henderson6813be92024-12-08 20:33:30 -06002213 uint64_t z_mask = -1, s_mask = 0;
Richard Hendersonfae450b2021-08-25 22:42:19 -07002214
Richard Henderson57fe5c62021-08-26 12:04:46 -07002215 if (width < 64) {
Richard Henderson75c3bf32024-12-19 10:50:40 -08002216 if (mop & MO_SIGN) {
Richard Henderson6813be92024-12-08 20:33:30 -06002217 s_mask = MAKE_64BIT_MASK(width - 1, 64 - (width - 1));
Richard Henderson75c3bf32024-12-19 10:50:40 -08002218 } else {
Richard Henderson6813be92024-12-08 20:33:30 -06002219 z_mask = MAKE_64BIT_MASK(0, width);
Richard Henderson57fe5c62021-08-26 12:04:46 -07002220 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07002221 }
2222
Richard Henderson3eefdf22021-08-25 11:06:43 -07002223 /* Opcodes that touch guest memory stop the mb optimization. */
2224 ctx->prev_mb = NULL;
Richard Henderson6813be92024-12-08 20:33:30 -06002225
2226 return fold_masks_zs(ctx, op, z_mask, s_mask);
2227}
2228
2229static bool fold_qemu_ld_2reg(OptContext *ctx, TCGOp *op)
2230{
2231 /* Opcodes that touch guest memory stop the mb optimization. */
2232 ctx->prev_mb = NULL;
2233 return finish_folding(ctx, op);
Richard Henderson3eefdf22021-08-25 11:06:43 -07002234}
2235
2236static bool fold_qemu_st(OptContext *ctx, TCGOp *op)
2237{
2238 /* Opcodes that touch guest memory stop the mb optimization. */
2239 ctx->prev_mb = NULL;
Richard Henderson082b3ef2024-12-08 20:34:57 -06002240 return true;
Richard Henderson3eefdf22021-08-25 11:06:43 -07002241}
2242
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002243static bool fold_remainder(OptContext *ctx, TCGOp *op)
2244{
Richard Henderson267c17e2021-10-25 11:30:33 -07002245 if (fold_const2(ctx, op) ||
2246 fold_xx_to_i(ctx, op, 0)) {
2247 return true;
2248 }
Richard Hendersonf9e39342024-12-08 20:36:50 -06002249 return finish_folding(ctx, op);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002250}
2251
Richard Henderson95eb2292024-12-08 20:47:59 -06002252/* Return 1 if finished, -1 if simplified, 0 if unchanged. */
2253static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg)
Richard Henderson8d65cda2024-03-26 16:00:40 -10002254{
2255 uint64_t a_zmask, b_val;
2256 TCGCond cond;
2257
2258 if (!arg_is_const(op->args[2])) {
2259 return false;
2260 }
2261
2262 a_zmask = arg_info(op->args[1])->z_mask;
2263 b_val = arg_info(op->args[2])->val;
2264 cond = op->args[3];
2265
2266 if (ctx->type == TCG_TYPE_I32) {
2267 a_zmask = (uint32_t)a_zmask;
2268 b_val = (uint32_t)b_val;
2269 }
2270
2271 /*
2272 * A with only low bits set vs B with high bits set means that A < B.
2273 */
2274 if (a_zmask < b_val) {
2275 bool inv = false;
2276
2277 switch (cond) {
2278 case TCG_COND_NE:
2279 case TCG_COND_LEU:
2280 case TCG_COND_LTU:
2281 inv = true;
2282 /* fall through */
2283 case TCG_COND_GTU:
2284 case TCG_COND_GEU:
2285 case TCG_COND_EQ:
2286 return tcg_opt_gen_movi(ctx, op, op->args[0], neg ? -inv : inv);
2287 default:
2288 break;
2289 }
2290 }
2291
2292 /*
2293 * A with only lsb set is already boolean.
2294 */
2295 if (a_zmask <= 1) {
2296 bool convert = false;
2297 bool inv = false;
2298
2299 switch (cond) {
2300 case TCG_COND_EQ:
2301 inv = true;
2302 /* fall through */
2303 case TCG_COND_NE:
2304 convert = (b_val == 0);
2305 break;
2306 case TCG_COND_LTU:
2307 case TCG_COND_TSTEQ:
2308 inv = true;
2309 /* fall through */
2310 case TCG_COND_GEU:
2311 case TCG_COND_TSTNE:
2312 convert = (b_val == 1);
2313 break;
2314 default:
2315 break;
2316 }
2317 if (convert) {
Richard Henderson8d65cda2024-03-26 16:00:40 -10002318 if (!inv && !neg) {
2319 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
2320 }
2321
Richard Henderson8d65cda2024-03-26 16:00:40 -10002322 if (!inv) {
Richard Henderson69713582025-01-06 22:48:57 -08002323 op->opc = INDEX_op_neg;
Richard Henderson8d65cda2024-03-26 16:00:40 -10002324 } else if (neg) {
Richard Henderson79602f62025-01-06 09:11:39 -08002325 op->opc = INDEX_op_add;
Richard Henderson8d65cda2024-03-26 16:00:40 -10002326 op->args[2] = arg_new_constant(ctx, -1);
2327 } else {
Richard Hendersonfffd3dc2025-01-06 15:18:35 -08002328 op->opc = INDEX_op_xor;
Richard Henderson8d65cda2024-03-26 16:00:40 -10002329 op->args[2] = arg_new_constant(ctx, 1);
2330 }
Richard Henderson95eb2292024-12-08 20:47:59 -06002331 return -1;
Richard Henderson8d65cda2024-03-26 16:00:40 -10002332 }
2333 }
Richard Henderson95eb2292024-12-08 20:47:59 -06002334 return 0;
Richard Henderson8d65cda2024-03-26 16:00:40 -10002335}
2336
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002337static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg)
2338{
Richard Henderson69713582025-01-06 22:48:57 -08002339 TCGOpcode shr_opc;
Paolo Bonziniff202812024-02-28 12:06:41 +01002340 TCGOpcode uext_opc = 0, sext_opc = 0;
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002341 TCGCond cond = op->args[3];
2342 TCGArg ret, src1, src2;
2343 TCGOp *op2;
2344 uint64_t val;
2345 int sh;
2346 bool inv;
2347
2348 if (!is_tst_cond(cond) || !arg_is_const(op->args[2])) {
2349 return;
2350 }
2351
2352 src2 = op->args[2];
2353 val = arg_info(src2)->val;
2354 if (!is_power_of_2(val)) {
2355 return;
2356 }
2357 sh = ctz64(val);
2358
2359 switch (ctx->type) {
2360 case TCG_TYPE_I32:
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002361 shr_opc = INDEX_op_shr_i32;
Richard Henderson4bce7522024-12-25 18:55:45 -08002362 if (TCG_TARGET_extract_valid(TCG_TYPE_I32, sh, 1)) {
Richard Hendersonc334de12024-12-26 00:43:19 -08002363 uext_opc = INDEX_op_extract_i32;
Richard Henderson4bce7522024-12-25 18:55:45 -08002364 }
2365 if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, sh, 1)) {
Richard Hendersonc334de12024-12-26 00:43:19 -08002366 sext_opc = INDEX_op_sextract_i32;
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002367 }
2368 break;
2369 case TCG_TYPE_I64:
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002370 shr_opc = INDEX_op_shr_i64;
Richard Henderson4bce7522024-12-25 18:55:45 -08002371 if (TCG_TARGET_extract_valid(TCG_TYPE_I64, sh, 1)) {
Richard Hendersonc334de12024-12-26 00:43:19 -08002372 uext_opc = INDEX_op_extract_i64;
Richard Henderson4bce7522024-12-25 18:55:45 -08002373 }
2374 if (TCG_TARGET_sextract_valid(TCG_TYPE_I64, sh, 1)) {
Richard Hendersonc334de12024-12-26 00:43:19 -08002375 sext_opc = INDEX_op_sextract_i64;
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002376 }
2377 break;
2378 default:
2379 g_assert_not_reached();
2380 }
2381
2382 ret = op->args[0];
2383 src1 = op->args[1];
2384 inv = cond == TCG_COND_TSTEQ;
2385
2386 if (sh && sext_opc && neg && !inv) {
2387 op->opc = sext_opc;
2388 op->args[1] = src1;
2389 op->args[2] = sh;
2390 op->args[3] = 1;
2391 return;
2392 } else if (sh && uext_opc) {
2393 op->opc = uext_opc;
2394 op->args[1] = src1;
2395 op->args[2] = sh;
2396 op->args[3] = 1;
2397 } else {
2398 if (sh) {
Richard Hendersona3c1c572025-04-21 11:05:29 -07002399 op2 = opt_insert_before(ctx, op, shr_opc, 3);
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002400 op2->args[0] = ret;
2401 op2->args[1] = src1;
2402 op2->args[2] = arg_new_constant(ctx, sh);
2403 src1 = ret;
2404 }
Richard Hendersonc3b920b2025-01-06 10:32:44 -08002405 op->opc = INDEX_op_and;
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002406 op->args[1] = src1;
2407 op->args[2] = arg_new_constant(ctx, 1);
2408 }
2409
2410 if (neg && inv) {
Richard Henderson93a9ddb2025-01-06 22:06:08 -08002411 op2 = opt_insert_after(ctx, op, INDEX_op_add, 3);
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002412 op2->args[0] = ret;
2413 op2->args[1] = ret;
Richard Henderson93a9ddb2025-01-06 22:06:08 -08002414 op2->args[2] = arg_new_constant(ctx, -1);
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002415 } else if (inv) {
Richard Hendersonfffd3dc2025-01-06 15:18:35 -08002416 op2 = opt_insert_after(ctx, op, INDEX_op_xor, 3);
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002417 op2->args[0] = ret;
2418 op2->args[1] = ret;
2419 op2->args[2] = arg_new_constant(ctx, 1);
2420 } else if (neg) {
Richard Henderson69713582025-01-06 22:48:57 -08002421 op2 = opt_insert_after(ctx, op, INDEX_op_neg, 2);
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002422 op2->args[0] = ret;
2423 op2->args[1] = ret;
2424 }
2425}
2426
Richard Hendersonc63ff552021-08-24 09:35:30 -07002427static bool fold_setcond(OptContext *ctx, TCGOp *op)
2428{
Richard Hendersonfb04ab72024-01-10 18:21:58 +11002429 int i = do_constant_folding_cond1(ctx, op, op->args[0], &op->args[1],
Richard Henderson246c4b72023-10-24 16:36:50 -07002430 &op->args[2], &op->args[3]);
Richard Hendersonc63ff552021-08-24 09:35:30 -07002431 if (i >= 0) {
2432 return tcg_opt_gen_movi(ctx, op, op->args[0], i);
2433 }
Richard Henderson8d65cda2024-03-26 16:00:40 -10002434
Richard Henderson95eb2292024-12-08 20:47:59 -06002435 i = fold_setcond_zmask(ctx, op, false);
2436 if (i > 0) {
Richard Henderson8d65cda2024-03-26 16:00:40 -10002437 return true;
2438 }
Richard Henderson95eb2292024-12-08 20:47:59 -06002439 if (i == 0) {
2440 fold_setcond_tst_pow2(ctx, op, false);
2441 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07002442
Richard Henderson2c8a2832024-12-08 20:50:37 -06002443 return fold_masks_z(ctx, op, 1);
Richard Hendersonc63ff552021-08-24 09:35:30 -07002444}
2445
Richard Henderson36355022023-08-04 23:24:04 +00002446static bool fold_negsetcond(OptContext *ctx, TCGOp *op)
2447{
Richard Hendersonfb04ab72024-01-10 18:21:58 +11002448 int i = do_constant_folding_cond1(ctx, op, op->args[0], &op->args[1],
Richard Henderson246c4b72023-10-24 16:36:50 -07002449 &op->args[2], &op->args[3]);
Richard Henderson36355022023-08-04 23:24:04 +00002450 if (i >= 0) {
2451 return tcg_opt_gen_movi(ctx, op, op->args[0], -i);
2452 }
Richard Henderson8d65cda2024-03-26 16:00:40 -10002453
Richard Henderson95eb2292024-12-08 20:47:59 -06002454 i = fold_setcond_zmask(ctx, op, true);
2455 if (i > 0) {
Richard Henderson8d65cda2024-03-26 16:00:40 -10002456 return true;
2457 }
Richard Henderson95eb2292024-12-08 20:47:59 -06002458 if (i == 0) {
2459 fold_setcond_tst_pow2(ctx, op, true);
2460 }
Richard Henderson36355022023-08-04 23:24:04 +00002461
2462 /* Value is {0,-1} so all bits are repetitions of the sign. */
Richard Henderson081cf082024-12-08 20:50:58 -06002463 return fold_masks_s(ctx, op, -1);
Richard Henderson36355022023-08-04 23:24:04 +00002464}
2465
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07002466static bool fold_setcond2(OptContext *ctx, TCGOp *op)
2467{
Richard Henderson7e64b112023-10-24 16:53:56 -07002468 TCGCond cond;
Richard Henderson7a2f7082021-08-26 07:06:39 -07002469 int i, inv = 0;
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07002470
Richard Hendersonfb04ab72024-01-10 18:21:58 +11002471 i = do_constant_folding_cond2(ctx, op, &op->args[1]);
Richard Henderson7e64b112023-10-24 16:53:56 -07002472 cond = op->args[5];
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07002473 if (i >= 0) {
2474 goto do_setcond_const;
2475 }
2476
2477 switch (cond) {
2478 case TCG_COND_LT:
2479 case TCG_COND_GE:
2480 /*
2481 * Simplify LT/GE comparisons vs zero to a single compare
2482 * vs the high word of the input.
2483 */
Richard Henderson27cdb852023-10-23 11:38:00 -07002484 if (arg_is_const_val(op->args[3], 0) &&
2485 arg_is_const_val(op->args[4], 0)) {
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07002486 goto do_setcond_high;
2487 }
2488 break;
2489
2490 case TCG_COND_NE:
2491 inv = 1;
2492 QEMU_FALLTHROUGH;
2493 case TCG_COND_EQ:
2494 /*
2495 * Simplify EQ/NE comparisons where one of the pairs
2496 * can be simplified.
2497 */
Richard Henderson67f84c92021-08-25 08:00:20 -07002498 i = do_constant_folding_cond(TCG_TYPE_I32, op->args[1],
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07002499 op->args[3], cond);
2500 switch (i ^ inv) {
2501 case 0:
2502 goto do_setcond_const;
2503 case 1:
2504 goto do_setcond_high;
2505 }
2506
Richard Henderson67f84c92021-08-25 08:00:20 -07002507 i = do_constant_folding_cond(TCG_TYPE_I32, op->args[2],
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07002508 op->args[4], cond);
2509 switch (i ^ inv) {
2510 case 0:
2511 goto do_setcond_const;
2512 case 1:
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002513 goto do_setcond_low;
2514 }
2515 break;
2516
2517 case TCG_COND_TSTEQ:
2518 case TCG_COND_TSTNE:
Richard Hendersona71d9df2024-06-30 19:46:23 -07002519 if (arg_is_const_val(op->args[3], 0)) {
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002520 goto do_setcond_high;
2521 }
2522 if (arg_is_const_val(op->args[4], 0)) {
2523 goto do_setcond_low;
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07002524 }
2525 break;
2526
2527 default:
2528 break;
2529
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002530 do_setcond_low:
2531 op->args[2] = op->args[3];
2532 op->args[3] = cond;
2533 op->opc = INDEX_op_setcond_i32;
2534 return fold_setcond(ctx, op);
2535
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07002536 do_setcond_high:
2537 op->args[1] = op->args[2];
2538 op->args[2] = op->args[4];
2539 op->args[3] = cond;
2540 op->opc = INDEX_op_setcond_i32;
Richard Hendersonceb9ee02023-10-23 23:44:27 -07002541 return fold_setcond(ctx, op);
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07002542 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07002543
Richard Hendersona53502c2024-12-08 20:56:36 -06002544 return fold_masks_z(ctx, op, 1);
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07002545
2546 do_setcond_const:
2547 return tcg_opt_gen_movi(ctx, op, op->args[0], i);
2548}
2549
Richard Hendersonb6617c82021-08-24 10:44:53 -07002550static bool fold_sextract(OptContext *ctx, TCGOp *op)
2551{
Richard Henderson57fe5c62021-08-26 12:04:46 -07002552 uint64_t z_mask, s_mask, s_mask_old;
Richard Hendersonbaff5072024-12-08 21:09:30 -06002553 TempOptInfo *t1 = arg_info(op->args[1]);
Richard Henderson57fe5c62021-08-26 12:04:46 -07002554 int pos = op->args[2];
2555 int len = op->args[3];
Richard Hendersonfae450b2021-08-25 22:42:19 -07002556
Richard Hendersonbaff5072024-12-08 21:09:30 -06002557 if (ti_is_const(t1)) {
2558 return tcg_opt_gen_movi(ctx, op, op->args[0],
2559 sextract64(ti_const_val(t1), pos, len));
Richard Hendersonb6617c82021-08-24 10:44:53 -07002560 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07002561
Richard Hendersonbaff5072024-12-08 21:09:30 -06002562 s_mask_old = t1->s_mask;
2563 s_mask = s_mask_old >> pos;
2564 s_mask |= -1ull << (len - 1);
Richard Henderson57fe5c62021-08-26 12:04:46 -07002565
Richard Hendersonaa9e0502024-12-21 22:03:53 -08002566 if (pos == 0 && fold_affected_mask(ctx, op, s_mask & ~s_mask_old)) {
Richard Henderson045ace32024-12-19 10:33:51 -08002567 return true;
Richard Henderson57fe5c62021-08-26 12:04:46 -07002568 }
2569
Richard Hendersonbaff5072024-12-08 21:09:30 -06002570 z_mask = sextract64(t1->z_mask, pos, len);
2571 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Hendersonb6617c82021-08-24 10:44:53 -07002572}
2573
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002574static bool fold_shift(OptContext *ctx, TCGOp *op)
2575{
Richard Henderson4ed2ba32024-12-19 19:38:54 -08002576 uint64_t s_mask, z_mask;
Richard Henderson4e9ce6a2024-12-08 21:13:41 -06002577 TempOptInfo *t1, *t2;
Richard Henderson93a967f2021-08-26 13:24:59 -07002578
Richard Hendersona63ce0e2021-08-25 20:28:53 -07002579 if (fold_const2(ctx, op) ||
Richard Hendersonda48e272021-08-25 20:42:04 -07002580 fold_ix_to_i(ctx, op, 0) ||
Richard Hendersona63ce0e2021-08-25 20:28:53 -07002581 fold_xi_to_x(ctx, op, 0)) {
2582 return true;
2583 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07002584
Richard Henderson4e9ce6a2024-12-08 21:13:41 -06002585 t1 = arg_info(op->args[1]);
2586 t2 = arg_info(op->args[2]);
2587 s_mask = t1->s_mask;
2588 z_mask = t1->z_mask;
Richard Henderson93a967f2021-08-26 13:24:59 -07002589
Richard Henderson4e9ce6a2024-12-08 21:13:41 -06002590 if (ti_is_const(t2)) {
2591 int sh = ti_const_val(t2);
Richard Henderson93a967f2021-08-26 13:24:59 -07002592
Richard Henderson4e9ce6a2024-12-08 21:13:41 -06002593 z_mask = do_constant_folding(op->opc, ctx->type, z_mask, sh);
Richard Henderson93a967f2021-08-26 13:24:59 -07002594 s_mask = do_constant_folding(op->opc, ctx->type, s_mask, sh);
Richard Henderson93a967f2021-08-26 13:24:59 -07002595
Richard Henderson4e9ce6a2024-12-08 21:13:41 -06002596 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Hendersonfae450b2021-08-25 22:42:19 -07002597 }
Richard Henderson93a967f2021-08-26 13:24:59 -07002598
2599 switch (op->opc) {
2600 CASE_OP_32_64(sar):
2601 /*
2602 * Arithmetic right shift will not reduce the number of
2603 * input sign repetitions.
2604 */
Richard Henderson4e9ce6a2024-12-08 21:13:41 -06002605 return fold_masks_s(ctx, op, s_mask);
Richard Henderson93a967f2021-08-26 13:24:59 -07002606 CASE_OP_32_64(shr):
2607 /*
2608 * If the sign bit is known zero, then logical right shift
Richard Henderson4e9ce6a2024-12-08 21:13:41 -06002609 * will not reduce the number of input sign repetitions.
Richard Henderson93a967f2021-08-26 13:24:59 -07002610 */
Richard Henderson4ed2ba32024-12-19 19:38:54 -08002611 if (~z_mask & -s_mask) {
Richard Henderson4e9ce6a2024-12-08 21:13:41 -06002612 return fold_masks_s(ctx, op, s_mask);
Richard Henderson93a967f2021-08-26 13:24:59 -07002613 }
2614 break;
2615 default:
2616 break;
2617 }
2618
Richard Henderson4e9ce6a2024-12-08 21:13:41 -06002619 return finish_folding(ctx, op);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002620}
2621
Richard Henderson9caca882021-08-24 13:30:32 -07002622static bool fold_sub_to_neg(OptContext *ctx, TCGOp *op)
2623{
2624 TCGOpcode neg_op;
2625 bool have_neg;
2626
2627 if (!arg_is_const(op->args[1]) || arg_info(op->args[1])->val != 0) {
2628 return false;
2629 }
2630
2631 switch (ctx->type) {
2632 case TCG_TYPE_I32:
Richard Henderson9caca882021-08-24 13:30:32 -07002633 case TCG_TYPE_I64:
Richard Henderson69713582025-01-06 22:48:57 -08002634 neg_op = INDEX_op_neg;
Richard Hendersonb701f192023-10-25 21:14:04 -07002635 have_neg = true;
Richard Henderson9caca882021-08-24 13:30:32 -07002636 break;
2637 case TCG_TYPE_V64:
2638 case TCG_TYPE_V128:
2639 case TCG_TYPE_V256:
2640 neg_op = INDEX_op_neg_vec;
2641 have_neg = (TCG_TARGET_HAS_neg_vec &&
2642 tcg_can_emit_vec_op(neg_op, ctx->type, TCGOP_VECE(op)) > 0);
2643 break;
2644 default:
2645 g_assert_not_reached();
2646 }
2647 if (have_neg) {
2648 op->opc = neg_op;
2649 op->args[1] = op->args[2];
Richard Hendersone25fe882024-04-04 20:53:50 +00002650 return fold_neg_no_const(ctx, op);
Richard Henderson9caca882021-08-24 13:30:32 -07002651 }
2652 return false;
2653}
2654
Richard Hendersonc578ff12021-12-16 06:07:25 -08002655/* We cannot as yet do_constant_folding with vectors. */
2656static bool fold_sub_vec(OptContext *ctx, TCGOp *op)
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002657{
Richard Hendersonc578ff12021-12-16 06:07:25 -08002658 if (fold_xx_to_i(ctx, op, 0) ||
Richard Hendersona63ce0e2021-08-25 20:28:53 -07002659 fold_xi_to_x(ctx, op, 0) ||
Richard Henderson9caca882021-08-24 13:30:32 -07002660 fold_sub_to_neg(ctx, op)) {
Richard Hendersoncbe42fb2021-08-25 13:02:00 -07002661 return true;
2662 }
Richard Hendersonfe1d0072024-12-08 21:15:22 -06002663 return finish_folding(ctx, op);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002664}
2665
Richard Hendersonc578ff12021-12-16 06:07:25 -08002666static bool fold_sub(OptContext *ctx, TCGOp *op)
2667{
Richard Hendersonfe1d0072024-12-08 21:15:22 -06002668 if (fold_const2(ctx, op) ||
2669 fold_xx_to_i(ctx, op, 0) ||
2670 fold_xi_to_x(ctx, op, 0) ||
2671 fold_sub_to_neg(ctx, op)) {
Richard Henderson6334a962023-10-25 18:39:43 -07002672 return true;
2673 }
2674
2675 /* Fold sub r,x,i to add r,x,-i */
2676 if (arg_is_const(op->args[2])) {
2677 uint64_t val = arg_info(op->args[2])->val;
2678
Richard Henderson79602f62025-01-06 09:11:39 -08002679 op->opc = INDEX_op_add;
Richard Henderson6334a962023-10-25 18:39:43 -07002680 op->args[2] = arg_new_constant(ctx, -val);
2681 }
Richard Hendersonfe1d0072024-12-08 21:15:22 -06002682 return finish_folding(ctx, op);
Richard Hendersonc578ff12021-12-16 06:07:25 -08002683}
2684
Richard Henderson9531c072021-08-26 06:51:39 -07002685static bool fold_sub2(OptContext *ctx, TCGOp *op)
Richard Hendersone3f7dc22021-08-24 10:30:38 -07002686{
Richard Henderson9531c072021-08-26 06:51:39 -07002687 return fold_addsub2(ctx, op, false);
Richard Hendersone3f7dc22021-08-24 10:30:38 -07002688}
2689
Richard Hendersonfae450b2021-08-25 22:42:19 -07002690static bool fold_tcg_ld(OptContext *ctx, TCGOp *op)
2691{
Richard Hendersond33e0f02024-12-09 08:53:20 -06002692 uint64_t z_mask = -1, s_mask = 0;
2693
Richard Hendersonfae450b2021-08-25 22:42:19 -07002694 /* We can't do any folding with a load, but we can record bits. */
2695 switch (op->opc) {
Richard Henderson57fe5c62021-08-26 12:04:46 -07002696 CASE_OP_32_64(ld8s):
Richard Hendersond33e0f02024-12-09 08:53:20 -06002697 s_mask = INT8_MIN;
Richard Henderson57fe5c62021-08-26 12:04:46 -07002698 break;
Richard Hendersonfae450b2021-08-25 22:42:19 -07002699 CASE_OP_32_64(ld8u):
Richard Hendersond33e0f02024-12-09 08:53:20 -06002700 z_mask = MAKE_64BIT_MASK(0, 8);
Richard Henderson57fe5c62021-08-26 12:04:46 -07002701 break;
2702 CASE_OP_32_64(ld16s):
Richard Hendersond33e0f02024-12-09 08:53:20 -06002703 s_mask = INT16_MIN;
Richard Hendersonfae450b2021-08-25 22:42:19 -07002704 break;
2705 CASE_OP_32_64(ld16u):
Richard Hendersond33e0f02024-12-09 08:53:20 -06002706 z_mask = MAKE_64BIT_MASK(0, 16);
Richard Henderson57fe5c62021-08-26 12:04:46 -07002707 break;
2708 case INDEX_op_ld32s_i64:
Richard Hendersond33e0f02024-12-09 08:53:20 -06002709 s_mask = INT32_MIN;
Richard Hendersonfae450b2021-08-25 22:42:19 -07002710 break;
2711 case INDEX_op_ld32u_i64:
Richard Hendersond33e0f02024-12-09 08:53:20 -06002712 z_mask = MAKE_64BIT_MASK(0, 32);
Richard Hendersonfae450b2021-08-25 22:42:19 -07002713 break;
2714 default:
2715 g_assert_not_reached();
2716 }
Richard Hendersond33e0f02024-12-09 08:53:20 -06002717 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Hendersonfae450b2021-08-25 22:42:19 -07002718}
2719
Richard Hendersonab84dc32023-08-23 23:04:24 -07002720static bool fold_tcg_ld_memcopy(OptContext *ctx, TCGOp *op)
2721{
2722 TCGTemp *dst, *src;
2723 intptr_t ofs;
2724 TCGType type;
2725
2726 if (op->args[1] != tcgv_ptr_arg(tcg_env)) {
Richard Henderson0fb5b752024-12-09 09:44:40 -06002727 return finish_folding(ctx, op);
Richard Hendersonab84dc32023-08-23 23:04:24 -07002728 }
2729
2730 type = ctx->type;
2731 ofs = op->args[2];
2732 dst = arg_temp(op->args[0]);
2733 src = find_mem_copy_for(ctx, type, ofs);
2734 if (src && src->base_type == type) {
2735 return tcg_opt_gen_mov(ctx, op, temp_arg(dst), temp_arg(src));
2736 }
2737
2738 reset_ts(ctx, dst);
2739 record_mem_copy(ctx, type, dst, ofs, ofs + tcg_type_size(type) - 1);
2740 return true;
2741}
2742
2743static bool fold_tcg_st(OptContext *ctx, TCGOp *op)
2744{
2745 intptr_t ofs = op->args[2];
2746 intptr_t lm1;
2747
2748 if (op->args[1] != tcgv_ptr_arg(tcg_env)) {
2749 remove_mem_copy_all(ctx);
Richard Henderson082b3ef2024-12-08 20:34:57 -06002750 return true;
Richard Hendersonab84dc32023-08-23 23:04:24 -07002751 }
2752
2753 switch (op->opc) {
2754 CASE_OP_32_64(st8):
2755 lm1 = 0;
2756 break;
2757 CASE_OP_32_64(st16):
2758 lm1 = 1;
2759 break;
2760 case INDEX_op_st32_i64:
2761 case INDEX_op_st_i32:
2762 lm1 = 3;
2763 break;
2764 case INDEX_op_st_i64:
2765 lm1 = 7;
2766 break;
2767 case INDEX_op_st_vec:
2768 lm1 = tcg_type_size(ctx->type) - 1;
2769 break;
2770 default:
2771 g_assert_not_reached();
2772 }
2773 remove_mem_copy_in(ctx, ofs, ofs + lm1);
Richard Henderson082b3ef2024-12-08 20:34:57 -06002774 return true;
Richard Hendersonab84dc32023-08-23 23:04:24 -07002775}
2776
2777static bool fold_tcg_st_memcopy(OptContext *ctx, TCGOp *op)
2778{
2779 TCGTemp *src;
2780 intptr_t ofs, last;
2781 TCGType type;
2782
2783 if (op->args[1] != tcgv_ptr_arg(tcg_env)) {
Richard Henderson082b3ef2024-12-08 20:34:57 -06002784 return fold_tcg_st(ctx, op);
Richard Hendersonab84dc32023-08-23 23:04:24 -07002785 }
2786
2787 src = arg_temp(op->args[0]);
2788 ofs = op->args[2];
2789 type = ctx->type;
Richard Henderson3eaadae2023-08-23 23:13:06 -07002790
2791 /*
2792 * Eliminate duplicate stores of a constant.
2793 * This happens frequently when the target ISA zero-extends.
2794 */
2795 if (ts_is_const(src)) {
2796 TCGTemp *prev = find_mem_copy_for(ctx, type, ofs);
2797 if (src == prev) {
2798 tcg_op_remove(ctx->tcg, op);
2799 return true;
2800 }
2801 }
2802
Richard Hendersonab84dc32023-08-23 23:04:24 -07002803 last = ofs + tcg_type_size(type) - 1;
2804 remove_mem_copy_in(ctx, ofs, last);
2805 record_mem_copy(ctx, type, src, ofs, last);
Richard Henderson082b3ef2024-12-08 20:34:57 -06002806 return true;
Richard Hendersonab84dc32023-08-23 23:04:24 -07002807}
2808
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002809static bool fold_xor(OptContext *ctx, TCGOp *op)
2810{
Richard Hendersonc890fd72024-12-08 21:39:01 -06002811 uint64_t z_mask, s_mask;
2812 TempOptInfo *t1, *t2;
2813
Richard Henderson7a2f7082021-08-26 07:06:39 -07002814 if (fold_const2_commutative(ctx, op) ||
Richard Henderson0e0a32b2021-08-24 13:18:01 -07002815 fold_xx_to_i(ctx, op, 0) ||
Richard Hendersona63ce0e2021-08-25 20:28:53 -07002816 fold_xi_to_x(ctx, op, 0) ||
Richard Henderson0e0a32b2021-08-24 13:18:01 -07002817 fold_xi_to_not(ctx, op, -1)) {
Richard Hendersoncbe42fb2021-08-25 13:02:00 -07002818 return true;
2819 }
Richard Hendersonfae450b2021-08-25 22:42:19 -07002820
Richard Hendersonc890fd72024-12-08 21:39:01 -06002821 t1 = arg_info(op->args[1]);
2822 t2 = arg_info(op->args[2]);
2823 z_mask = t1->z_mask | t2->z_mask;
2824 s_mask = t1->s_mask & t2->s_mask;
2825 return fold_masks_zs(ctx, op, z_mask, s_mask);
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002826}
2827
Kirill Batuzov22613af2011-07-07 16:37:13 +04002828/* Propagate constants and copies, fold constant expressions. */
Aurelien Jarno36e60ef2015-06-04 21:53:27 +02002829void tcg_optimize(TCGContext *s)
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +04002830{
Richard Henderson5cf32be2021-08-24 08:17:08 -07002831 int nb_temps, i;
Richard Hendersond0ed5152021-08-24 07:38:39 -07002832 TCGOp *op, *op_next;
Richard Hendersondc849882021-08-24 07:13:45 -07002833 OptContext ctx = { .tcg = s };
Richard Henderson5d8f5362012-09-21 10:13:38 -07002834
Richard Hendersonab84dc32023-08-23 23:04:24 -07002835 QSIMPLEQ_INIT(&ctx.mem_free);
2836
Kirill Batuzov22613af2011-07-07 16:37:13 +04002837 /* Array VALS has an element for each temp.
2838 If this temp holds a constant then its value is kept in VALS' element.
Aurelien Jarnoe590d4e2012-09-11 12:31:21 +02002839 If this temp is a copy of other ones then the other copies are
2840 available through the doubly linked circular list. */
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +04002841
2842 nb_temps = s->nb_temps;
Richard Henderson8f17a972020-03-30 19:52:02 -07002843 for (i = 0; i < nb_temps; ++i) {
2844 s->temps[i].state_ptr = NULL;
2845 }
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +04002846
Richard Henderson15fa08f2017-11-02 15:19:14 +01002847 QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
Richard Hendersonc45cb8b2014-09-19 13:49:15 -07002848 TCGOpcode opc = op->opc;
Richard Henderson5cf32be2021-08-24 08:17:08 -07002849 const TCGOpDef *def;
Richard Henderson404a1482021-08-24 11:08:21 -07002850 bool done = false;
Richard Hendersonc45cb8b2014-09-19 13:49:15 -07002851
Richard Henderson5cf32be2021-08-24 08:17:08 -07002852 /* Calls are special. */
Richard Hendersonc45cb8b2014-09-19 13:49:15 -07002853 if (opc == INDEX_op_call) {
Richard Henderson5cf32be2021-08-24 08:17:08 -07002854 fold_call(&ctx, op);
2855 continue;
Richard Hendersoncf066672014-03-22 20:06:52 -07002856 }
Richard Henderson5cf32be2021-08-24 08:17:08 -07002857
2858 def = &tcg_op_defs[opc];
Richard Hendersonec5d4cb2021-08-24 08:20:27 -07002859 init_arguments(&ctx, op, def->nb_oargs + def->nb_iargs);
2860 copy_propagate(&ctx, op, def->nb_oargs, def->nb_iargs);
Kirill Batuzov22613af2011-07-07 16:37:13 +04002861
Richard Henderson67f84c92021-08-25 08:00:20 -07002862 /* Pre-compute the type of the operation. */
Richard Henderson4d872212025-01-02 19:43:06 -08002863 ctx.type = TCGOP_TYPE(op);
Richard Henderson67f84c92021-08-25 08:00:20 -07002864
Richard Henderson2cfac7f2021-08-25 13:05:43 -07002865 /*
2866 * Process each opcode.
2867 * Sorted alphabetically by opcode as much as possible.
2868 */
Richard Hendersonc45cb8b2014-09-19 13:49:15 -07002869 switch (opc) {
Richard Henderson79602f62025-01-06 09:11:39 -08002870 case INDEX_op_add:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002871 done = fold_add(&ctx, op);
2872 break;
Richard Hendersonc578ff12021-12-16 06:07:25 -08002873 case INDEX_op_add_vec:
2874 done = fold_add_vec(&ctx, op);
2875 break;
Richard Henderson9531c072021-08-26 06:51:39 -07002876 CASE_OP_32_64(add2):
2877 done = fold_add2(&ctx, op);
Richard Hendersone3f7dc22021-08-24 10:30:38 -07002878 break;
Richard Hendersonc3b920b2025-01-06 10:32:44 -08002879 case INDEX_op_and:
2880 case INDEX_op_and_vec:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002881 done = fold_and(&ctx, op);
2882 break;
Richard Henderson46f96bf2025-01-06 12:37:02 -08002883 case INDEX_op_andc:
2884 case INDEX_op_andc_vec:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002885 done = fold_andc(&ctx, op);
2886 break;
Richard Henderson079b0802021-08-24 09:30:59 -07002887 CASE_OP_32_64(brcond):
2888 done = fold_brcond(&ctx, op);
2889 break;
Richard Henderson764d2ab2021-08-24 09:22:11 -07002890 case INDEX_op_brcond2_i32:
2891 done = fold_brcond2(&ctx, op);
2892 break;
Richard Henderson09bacdc2021-08-24 11:58:12 -07002893 CASE_OP_32_64(bswap16):
2894 CASE_OP_32_64(bswap32):
2895 case INDEX_op_bswap64_i64:
2896 done = fold_bswap(&ctx, op);
2897 break;
Richard Henderson30dd0bf2021-08-24 10:51:34 -07002898 CASE_OP_32_64(clz):
2899 CASE_OP_32_64(ctz):
2900 done = fold_count_zeros(&ctx, op);
2901 break;
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002902 CASE_OP_32_64(ctpop):
2903 done = fold_ctpop(&ctx, op);
2904 break;
Richard Henderson1b1907b2021-08-24 10:47:04 -07002905 CASE_OP_32_64(deposit):
2906 done = fold_deposit(&ctx, op);
2907 break;
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002908 CASE_OP_32_64(div):
2909 CASE_OP_32_64(divu):
2910 done = fold_divide(&ctx, op);
2911 break;
Richard Henderson8cdb3fc2021-08-24 12:06:33 -07002912 case INDEX_op_dup_vec:
2913 done = fold_dup(&ctx, op);
2914 break;
2915 case INDEX_op_dup2_vec:
2916 done = fold_dup2(&ctx, op);
2917 break;
Richard Henderson5c0968a2025-01-06 15:47:53 -08002918 case INDEX_op_eqv:
2919 case INDEX_op_eqv_vec:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002920 done = fold_eqv(&ctx, op);
2921 break;
Richard Hendersonb6617c82021-08-24 10:44:53 -07002922 CASE_OP_32_64(extract):
2923 done = fold_extract(&ctx, op);
2924 break;
Richard Hendersondcd08992021-08-24 10:41:39 -07002925 CASE_OP_32_64(extract2):
2926 done = fold_extract2(&ctx, op);
2927 break;
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002928 case INDEX_op_ext_i32_i64:
2929 done = fold_exts(&ctx, op);
2930 break;
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002931 case INDEX_op_extu_i32_i64:
2932 case INDEX_op_extrl_i64_i32:
2933 case INDEX_op_extrh_i64_i32:
2934 done = fold_extu(&ctx, op);
2935 break;
Richard Henderson57fe5c62021-08-26 12:04:46 -07002936 CASE_OP_32_64(ld8s):
Richard Hendersonfae450b2021-08-25 22:42:19 -07002937 CASE_OP_32_64(ld8u):
Richard Henderson57fe5c62021-08-26 12:04:46 -07002938 CASE_OP_32_64(ld16s):
Richard Hendersonfae450b2021-08-25 22:42:19 -07002939 CASE_OP_32_64(ld16u):
Richard Henderson57fe5c62021-08-26 12:04:46 -07002940 case INDEX_op_ld32s_i64:
Richard Hendersonfae450b2021-08-25 22:42:19 -07002941 case INDEX_op_ld32u_i64:
2942 done = fold_tcg_ld(&ctx, op);
2943 break;
Richard Hendersonab84dc32023-08-23 23:04:24 -07002944 case INDEX_op_ld_i32:
2945 case INDEX_op_ld_i64:
2946 case INDEX_op_ld_vec:
2947 done = fold_tcg_ld_memcopy(&ctx, op);
2948 break;
2949 CASE_OP_32_64(st8):
2950 CASE_OP_32_64(st16):
2951 case INDEX_op_st32_i64:
2952 done = fold_tcg_st(&ctx, op);
2953 break;
2954 case INDEX_op_st_i32:
2955 case INDEX_op_st_i64:
2956 case INDEX_op_st_vec:
2957 done = fold_tcg_st_memcopy(&ctx, op);
2958 break;
Richard Henderson3eefdf22021-08-25 11:06:43 -07002959 case INDEX_op_mb:
2960 done = fold_mb(&ctx, op);
2961 break;
Richard Hendersonb5701262024-12-28 15:58:24 -08002962 case INDEX_op_mov:
2963 case INDEX_op_mov_vec:
Richard Henderson2cfac7f2021-08-25 13:05:43 -07002964 done = fold_mov(&ctx, op);
2965 break;
Richard Henderson0c310a32021-08-24 10:37:24 -07002966 CASE_OP_32_64(movcond):
2967 done = fold_movcond(&ctx, op);
2968 break;
Richard Hendersond2c3eca2025-01-07 09:32:18 -08002969 case INDEX_op_mul:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002970 done = fold_mul(&ctx, op);
2971 break;
Richard Hendersonc7428242025-01-07 11:19:29 -08002972 case INDEX_op_mulsh:
Richard Hendersonaa28c9e2025-01-07 10:36:24 -08002973 case INDEX_op_muluh:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002974 done = fold_mul_highpart(&ctx, op);
2975 break;
Richard Henderson407112b2021-08-26 06:33:04 -07002976 CASE_OP_32_64(muls2):
2977 CASE_OP_32_64(mulu2):
2978 done = fold_multiply2(&ctx, op);
Richard Henderson6b8ac0d2021-08-24 10:24:12 -07002979 break;
Richard Henderson59379a42025-01-06 20:32:54 -08002980 case INDEX_op_nand:
2981 case INDEX_op_nand_vec:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002982 done = fold_nand(&ctx, op);
2983 break;
Richard Henderson69713582025-01-06 22:48:57 -08002984 case INDEX_op_neg:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002985 done = fold_neg(&ctx, op);
2986 break;
Richard Henderson3a8c4e92025-01-06 21:02:17 -08002987 case INDEX_op_nor:
2988 case INDEX_op_nor_vec:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002989 done = fold_nor(&ctx, op);
2990 break;
Richard Henderson5c62d372025-01-06 23:46:47 -08002991 case INDEX_op_not:
2992 case INDEX_op_not_vec:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002993 done = fold_not(&ctx, op);
2994 break;
Richard Henderson49bd7512025-01-06 14:00:40 -08002995 case INDEX_op_or:
2996 case INDEX_op_or_vec:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07002997 done = fold_or(&ctx, op);
2998 break;
Richard Henderson6aba25e2025-01-06 14:46:26 -08002999 case INDEX_op_orc:
3000 case INDEX_op_orc_vec:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07003001 done = fold_orc(&ctx, op);
3002 break;
Richard Henderson50b7a192025-02-04 13:46:09 -08003003 case INDEX_op_qemu_ld_i32:
Richard Henderson6813be92024-12-08 20:33:30 -06003004 done = fold_qemu_ld_1reg(&ctx, op);
3005 break;
Richard Henderson50b7a192025-02-04 13:46:09 -08003006 case INDEX_op_qemu_ld_i64:
Richard Henderson6813be92024-12-08 20:33:30 -06003007 if (TCG_TARGET_REG_BITS == 64) {
3008 done = fold_qemu_ld_1reg(&ctx, op);
3009 break;
3010 }
3011 QEMU_FALLTHROUGH;
Richard Henderson50b7a192025-02-04 13:46:09 -08003012 case INDEX_op_qemu_ld_i128:
Richard Henderson6813be92024-12-08 20:33:30 -06003013 done = fold_qemu_ld_2reg(&ctx, op);
Richard Henderson3eefdf22021-08-25 11:06:43 -07003014 break;
Richard Henderson50b7a192025-02-04 13:46:09 -08003015 case INDEX_op_qemu_st8_i32:
3016 case INDEX_op_qemu_st_i32:
3017 case INDEX_op_qemu_st_i64:
3018 case INDEX_op_qemu_st_i128:
Richard Henderson3eefdf22021-08-25 11:06:43 -07003019 done = fold_qemu_st(&ctx, op);
3020 break;
Richard Henderson2f9f08b2021-08-25 12:03:48 -07003021 CASE_OP_32_64(rem):
3022 CASE_OP_32_64(remu):
3023 done = fold_remainder(&ctx, op);
3024 break;
3025 CASE_OP_32_64(rotl):
3026 CASE_OP_32_64(rotr):
3027 CASE_OP_32_64(sar):
3028 CASE_OP_32_64(shl):
3029 CASE_OP_32_64(shr):
3030 done = fold_shift(&ctx, op);
3031 break;
Richard Hendersonc63ff552021-08-24 09:35:30 -07003032 CASE_OP_32_64(setcond):
3033 done = fold_setcond(&ctx, op);
3034 break;
Richard Henderson36355022023-08-04 23:24:04 +00003035 CASE_OP_32_64(negsetcond):
3036 done = fold_negsetcond(&ctx, op);
3037 break;
Richard Hendersonbc47b1a2021-08-24 09:09:35 -07003038 case INDEX_op_setcond2_i32:
3039 done = fold_setcond2(&ctx, op);
3040 break;
Richard Henderson1f106542024-09-06 12:22:41 -07003041 case INDEX_op_cmp_vec:
3042 done = fold_cmp_vec(&ctx, op);
3043 break;
3044 case INDEX_op_cmpsel_vec:
3045 done = fold_cmpsel_vec(&ctx, op);
3046 break;
Richard Hendersone58b9772024-09-06 22:30:01 -07003047 case INDEX_op_bitsel_vec:
3048 done = fold_bitsel_vec(&ctx, op);
3049 break;
Richard Hendersonb6617c82021-08-24 10:44:53 -07003050 CASE_OP_32_64(sextract):
3051 done = fold_sextract(&ctx, op);
3052 break;
Richard Henderson60f34f52025-01-06 22:06:32 -08003053 case INDEX_op_sub:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07003054 done = fold_sub(&ctx, op);
3055 break;
Richard Hendersonc578ff12021-12-16 06:07:25 -08003056 case INDEX_op_sub_vec:
3057 done = fold_sub_vec(&ctx, op);
3058 break;
Richard Henderson9531c072021-08-26 06:51:39 -07003059 CASE_OP_32_64(sub2):
3060 done = fold_sub2(&ctx, op);
Richard Hendersone3f7dc22021-08-24 10:30:38 -07003061 break;
Richard Hendersonfffd3dc2025-01-06 15:18:35 -08003062 case INDEX_op_xor:
3063 case INDEX_op_xor_vec:
Richard Henderson2f9f08b2021-08-25 12:03:48 -07003064 done = fold_xor(&ctx, op);
Richard Hendersonb10f3832021-08-23 22:30:17 -07003065 break;
Richard Henderson15268552024-12-08 07:45:11 -06003066 case INDEX_op_set_label:
3067 case INDEX_op_br:
3068 case INDEX_op_exit_tb:
3069 case INDEX_op_goto_tb:
3070 case INDEX_op_goto_ptr:
3071 finish_ebb(&ctx);
3072 done = true;
3073 break;
Richard Henderson2cfac7f2021-08-25 13:05:43 -07003074 default:
Richard Henderson0ae56422024-12-08 21:42:53 -06003075 done = finish_folding(&ctx, op);
Richard Henderson2cfac7f2021-08-25 13:05:43 -07003076 break;
Richard Hendersonb10f3832021-08-23 22:30:17 -07003077 }
Richard Henderson0ae56422024-12-08 21:42:53 -06003078 tcg_debug_assert(done);
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +04003079 }
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +04003080}