blob: 3fec7fec5f5a3da8df1cc6e1e0de2137ddd5dee4 [file] [log] [blame]
Alexander Graf28278222009-12-05 12:44:23 +01001/*
2 * Tiny Code Generator for QEMU
3 *
4 * Copyright (c) 2009 Ulrich Hecht <uli@suse.de>
Richard Henderson48bb3752010-06-28 19:15:37 -07005 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
6 * Copyright (c) 2010 Richard Henderson <rth@twiddle.net>
Alexander Graf28278222009-12-05 12:44:23 +01007 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
Richard Hendersona01fc302013-03-26 16:39:50 -040027/* We only support generating code for 64-bit mode. */
28#if TCG_TARGET_REG_BITS != 64
29#error "unsupported code generation mode"
30#endif
31
Paolo Bonzini139c1832020-02-04 12:41:01 +010032#include "../tcg-pool.c.inc"
Richard Hendersonc9baa302013-06-07 07:43:33 -070033#include "elf.h"
34
Richard Henderson48bb3752010-06-28 19:15:37 -070035/* ??? The translation blocks produced by TCG are generally small enough to
36 be entirely reachable with a 16-bit displacement. Leaving the option for
37 a 32-bit displacement here Just In Case. */
38#define USE_LONG_BRANCHES 0
39
Richard Hendersona8f02692017-06-16 14:52:32 -070040#define TCG_CT_CONST_S16 0x100
41#define TCG_CT_CONST_S32 0x200
Richard Hendersona534bb12017-07-25 20:10:29 -040042#define TCG_CT_CONST_S33 0x400
43#define TCG_CT_CONST_ZERO 0x800
Richard Henderson48bb3752010-06-28 19:15:37 -070044
Richard Hendersonc947deb2020-10-16 20:09:02 -070045#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 16)
46/*
47 * For softmmu, we need to avoid conflicts with the first 3
48 * argument registers to perform the tlb lookup, and to call
49 * the helper function.
50 */
51#ifdef CONFIG_SOFTMMU
52#define SOFTMMU_RESERVE_REGS MAKE_64BIT_MASK(TCG_REG_R2, 3)
53#else
54#define SOFTMMU_RESERVE_REGS 0
55#endif
56
57
Richard Henderson48bb3752010-06-28 19:15:37 -070058/* Several places within the instruction set 0 means "no register"
59 rather than TCG_REG_R0. */
60#define TCG_REG_NONE 0
61
62/* A scratch register that may be be used throughout the backend. */
Richard Hendersonce411062016-11-16 16:10:37 +010063#define TCG_TMP0 TCG_REG_R1
Richard Henderson48bb3752010-06-28 19:15:37 -070064
Richard Henderson829e1372017-07-25 11:53:50 -070065/* A scratch register that holds a pointer to the beginning of the TB.
66 We don't need this when we have pc-relative loads with the general
67 instructions extension facility. */
68#define TCG_REG_TB TCG_REG_R12
69#define USE_REG_TB (!(s390_facilities & FACILITY_GEN_INST_EXT))
70
Laurent Vivier4cbea592015-08-24 01:42:07 +020071#ifndef CONFIG_SOFTMMU
Richard Henderson48bb3752010-06-28 19:15:37 -070072#define TCG_GUEST_BASE_REG TCG_REG_R13
Richard Henderson48bb3752010-06-28 19:15:37 -070073#endif
74
Richard Henderson48bb3752010-06-28 19:15:37 -070075/* All of the following instructions are prefixed with their instruction
76 format, and are defined as 8- or 16-bit quantities, even when the two
77 halves of the 16-bit quantity may appear 32 bits apart in the insn.
78 This makes it easy to copy the values from the tables in Appendix B. */
79typedef enum S390Opcode {
80 RIL_AFI = 0xc209,
81 RIL_AGFI = 0xc208,
Richard Henderson3790b912013-03-26 16:41:45 -040082 RIL_ALFI = 0xc20b,
Richard Henderson48bb3752010-06-28 19:15:37 -070083 RIL_ALGFI = 0xc20a,
84 RIL_BRASL = 0xc005,
85 RIL_BRCL = 0xc004,
86 RIL_CFI = 0xc20d,
87 RIL_CGFI = 0xc20c,
88 RIL_CLFI = 0xc20f,
89 RIL_CLGFI = 0xc20e,
Richard Hendersona534bb12017-07-25 20:10:29 -040090 RIL_CLRL = 0xc60f,
91 RIL_CLGRL = 0xc60a,
92 RIL_CRL = 0xc60d,
93 RIL_CGRL = 0xc608,
Richard Henderson48bb3752010-06-28 19:15:37 -070094 RIL_IIHF = 0xc008,
95 RIL_IILF = 0xc009,
96 RIL_LARL = 0xc000,
97 RIL_LGFI = 0xc001,
98 RIL_LGRL = 0xc408,
99 RIL_LLIHF = 0xc00e,
100 RIL_LLILF = 0xc00f,
101 RIL_LRL = 0xc40d,
102 RIL_MSFI = 0xc201,
103 RIL_MSGFI = 0xc200,
104 RIL_NIHF = 0xc00a,
105 RIL_NILF = 0xc00b,
106 RIL_OIHF = 0xc00c,
107 RIL_OILF = 0xc00d,
Richard Henderson3790b912013-03-26 16:41:45 -0400108 RIL_SLFI = 0xc205,
Richard Henderson0db921e2013-03-27 14:23:26 -0400109 RIL_SLGFI = 0xc204,
Richard Henderson48bb3752010-06-28 19:15:37 -0700110 RIL_XIHF = 0xc006,
111 RIL_XILF = 0xc007,
112
113 RI_AGHI = 0xa70b,
114 RI_AHI = 0xa70a,
115 RI_BRC = 0xa704,
Richard Hendersona534bb12017-07-25 20:10:29 -0400116 RI_CHI = 0xa70e,
117 RI_CGHI = 0xa70f,
Richard Henderson48bb3752010-06-28 19:15:37 -0700118 RI_IIHH = 0xa500,
119 RI_IIHL = 0xa501,
120 RI_IILH = 0xa502,
121 RI_IILL = 0xa503,
122 RI_LGHI = 0xa709,
123 RI_LLIHH = 0xa50c,
124 RI_LLIHL = 0xa50d,
125 RI_LLILH = 0xa50e,
126 RI_LLILL = 0xa50f,
127 RI_MGHI = 0xa70d,
128 RI_MHI = 0xa70c,
129 RI_NIHH = 0xa504,
130 RI_NIHL = 0xa505,
131 RI_NILH = 0xa506,
132 RI_NILL = 0xa507,
133 RI_OIHH = 0xa508,
134 RI_OIHL = 0xa509,
135 RI_OILH = 0xa50a,
136 RI_OILL = 0xa50b,
137
138 RIE_CGIJ = 0xec7c,
139 RIE_CGRJ = 0xec64,
140 RIE_CIJ = 0xec7e,
141 RIE_CLGRJ = 0xec65,
142 RIE_CLIJ = 0xec7f,
143 RIE_CLGIJ = 0xec7d,
144 RIE_CLRJ = 0xec77,
145 RIE_CRJ = 0xec76,
Richard Henderson7af525a2017-06-16 15:33:28 -0700146 RIE_LOCGHI = 0xec46,
Richard Hendersond5690ea2013-03-27 09:30:58 -0400147 RIE_RISBG = 0xec55,
Richard Henderson48bb3752010-06-28 19:15:37 -0700148
149 RRE_AGR = 0xb908,
Richard Henderson3790b912013-03-26 16:41:45 -0400150 RRE_ALGR = 0xb90a,
151 RRE_ALCR = 0xb998,
152 RRE_ALCGR = 0xb988,
Richard Henderson48bb3752010-06-28 19:15:37 -0700153 RRE_CGR = 0xb920,
154 RRE_CLGR = 0xb921,
155 RRE_DLGR = 0xb987,
156 RRE_DLR = 0xb997,
157 RRE_DSGFR = 0xb91d,
158 RRE_DSGR = 0xb90d,
Richard Hendersonce411062016-11-16 16:10:37 +0100159 RRE_FLOGR = 0xb983,
Richard Henderson48bb3752010-06-28 19:15:37 -0700160 RRE_LGBR = 0xb906,
161 RRE_LCGR = 0xb903,
162 RRE_LGFR = 0xb914,
163 RRE_LGHR = 0xb907,
164 RRE_LGR = 0xb904,
165 RRE_LLGCR = 0xb984,
166 RRE_LLGFR = 0xb916,
167 RRE_LLGHR = 0xb985,
168 RRE_LRVR = 0xb91f,
169 RRE_LRVGR = 0xb90f,
170 RRE_LTGR = 0xb902,
Richard Henderson36017dc2013-03-26 16:50:29 -0400171 RRE_MLGR = 0xb986,
Richard Henderson48bb3752010-06-28 19:15:37 -0700172 RRE_MSGR = 0xb90c,
173 RRE_MSR = 0xb252,
174 RRE_NGR = 0xb980,
175 RRE_OGR = 0xb981,
176 RRE_SGR = 0xb909,
Richard Henderson3790b912013-03-26 16:41:45 -0400177 RRE_SLGR = 0xb90b,
178 RRE_SLBR = 0xb999,
179 RRE_SLBGR = 0xb989,
Richard Henderson48bb3752010-06-28 19:15:37 -0700180 RRE_XGR = 0xb982,
181
Richard Henderson96a9f092013-03-26 17:28:52 -0400182 RRF_LOCR = 0xb9f2,
183 RRF_LOCGR = 0xb9e2,
Richard Hendersonc2097132017-06-16 13:43:17 -0700184 RRF_NRK = 0xb9f4,
185 RRF_NGRK = 0xb9e4,
186 RRF_ORK = 0xb9f6,
187 RRF_OGRK = 0xb9e6,
188 RRF_SRK = 0xb9f9,
189 RRF_SGRK = 0xb9e9,
190 RRF_SLRK = 0xb9fb,
191 RRF_SLGRK = 0xb9eb,
192 RRF_XRK = 0xb9f7,
193 RRF_XGRK = 0xb9e7,
Richard Henderson96a9f092013-03-26 17:28:52 -0400194
Richard Henderson48bb3752010-06-28 19:15:37 -0700195 RR_AR = 0x1a,
Richard Henderson3790b912013-03-26 16:41:45 -0400196 RR_ALR = 0x1e,
Richard Henderson48bb3752010-06-28 19:15:37 -0700197 RR_BASR = 0x0d,
198 RR_BCR = 0x07,
199 RR_CLR = 0x15,
200 RR_CR = 0x19,
201 RR_DR = 0x1d,
202 RR_LCR = 0x13,
203 RR_LR = 0x18,
204 RR_LTR = 0x12,
205 RR_NR = 0x14,
206 RR_OR = 0x16,
207 RR_SR = 0x1b,
Richard Henderson3790b912013-03-26 16:41:45 -0400208 RR_SLR = 0x1f,
Richard Henderson48bb3752010-06-28 19:15:37 -0700209 RR_XR = 0x17,
210
211 RSY_RLL = 0xeb1d,
212 RSY_RLLG = 0xeb1c,
213 RSY_SLLG = 0xeb0d,
Richard Hendersonc2097132017-06-16 13:43:17 -0700214 RSY_SLLK = 0xebdf,
Richard Henderson48bb3752010-06-28 19:15:37 -0700215 RSY_SRAG = 0xeb0a,
Richard Hendersonc2097132017-06-16 13:43:17 -0700216 RSY_SRAK = 0xebdc,
Richard Henderson48bb3752010-06-28 19:15:37 -0700217 RSY_SRLG = 0xeb0c,
Richard Hendersonc2097132017-06-16 13:43:17 -0700218 RSY_SRLK = 0xebde,
Richard Henderson48bb3752010-06-28 19:15:37 -0700219
220 RS_SLL = 0x89,
221 RS_SRA = 0x8a,
222 RS_SRL = 0x88,
223
224 RXY_AG = 0xe308,
225 RXY_AY = 0xe35a,
226 RXY_CG = 0xe320,
Richard Hendersona534bb12017-07-25 20:10:29 -0400227 RXY_CLG = 0xe321,
228 RXY_CLY = 0xe355,
Richard Henderson48bb3752010-06-28 19:15:37 -0700229 RXY_CY = 0xe359,
Richard Henderson0db921e2013-03-27 14:23:26 -0400230 RXY_LAY = 0xe371,
Richard Henderson48bb3752010-06-28 19:15:37 -0700231 RXY_LB = 0xe376,
232 RXY_LG = 0xe304,
233 RXY_LGB = 0xe377,
234 RXY_LGF = 0xe314,
235 RXY_LGH = 0xe315,
236 RXY_LHY = 0xe378,
237 RXY_LLGC = 0xe390,
238 RXY_LLGF = 0xe316,
239 RXY_LLGH = 0xe391,
240 RXY_LMG = 0xeb04,
241 RXY_LRV = 0xe31e,
242 RXY_LRVG = 0xe30f,
243 RXY_LRVH = 0xe31f,
244 RXY_LY = 0xe358,
Richard Hendersonbdcd5d12017-07-25 18:59:13 -0400245 RXY_NG = 0xe380,
Richard Henderson4046d9c2017-07-25 19:21:36 -0400246 RXY_OG = 0xe381,
Richard Henderson48bb3752010-06-28 19:15:37 -0700247 RXY_STCY = 0xe372,
248 RXY_STG = 0xe324,
249 RXY_STHY = 0xe370,
250 RXY_STMG = 0xeb24,
251 RXY_STRV = 0xe33e,
252 RXY_STRVG = 0xe32f,
253 RXY_STRVH = 0xe33f,
254 RXY_STY = 0xe350,
Richard Henderson5bf67a92017-07-25 19:42:51 -0400255 RXY_XG = 0xe382,
Richard Henderson48bb3752010-06-28 19:15:37 -0700256
257 RX_A = 0x5a,
258 RX_C = 0x59,
259 RX_L = 0x58,
Richard Henderson0db921e2013-03-27 14:23:26 -0400260 RX_LA = 0x41,
Richard Henderson48bb3752010-06-28 19:15:37 -0700261 RX_LH = 0x48,
262 RX_ST = 0x50,
263 RX_STC = 0x42,
264 RX_STH = 0x40,
Sergey Fedoroved3d51e2016-04-22 19:08:48 +0300265
266 NOP = 0x0707,
Richard Henderson48bb3752010-06-28 19:15:37 -0700267} S390Opcode;
268
Aurelien Jarno8d8fdba2016-04-21 10:48:50 +0200269#ifdef CONFIG_DEBUG_TCG
Richard Henderson48bb3752010-06-28 19:15:37 -0700270static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
271 "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
272 "%r8", "%r9", "%r10" "%r11" "%r12" "%r13" "%r14" "%r15"
273};
274#endif
275
276/* Since R6 is a potential argument register, choose it last of the
277 call-saved registers. Likewise prefer the call-clobbered registers
278 in reverse order to maximize the chance of avoiding the arguments. */
Alexander Graf28278222009-12-05 12:44:23 +0100279static const int tcg_target_reg_alloc_order[] = {
Richard Hendersonf24efee2014-03-23 13:36:00 -0700280 /* Call saved registers. */
Richard Henderson48bb3752010-06-28 19:15:37 -0700281 TCG_REG_R13,
282 TCG_REG_R12,
283 TCG_REG_R11,
284 TCG_REG_R10,
285 TCG_REG_R9,
286 TCG_REG_R8,
287 TCG_REG_R7,
288 TCG_REG_R6,
Richard Hendersonf24efee2014-03-23 13:36:00 -0700289 /* Call clobbered registers. */
Richard Henderson48bb3752010-06-28 19:15:37 -0700290 TCG_REG_R14,
291 TCG_REG_R0,
292 TCG_REG_R1,
Richard Hendersonf24efee2014-03-23 13:36:00 -0700293 /* Argument registers, in reverse order of allocation. */
Richard Henderson48bb3752010-06-28 19:15:37 -0700294 TCG_REG_R5,
295 TCG_REG_R4,
296 TCG_REG_R3,
297 TCG_REG_R2,
Alexander Graf28278222009-12-05 12:44:23 +0100298};
299
300static const int tcg_target_call_iarg_regs[] = {
Richard Henderson48bb3752010-06-28 19:15:37 -0700301 TCG_REG_R2,
302 TCG_REG_R3,
303 TCG_REG_R4,
304 TCG_REG_R5,
305 TCG_REG_R6,
Alexander Graf28278222009-12-05 12:44:23 +0100306};
307
308static const int tcg_target_call_oarg_regs[] = {
Richard Henderson48bb3752010-06-28 19:15:37 -0700309 TCG_REG_R2,
Alexander Graf28278222009-12-05 12:44:23 +0100310};
311
Richard Henderson48bb3752010-06-28 19:15:37 -0700312#define S390_CC_EQ 8
313#define S390_CC_LT 4
314#define S390_CC_GT 2
315#define S390_CC_OV 1
316#define S390_CC_NE (S390_CC_LT | S390_CC_GT)
317#define S390_CC_LE (S390_CC_LT | S390_CC_EQ)
318#define S390_CC_GE (S390_CC_GT | S390_CC_EQ)
319#define S390_CC_NEVER 0
320#define S390_CC_ALWAYS 15
321
322/* Condition codes that result from a COMPARE and COMPARE LOGICAL. */
Richard Henderson0aed2572012-09-24 14:21:40 -0700323static const uint8_t tcg_cond_to_s390_cond[] = {
Richard Henderson48bb3752010-06-28 19:15:37 -0700324 [TCG_COND_EQ] = S390_CC_EQ,
325 [TCG_COND_NE] = S390_CC_NE,
326 [TCG_COND_LT] = S390_CC_LT,
327 [TCG_COND_LE] = S390_CC_LE,
328 [TCG_COND_GT] = S390_CC_GT,
329 [TCG_COND_GE] = S390_CC_GE,
330 [TCG_COND_LTU] = S390_CC_LT,
331 [TCG_COND_LEU] = S390_CC_LE,
332 [TCG_COND_GTU] = S390_CC_GT,
333 [TCG_COND_GEU] = S390_CC_GE,
334};
335
336/* Condition codes that result from a LOAD AND TEST. Here, we have no
337 unsigned instruction variation, however since the test is vs zero we
338 can re-map the outcomes appropriately. */
Richard Henderson0aed2572012-09-24 14:21:40 -0700339static const uint8_t tcg_cond_to_ltr_cond[] = {
Richard Henderson48bb3752010-06-28 19:15:37 -0700340 [TCG_COND_EQ] = S390_CC_EQ,
341 [TCG_COND_NE] = S390_CC_NE,
342 [TCG_COND_LT] = S390_CC_LT,
343 [TCG_COND_LE] = S390_CC_LE,
344 [TCG_COND_GT] = S390_CC_GT,
345 [TCG_COND_GE] = S390_CC_GE,
346 [TCG_COND_LTU] = S390_CC_NEVER,
347 [TCG_COND_LEU] = S390_CC_EQ,
348 [TCG_COND_GTU] = S390_CC_NE,
349 [TCG_COND_GEU] = S390_CC_ALWAYS,
350};
351
352#ifdef CONFIG_SOFTMMU
Richard Hendersonf24efee2014-03-23 13:36:00 -0700353static void * const qemu_ld_helpers[16] = {
354 [MO_UB] = helper_ret_ldub_mmu,
355 [MO_SB] = helper_ret_ldsb_mmu,
356 [MO_LEUW] = helper_le_lduw_mmu,
357 [MO_LESW] = helper_le_ldsw_mmu,
358 [MO_LEUL] = helper_le_ldul_mmu,
359 [MO_LESL] = helper_le_ldsl_mmu,
360 [MO_LEQ] = helper_le_ldq_mmu,
361 [MO_BEUW] = helper_be_lduw_mmu,
362 [MO_BESW] = helper_be_ldsw_mmu,
363 [MO_BEUL] = helper_be_ldul_mmu,
364 [MO_BESL] = helper_be_ldsl_mmu,
365 [MO_BEQ] = helper_be_ldq_mmu,
Blue Swirle141ab52011-09-18 14:55:46 +0000366};
367
Richard Hendersonf24efee2014-03-23 13:36:00 -0700368static void * const qemu_st_helpers[16] = {
369 [MO_UB] = helper_ret_stb_mmu,
370 [MO_LEUW] = helper_le_stw_mmu,
371 [MO_LEUL] = helper_le_stl_mmu,
372 [MO_LEQ] = helper_le_stq_mmu,
373 [MO_BEUW] = helper_be_stw_mmu,
374 [MO_BEUL] = helper_be_stl_mmu,
375 [MO_BEQ] = helper_be_stq_mmu,
Blue Swirle141ab52011-09-18 14:55:46 +0000376};
Blue Swirle141ab52011-09-18 14:55:46 +0000377#endif
Richard Henderson48bb3752010-06-28 19:15:37 -0700378
Richard Henderson79dae4d2020-11-04 20:56:16 -0800379static const tcg_insn_unit *tb_ret_addr;
Richard Hendersonb2c98d92016-10-17 11:24:38 -0400380uint64_t s390_facilities;
Richard Henderson48bb3752010-06-28 19:15:37 -0700381
Richard Henderson79dae4d2020-11-04 20:56:16 -0800382static bool patch_reloc(tcg_insn_unit *src_rw, int type,
Richard Henderson2ba7fae22013-08-20 15:30:10 -0700383 intptr_t value, intptr_t addend)
Alexander Graf28278222009-12-05 12:44:23 +0100384{
Richard Henderson79dae4d2020-11-04 20:56:16 -0800385 const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw);
Richard Hendersone692a342017-07-30 13:58:01 -0700386 intptr_t pcrel2;
Richard Henderson28eef8a2017-07-31 19:16:02 -0700387 uint32_t old;
Richard Hendersone692a342017-07-30 13:58:01 -0700388
389 value += addend;
Richard Henderson79dae4d2020-11-04 20:56:16 -0800390 pcrel2 = (tcg_insn_unit *)value - src_rx;
Richard Henderson48bb3752010-06-28 19:15:37 -0700391
392 switch (type) {
393 case R_390_PC16DBL:
Richard Henderson55dfd8f2018-11-30 21:41:51 +0000394 if (pcrel2 == (int16_t)pcrel2) {
Richard Henderson79dae4d2020-11-04 20:56:16 -0800395 tcg_patch16(src_rw, pcrel2);
Richard Henderson55dfd8f2018-11-30 21:41:51 +0000396 return true;
397 }
Richard Henderson48bb3752010-06-28 19:15:37 -0700398 break;
399 case R_390_PC32DBL:
Richard Henderson55dfd8f2018-11-30 21:41:51 +0000400 if (pcrel2 == (int32_t)pcrel2) {
Richard Henderson79dae4d2020-11-04 20:56:16 -0800401 tcg_patch32(src_rw, pcrel2);
Richard Henderson55dfd8f2018-11-30 21:41:51 +0000402 return true;
403 }
Richard Henderson48bb3752010-06-28 19:15:37 -0700404 break;
Richard Henderson28eef8a2017-07-31 19:16:02 -0700405 case R_390_20:
Richard Henderson55dfd8f2018-11-30 21:41:51 +0000406 if (value == sextract64(value, 0, 20)) {
Richard Henderson79dae4d2020-11-04 20:56:16 -0800407 old = *(uint32_t *)src_rw & 0xf00000ff;
Richard Henderson55dfd8f2018-11-30 21:41:51 +0000408 old |= ((value & 0xfff) << 16) | ((value & 0xff000) >> 4);
Richard Henderson79dae4d2020-11-04 20:56:16 -0800409 tcg_patch32(src_rw, old);
Richard Henderson55dfd8f2018-11-30 21:41:51 +0000410 return true;
411 }
Richard Henderson28eef8a2017-07-31 19:16:02 -0700412 break;
Richard Henderson48bb3752010-06-28 19:15:37 -0700413 default:
Richard Hendersone692a342017-07-30 13:58:01 -0700414 g_assert_not_reached();
Richard Henderson48bb3752010-06-28 19:15:37 -0700415 }
Richard Henderson55dfd8f2018-11-30 21:41:51 +0000416 return false;
Alexander Graf28278222009-12-05 12:44:23 +0100417}
418
Alexander Graf28278222009-12-05 12:44:23 +0100419/* Test if a constant matches the constraint. */
Richard Hendersonf6c6afc2014-03-30 21:22:11 -0700420static int tcg_target_const_match(tcg_target_long val, TCGType type,
Richard Henderson48bb3752010-06-28 19:15:37 -0700421 const TCGArgConstraint *arg_ct)
Alexander Graf28278222009-12-05 12:44:23 +0100422{
Richard Henderson48bb3752010-06-28 19:15:37 -0700423 int ct = arg_ct->ct;
424
425 if (ct & TCG_CT_CONST) {
426 return 1;
427 }
428
Richard Henderson671c8352014-03-31 02:25:26 -0400429 if (type == TCG_TYPE_I32) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700430 val = (int32_t)val;
431 }
432
433 /* The following are mutually exclusive. */
Richard Hendersona8f02692017-06-16 14:52:32 -0700434 if (ct & TCG_CT_CONST_S16) {
435 return val == (int16_t)val;
436 } else if (ct & TCG_CT_CONST_S32) {
437 return val == (int32_t)val;
Richard Hendersonba18b072017-06-16 14:59:55 -0700438 } else if (ct & TCG_CT_CONST_S33) {
439 return val >= -0xffffffffll && val <= 0xffffffffll;
Richard Henderson752b1be2016-10-17 17:00:46 -0700440 } else if (ct & TCG_CT_CONST_ZERO) {
441 return val == 0;
Richard Henderson48bb3752010-06-28 19:15:37 -0700442 }
443
Alexander Graf28278222009-12-05 12:44:23 +0100444 return 0;
445}
446
Richard Henderson48bb3752010-06-28 19:15:37 -0700447/* Emit instructions according to the given instruction format. */
448
449static void tcg_out_insn_RR(TCGContext *s, S390Opcode op, TCGReg r1, TCGReg r2)
Alexander Graf28278222009-12-05 12:44:23 +0100450{
Richard Henderson48bb3752010-06-28 19:15:37 -0700451 tcg_out16(s, (op << 8) | (r1 << 4) | r2);
Alexander Graf28278222009-12-05 12:44:23 +0100452}
453
Richard Henderson48bb3752010-06-28 19:15:37 -0700454static void tcg_out_insn_RRE(TCGContext *s, S390Opcode op,
455 TCGReg r1, TCGReg r2)
456{
457 tcg_out32(s, (op << 16) | (r1 << 4) | r2);
458}
459
Richard Henderson96a9f092013-03-26 17:28:52 -0400460static void tcg_out_insn_RRF(TCGContext *s, S390Opcode op,
461 TCGReg r1, TCGReg r2, int m3)
462{
463 tcg_out32(s, (op << 16) | (m3 << 12) | (r1 << 4) | r2);
464}
465
Richard Henderson48bb3752010-06-28 19:15:37 -0700466static void tcg_out_insn_RI(TCGContext *s, S390Opcode op, TCGReg r1, int i2)
467{
468 tcg_out32(s, (op << 16) | (r1 << 20) | (i2 & 0xffff));
469}
470
Richard Henderson7af525a2017-06-16 15:33:28 -0700471static void tcg_out_insn_RIE(TCGContext *s, S390Opcode op, TCGReg r1,
472 int i2, int m3)
473{
474 tcg_out16(s, (op & 0xff00) | (r1 << 4) | m3);
475 tcg_out32(s, (i2 << 16) | (op & 0xff));
476}
477
Richard Henderson48bb3752010-06-28 19:15:37 -0700478static void tcg_out_insn_RIL(TCGContext *s, S390Opcode op, TCGReg r1, int i2)
479{
480 tcg_out16(s, op | (r1 << 4));
481 tcg_out32(s, i2);
482}
483
484static void tcg_out_insn_RS(TCGContext *s, S390Opcode op, TCGReg r1,
485 TCGReg b2, TCGReg r3, int disp)
486{
487 tcg_out32(s, (op << 24) | (r1 << 20) | (r3 << 16) | (b2 << 12)
488 | (disp & 0xfff));
489}
490
491static void tcg_out_insn_RSY(TCGContext *s, S390Opcode op, TCGReg r1,
492 TCGReg b2, TCGReg r3, int disp)
493{
494 tcg_out16(s, (op & 0xff00) | (r1 << 4) | r3);
495 tcg_out32(s, (op & 0xff) | (b2 << 28)
496 | ((disp & 0xfff) << 16) | ((disp & 0xff000) >> 4));
497}
498
499#define tcg_out_insn_RX tcg_out_insn_RS
500#define tcg_out_insn_RXY tcg_out_insn_RSY
501
502/* Emit an opcode with "type-checking" of the format. */
503#define tcg_out_insn(S, FMT, OP, ...) \
504 glue(tcg_out_insn_,FMT)(S, glue(glue(FMT,_),OP), ## __VA_ARGS__)
505
506
507/* emit 64-bit shifts */
508static void tcg_out_sh64(TCGContext* s, S390Opcode op, TCGReg dest,
509 TCGReg src, TCGReg sh_reg, int sh_imm)
510{
511 tcg_out_insn_RSY(s, op, dest, sh_reg, src, sh_imm);
512}
513
514/* emit 32-bit shifts */
515static void tcg_out_sh32(TCGContext* s, S390Opcode op, TCGReg dest,
516 TCGReg sh_reg, int sh_imm)
517{
518 tcg_out_insn_RS(s, op, dest, sh_reg, 0, sh_imm);
519}
520
Richard Henderson78113e82019-03-16 17:48:18 +0000521static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg dst, TCGReg src)
Richard Henderson48bb3752010-06-28 19:15:37 -0700522{
523 if (src != dst) {
524 if (type == TCG_TYPE_I32) {
525 tcg_out_insn(s, RR, LR, dst, src);
526 } else {
527 tcg_out_insn(s, RRE, LGR, dst, src);
528 }
529 }
Richard Henderson78113e82019-03-16 17:48:18 +0000530 return true;
Richard Henderson48bb3752010-06-28 19:15:37 -0700531}
532
Richard Henderson28eef8a2017-07-31 19:16:02 -0700533static const S390Opcode lli_insns[4] = {
534 RI_LLILL, RI_LLILH, RI_LLIHL, RI_LLIHH
535};
Richard Henderson48bb3752010-06-28 19:15:37 -0700536
Richard Henderson28eef8a2017-07-31 19:16:02 -0700537static bool maybe_out_small_movi(TCGContext *s, TCGType type,
538 TCGReg ret, tcg_target_long sval)
539{
Richard Henderson48bb3752010-06-28 19:15:37 -0700540 tcg_target_ulong uval = sval;
541 int i;
542
543 if (type == TCG_TYPE_I32) {
544 uval = (uint32_t)sval;
545 sval = (int32_t)sval;
546 }
547
548 /* Try all 32-bit insns that can load it in one go. */
549 if (sval >= -0x8000 && sval < 0x8000) {
550 tcg_out_insn(s, RI, LGHI, ret, sval);
Richard Henderson28eef8a2017-07-31 19:16:02 -0700551 return true;
Richard Henderson48bb3752010-06-28 19:15:37 -0700552 }
553
554 for (i = 0; i < 4; i++) {
555 tcg_target_long mask = 0xffffull << i*16;
556 if ((uval & mask) == uval) {
557 tcg_out_insn_RI(s, lli_insns[i], ret, uval >> i*16);
Richard Henderson28eef8a2017-07-31 19:16:02 -0700558 return true;
Richard Henderson48bb3752010-06-28 19:15:37 -0700559 }
560 }
561
Richard Henderson28eef8a2017-07-31 19:16:02 -0700562 return false;
563}
564
565/* load a register with an immediate value */
566static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret,
567 tcg_target_long sval, bool in_prologue)
568{
569 tcg_target_ulong uval;
570
571 /* Try all 32-bit insns that can load it in one go. */
572 if (maybe_out_small_movi(s, type, ret, sval)) {
573 return;
574 }
575
576 uval = sval;
577 if (type == TCG_TYPE_I32) {
578 uval = (uint32_t)sval;
579 sval = (int32_t)sval;
580 }
581
Richard Henderson48bb3752010-06-28 19:15:37 -0700582 /* Try all 48-bit insns that can load it in one go. */
Richard Hendersonb2c98d92016-10-17 11:24:38 -0400583 if (s390_facilities & FACILITY_EXT_IMM) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700584 if (sval == (int32_t)sval) {
585 tcg_out_insn(s, RIL, LGFI, ret, sval);
586 return;
587 }
588 if (uval <= 0xffffffff) {
589 tcg_out_insn(s, RIL, LLILF, ret, uval);
590 return;
591 }
592 if ((uval & 0xffffffff) == 0) {
Richard Henderson28eef8a2017-07-31 19:16:02 -0700593 tcg_out_insn(s, RIL, LLIHF, ret, uval >> 32);
Richard Henderson48bb3752010-06-28 19:15:37 -0700594 return;
595 }
596 }
597
Richard Henderson829e1372017-07-25 11:53:50 -0700598 /* Try for PC-relative address load. For odd addresses,
599 attempt to use an offset from the start of the TB. */
Richard Henderson48bb3752010-06-28 19:15:37 -0700600 if ((sval & 1) == 0) {
Richard Henderson8c081b12014-04-25 10:18:59 -0400601 ptrdiff_t off = tcg_pcrel_diff(s, (void *)sval) >> 1;
Richard Henderson48bb3752010-06-28 19:15:37 -0700602 if (off == (int32_t)off) {
603 tcg_out_insn(s, RIL, LARL, ret, off);
604 return;
605 }
Richard Henderson829e1372017-07-25 11:53:50 -0700606 } else if (USE_REG_TB && !in_prologue) {
Richard Hendersondd900432020-11-04 18:00:35 -0800607 ptrdiff_t off = tcg_tbrel_diff(s, (void *)sval);
Richard Henderson829e1372017-07-25 11:53:50 -0700608 if (off == sextract64(off, 0, 20)) {
609 /* This is certain to be an address within TB, and therefore
610 OFF will be negative; don't try RX_LA. */
611 tcg_out_insn(s, RXY, LAY, ret, TCG_REG_TB, TCG_REG_NONE, off);
612 return;
613 }
Richard Henderson48bb3752010-06-28 19:15:37 -0700614 }
615
Richard Henderson28eef8a2017-07-31 19:16:02 -0700616 /* A 32-bit unsigned value can be loaded in 2 insns. And given
617 that LLILL, LLIHL, LLILF above did not succeed, we know that
618 both insns are required. */
619 if (uval <= 0xffffffff) {
620 tcg_out_insn(s, RI, LLILL, ret, uval);
621 tcg_out_insn(s, RI, IILH, ret, uval >> 16);
622 return;
Richard Henderson48bb3752010-06-28 19:15:37 -0700623 }
624
Richard Hendersonba2c7472017-10-25 18:03:27 +0200625 /* Otherwise, stuff it in the constant pool. */
626 if (s390_facilities & FACILITY_GEN_INST_EXT) {
627 tcg_out_insn(s, RIL, LGRL, ret, 0);
628 new_pool_label(s, sval, R_390_PC32DBL, s->code_ptr - 2, 2);
629 } else if (USE_REG_TB && !in_prologue) {
630 tcg_out_insn(s, RXY, LG, ret, TCG_REG_TB, TCG_REG_NONE, 0);
631 new_pool_label(s, sval, R_390_20, s->code_ptr - 2,
Richard Hendersondd900432020-11-04 18:00:35 -0800632 tcg_tbrel_diff(s, NULL));
Richard Henderson48bb3752010-06-28 19:15:37 -0700633 } else {
Richard Hendersonba2c7472017-10-25 18:03:27 +0200634 TCGReg base = ret ? ret : TCG_TMP0;
635 tcg_out_insn(s, RIL, LARL, base, 0);
636 new_pool_label(s, sval, R_390_PC32DBL, s->code_ptr - 2, 2);
637 tcg_out_insn(s, RXY, LG, ret, base, TCG_REG_NONE, 0);
Richard Henderson48bb3752010-06-28 19:15:37 -0700638 }
639}
640
Richard Henderson829e1372017-07-25 11:53:50 -0700641static void tcg_out_movi(TCGContext *s, TCGType type,
642 TCGReg ret, tcg_target_long sval)
643{
644 tcg_out_movi_int(s, type, ret, sval, false);
645}
Richard Henderson48bb3752010-06-28 19:15:37 -0700646
647/* Emit a load/store type instruction. Inputs are:
648 DATA: The register to be loaded or stored.
649 BASE+OFS: The effective address.
650 OPC_RX: If the operation has an RX format opcode (e.g. STC), otherwise 0.
651 OPC_RXY: The RXY format opcode for the operation (e.g. STCY). */
652
653static void tcg_out_mem(TCGContext *s, S390Opcode opc_rx, S390Opcode opc_rxy,
654 TCGReg data, TCGReg base, TCGReg index,
655 tcg_target_long ofs)
656{
657 if (ofs < -0x80000 || ofs >= 0x80000) {
Richard Henderson78c9f7c2013-03-27 14:37:42 -0400658 /* Combine the low 20 bits of the offset with the actual load insn;
659 the high 44 bits must come from an immediate load. */
660 tcg_target_long low = ((ofs & 0xfffff) ^ 0x80000) - 0x80000;
661 tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, ofs - low);
662 ofs = low;
Richard Henderson48bb3752010-06-28 19:15:37 -0700663
664 /* If we were already given an index register, add it in. */
665 if (index != TCG_REG_NONE) {
666 tcg_out_insn(s, RRE, AGR, TCG_TMP0, index);
667 }
668 index = TCG_TMP0;
669 }
670
671 if (opc_rx && ofs >= 0 && ofs < 0x1000) {
672 tcg_out_insn_RX(s, opc_rx, data, base, index, ofs);
673 } else {
674 tcg_out_insn_RXY(s, opc_rxy, data, base, index, ofs);
675 }
676}
677
678
Alexander Graf28278222009-12-05 12:44:23 +0100679/* load data without address translation or endianness conversion */
Richard Henderson48bb3752010-06-28 19:15:37 -0700680static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg data,
Richard Hendersona05b5b92013-08-20 17:07:26 -0700681 TCGReg base, intptr_t ofs)
Alexander Graf28278222009-12-05 12:44:23 +0100682{
Richard Henderson48bb3752010-06-28 19:15:37 -0700683 if (type == TCG_TYPE_I32) {
684 tcg_out_mem(s, RX_L, RXY_LY, data, base, TCG_REG_NONE, ofs);
685 } else {
686 tcg_out_mem(s, 0, RXY_LG, data, base, TCG_REG_NONE, ofs);
687 }
Alexander Graf28278222009-12-05 12:44:23 +0100688}
689
Richard Henderson48bb3752010-06-28 19:15:37 -0700690static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg data,
Richard Hendersona05b5b92013-08-20 17:07:26 -0700691 TCGReg base, intptr_t ofs)
Alexander Graf28278222009-12-05 12:44:23 +0100692{
Richard Henderson48bb3752010-06-28 19:15:37 -0700693 if (type == TCG_TYPE_I32) {
694 tcg_out_mem(s, RX_ST, RXY_STY, data, base, TCG_REG_NONE, ofs);
695 } else {
696 tcg_out_mem(s, 0, RXY_STG, data, base, TCG_REG_NONE, ofs);
697 }
Alexander Graf28278222009-12-05 12:44:23 +0100698}
699
Richard Henderson59d7c142016-06-19 22:59:13 -0700700static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
701 TCGReg base, intptr_t ofs)
702{
703 return false;
704}
705
Richard Henderson48bb3752010-06-28 19:15:37 -0700706/* load data from an absolute host address */
Richard Henderson79dae4d2020-11-04 20:56:16 -0800707static void tcg_out_ld_abs(TCGContext *s, TCGType type,
708 TCGReg dest, const void *abs)
Richard Henderson48bb3752010-06-28 19:15:37 -0700709{
Richard Henderson8c081b12014-04-25 10:18:59 -0400710 intptr_t addr = (intptr_t)abs;
Richard Henderson48bb3752010-06-28 19:15:37 -0700711
Richard Hendersonb2c98d92016-10-17 11:24:38 -0400712 if ((s390_facilities & FACILITY_GEN_INST_EXT) && !(addr & 1)) {
Richard Henderson8c081b12014-04-25 10:18:59 -0400713 ptrdiff_t disp = tcg_pcrel_diff(s, abs) >> 1;
Richard Henderson48bb3752010-06-28 19:15:37 -0700714 if (disp == (int32_t)disp) {
715 if (type == TCG_TYPE_I32) {
716 tcg_out_insn(s, RIL, LRL, dest, disp);
717 } else {
718 tcg_out_insn(s, RIL, LGRL, dest, disp);
719 }
720 return;
721 }
722 }
Richard Henderson829e1372017-07-25 11:53:50 -0700723 if (USE_REG_TB) {
Richard Hendersondd900432020-11-04 18:00:35 -0800724 ptrdiff_t disp = tcg_tbrel_diff(s, abs);
Richard Henderson829e1372017-07-25 11:53:50 -0700725 if (disp == sextract64(disp, 0, 20)) {
726 tcg_out_ld(s, type, dest, TCG_REG_TB, disp);
727 return;
728 }
729 }
Richard Henderson48bb3752010-06-28 19:15:37 -0700730
731 tcg_out_movi(s, TCG_TYPE_PTR, dest, addr & ~0xffff);
732 tcg_out_ld(s, type, dest, dest, addr & 0xffff);
733}
734
Richard Hendersonf0bffc22013-03-27 12:28:22 -0400735static inline void tcg_out_risbg(TCGContext *s, TCGReg dest, TCGReg src,
736 int msb, int lsb, int ofs, int z)
737{
738 /* Format RIE-f */
739 tcg_out16(s, (RIE_RISBG & 0xff00) | (dest << 4) | src);
740 tcg_out16(s, (msb << 8) | (z << 7) | lsb);
741 tcg_out16(s, (ofs << 8) | (RIE_RISBG & 0xff));
742}
743
Richard Henderson48bb3752010-06-28 19:15:37 -0700744static void tgen_ext8s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
745{
Richard Hendersonb2c98d92016-10-17 11:24:38 -0400746 if (s390_facilities & FACILITY_EXT_IMM) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700747 tcg_out_insn(s, RRE, LGBR, dest, src);
748 return;
749 }
750
751 if (type == TCG_TYPE_I32) {
752 if (dest == src) {
753 tcg_out_sh32(s, RS_SLL, dest, TCG_REG_NONE, 24);
754 } else {
755 tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 24);
756 }
757 tcg_out_sh32(s, RS_SRA, dest, TCG_REG_NONE, 24);
758 } else {
759 tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 56);
760 tcg_out_sh64(s, RSY_SRAG, dest, dest, TCG_REG_NONE, 56);
761 }
762}
763
764static void tgen_ext8u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
765{
Richard Hendersonb2c98d92016-10-17 11:24:38 -0400766 if (s390_facilities & FACILITY_EXT_IMM) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700767 tcg_out_insn(s, RRE, LLGCR, dest, src);
768 return;
769 }
770
771 if (dest == src) {
772 tcg_out_movi(s, type, TCG_TMP0, 0xff);
773 src = TCG_TMP0;
774 } else {
775 tcg_out_movi(s, type, dest, 0xff);
776 }
777 if (type == TCG_TYPE_I32) {
778 tcg_out_insn(s, RR, NR, dest, src);
779 } else {
780 tcg_out_insn(s, RRE, NGR, dest, src);
781 }
782}
783
784static void tgen_ext16s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
785{
Richard Hendersonb2c98d92016-10-17 11:24:38 -0400786 if (s390_facilities & FACILITY_EXT_IMM) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700787 tcg_out_insn(s, RRE, LGHR, dest, src);
788 return;
789 }
790
791 if (type == TCG_TYPE_I32) {
792 if (dest == src) {
793 tcg_out_sh32(s, RS_SLL, dest, TCG_REG_NONE, 16);
794 } else {
795 tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 16);
796 }
797 tcg_out_sh32(s, RS_SRA, dest, TCG_REG_NONE, 16);
798 } else {
799 tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 48);
800 tcg_out_sh64(s, RSY_SRAG, dest, dest, TCG_REG_NONE, 48);
801 }
802}
803
804static void tgen_ext16u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
805{
Richard Hendersonb2c98d92016-10-17 11:24:38 -0400806 if (s390_facilities & FACILITY_EXT_IMM) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700807 tcg_out_insn(s, RRE, LLGHR, dest, src);
808 return;
809 }
810
811 if (dest == src) {
812 tcg_out_movi(s, type, TCG_TMP0, 0xffff);
813 src = TCG_TMP0;
814 } else {
815 tcg_out_movi(s, type, dest, 0xffff);
816 }
817 if (type == TCG_TYPE_I32) {
818 tcg_out_insn(s, RR, NR, dest, src);
819 } else {
820 tcg_out_insn(s, RRE, NGR, dest, src);
821 }
822}
823
824static inline void tgen_ext32s(TCGContext *s, TCGReg dest, TCGReg src)
825{
826 tcg_out_insn(s, RRE, LGFR, dest, src);
827}
828
829static inline void tgen_ext32u(TCGContext *s, TCGReg dest, TCGReg src)
830{
831 tcg_out_insn(s, RRE, LLGFR, dest, src);
832}
833
Richard Hendersonf0bffc22013-03-27 12:28:22 -0400834/* Accept bit patterns like these:
835 0....01....1
836 1....10....0
837 1..10..01..1
838 0..01..10..0
839 Copied from gcc sources. */
840static inline bool risbg_mask(uint64_t c)
841{
842 uint64_t lsb;
843 /* We don't change the number of transitions by inverting,
844 so make sure we start with the LSB zero. */
845 if (c & 1) {
846 c = ~c;
847 }
848 /* Reject all zeros or all ones. */
849 if (c == 0) {
850 return false;
851 }
852 /* Find the first transition. */
853 lsb = c & -c;
854 /* Invert to look for a second transition. */
855 c = ~c;
856 /* Erase the first transition. */
857 c &= -lsb;
858 /* Find the second transition, if any. */
859 lsb = c & -c;
860 /* Match if all the bits are 1's, or if c is zero. */
861 return c == -lsb;
862}
863
Richard Henderson547ec122014-03-23 19:35:44 -0400864static void tgen_andi_risbg(TCGContext *s, TCGReg out, TCGReg in, uint64_t val)
865{
866 int msb, lsb;
867 if ((val & 0x8000000000000001ull) == 0x8000000000000001ull) {
868 /* Achieve wraparound by swapping msb and lsb. */
869 msb = 64 - ctz64(~val);
870 lsb = clz64(~val) - 1;
871 } else {
872 msb = clz64(val);
873 lsb = 63 - ctz64(val);
874 }
875 tcg_out_risbg(s, out, in, msb, lsb, 0, 1);
876}
877
Richard Henderson07ff7982013-03-27 11:47:54 -0400878static void tgen_andi(TCGContext *s, TCGType type, TCGReg dest, uint64_t val)
Richard Henderson48bb3752010-06-28 19:15:37 -0700879{
880 static const S390Opcode ni_insns[4] = {
881 RI_NILL, RI_NILH, RI_NIHL, RI_NIHH
882 };
883 static const S390Opcode nif_insns[2] = {
884 RIL_NILF, RIL_NIHF
885 };
Richard Henderson07ff7982013-03-27 11:47:54 -0400886 uint64_t valid = (type == TCG_TYPE_I32 ? 0xffffffffull : -1ull);
Richard Henderson48bb3752010-06-28 19:15:37 -0700887 int i;
888
Richard Henderson48bb3752010-06-28 19:15:37 -0700889 /* Look for the zero-extensions. */
Richard Henderson07ff7982013-03-27 11:47:54 -0400890 if ((val & valid) == 0xffffffff) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700891 tgen_ext32u(s, dest, dest);
892 return;
893 }
Richard Hendersonb2c98d92016-10-17 11:24:38 -0400894 if (s390_facilities & FACILITY_EXT_IMM) {
Richard Henderson07ff7982013-03-27 11:47:54 -0400895 if ((val & valid) == 0xff) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700896 tgen_ext8u(s, TCG_TYPE_I64, dest, dest);
897 return;
898 }
Richard Henderson07ff7982013-03-27 11:47:54 -0400899 if ((val & valid) == 0xffff) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700900 tgen_ext16u(s, TCG_TYPE_I64, dest, dest);
901 return;
902 }
Richard Henderson07ff7982013-03-27 11:47:54 -0400903 }
Richard Henderson48bb3752010-06-28 19:15:37 -0700904
Richard Henderson07ff7982013-03-27 11:47:54 -0400905 /* Try all 32-bit insns that can perform it in one go. */
906 for (i = 0; i < 4; i++) {
907 tcg_target_ulong mask = ~(0xffffull << i*16);
908 if (((val | ~valid) & mask) == mask) {
909 tcg_out_insn_RI(s, ni_insns[i], dest, val >> i*16);
910 return;
911 }
912 }
913
914 /* Try all 48-bit insns that can perform it in one go. */
Richard Hendersonb2c98d92016-10-17 11:24:38 -0400915 if (s390_facilities & FACILITY_EXT_IMM) {
Richard Henderson07ff7982013-03-27 11:47:54 -0400916 for (i = 0; i < 2; i++) {
917 tcg_target_ulong mask = ~(0xffffffffull << i*32);
918 if (((val | ~valid) & mask) == mask) {
919 tcg_out_insn_RIL(s, nif_insns[i], dest, val >> i*32);
Richard Henderson48bb3752010-06-28 19:15:37 -0700920 return;
921 }
922 }
Richard Henderson07ff7982013-03-27 11:47:54 -0400923 }
Richard Hendersonb2c98d92016-10-17 11:24:38 -0400924 if ((s390_facilities & FACILITY_GEN_INST_EXT) && risbg_mask(val)) {
Richard Henderson547ec122014-03-23 19:35:44 -0400925 tgen_andi_risbg(s, dest, dest, val);
Richard Hendersonf0bffc22013-03-27 12:28:22 -0400926 return;
927 }
Richard Henderson48bb3752010-06-28 19:15:37 -0700928
Richard Hendersonbdcd5d12017-07-25 18:59:13 -0400929 /* Use the constant pool if USE_REG_TB, but not for small constants. */
930 if (USE_REG_TB) {
931 if (!maybe_out_small_movi(s, type, TCG_TMP0, val)) {
932 tcg_out_insn(s, RXY, NG, dest, TCG_REG_TB, TCG_REG_NONE, 0);
933 new_pool_label(s, val & valid, R_390_20, s->code_ptr - 2,
Richard Hendersondd900432020-11-04 18:00:35 -0800934 tcg_tbrel_diff(s, NULL));
Richard Hendersonbdcd5d12017-07-25 18:59:13 -0400935 return;
936 }
937 } else {
938 tcg_out_movi(s, type, TCG_TMP0, val);
939 }
Richard Henderson07ff7982013-03-27 11:47:54 -0400940 if (type == TCG_TYPE_I32) {
941 tcg_out_insn(s, RR, NR, dest, TCG_TMP0);
Richard Henderson48bb3752010-06-28 19:15:37 -0700942 } else {
Richard Henderson07ff7982013-03-27 11:47:54 -0400943 tcg_out_insn(s, RRE, NGR, dest, TCG_TMP0);
Richard Henderson48bb3752010-06-28 19:15:37 -0700944 }
945}
946
Richard Henderson4046d9c2017-07-25 19:21:36 -0400947static void tgen_ori(TCGContext *s, TCGType type, TCGReg dest, uint64_t val)
Richard Henderson48bb3752010-06-28 19:15:37 -0700948{
949 static const S390Opcode oi_insns[4] = {
950 RI_OILL, RI_OILH, RI_OIHL, RI_OIHH
951 };
Richard Henderson4046d9c2017-07-25 19:21:36 -0400952 static const S390Opcode oif_insns[2] = {
Richard Henderson48bb3752010-06-28 19:15:37 -0700953 RIL_OILF, RIL_OIHF
954 };
955
956 int i;
957
958 /* Look for no-op. */
Richard Henderson4046d9c2017-07-25 19:21:36 -0400959 if (unlikely(val == 0)) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700960 return;
961 }
962
Richard Henderson4046d9c2017-07-25 19:21:36 -0400963 /* Try all 32-bit insns that can perform it in one go. */
964 for (i = 0; i < 4; i++) {
965 tcg_target_ulong mask = (0xffffull << i*16);
966 if ((val & mask) != 0 && (val & ~mask) == 0) {
967 tcg_out_insn_RI(s, oi_insns[i], dest, val >> i*16);
968 return;
Richard Henderson48bb3752010-06-28 19:15:37 -0700969 }
Richard Henderson4046d9c2017-07-25 19:21:36 -0400970 }
Richard Henderson48bb3752010-06-28 19:15:37 -0700971
Richard Henderson4046d9c2017-07-25 19:21:36 -0400972 /* Try all 48-bit insns that can perform it in one go. */
973 if (s390_facilities & FACILITY_EXT_IMM) {
Richard Henderson48bb3752010-06-28 19:15:37 -0700974 for (i = 0; i < 2; i++) {
975 tcg_target_ulong mask = (0xffffffffull << i*32);
976 if ((val & mask) != 0 && (val & ~mask) == 0) {
Richard Henderson4046d9c2017-07-25 19:21:36 -0400977 tcg_out_insn_RIL(s, oif_insns[i], dest, val >> i*32);
Richard Henderson48bb3752010-06-28 19:15:37 -0700978 return;
979 }
980 }
Richard Henderson4046d9c2017-07-25 19:21:36 -0400981 }
Richard Henderson48bb3752010-06-28 19:15:37 -0700982
Richard Henderson4046d9c2017-07-25 19:21:36 -0400983 /* Use the constant pool if USE_REG_TB, but not for small constants. */
984 if (maybe_out_small_movi(s, type, TCG_TMP0, val)) {
985 if (type == TCG_TYPE_I32) {
986 tcg_out_insn(s, RR, OR, dest, TCG_TMP0);
987 } else {
988 tcg_out_insn(s, RRE, OGR, dest, TCG_TMP0);
989 }
990 } else if (USE_REG_TB) {
991 tcg_out_insn(s, RXY, OG, dest, TCG_REG_TB, TCG_REG_NONE, 0);
992 new_pool_label(s, val, R_390_20, s->code_ptr - 2,
Richard Hendersondd900432020-11-04 18:00:35 -0800993 tcg_tbrel_diff(s, NULL));
Richard Henderson4046d9c2017-07-25 19:21:36 -0400994 } else {
Richard Henderson48bb3752010-06-28 19:15:37 -0700995 /* Perform the OR via sequential modifications to the high and
996 low parts. Do this via recursion to handle 16-bit vs 32-bit
997 masks in each half. */
Richard Henderson4046d9c2017-07-25 19:21:36 -0400998 tcg_debug_assert(s390_facilities & FACILITY_EXT_IMM);
999 tgen_ori(s, type, dest, val & 0x00000000ffffffffull);
1000 tgen_ori(s, type, dest, val & 0xffffffff00000000ull);
Richard Henderson48bb3752010-06-28 19:15:37 -07001001 }
1002}
1003
Richard Henderson5bf67a92017-07-25 19:42:51 -04001004static void tgen_xori(TCGContext *s, TCGType type, TCGReg dest, uint64_t val)
Richard Henderson48bb3752010-06-28 19:15:37 -07001005{
Richard Henderson5bf67a92017-07-25 19:42:51 -04001006 /* Try all 48-bit insns that can perform it in one go. */
1007 if (s390_facilities & FACILITY_EXT_IMM) {
1008 if ((val & 0xffffffff00000000ull) == 0) {
1009 tcg_out_insn(s, RIL, XILF, dest, val);
1010 return;
1011 }
1012 if ((val & 0x00000000ffffffffull) == 0) {
1013 tcg_out_insn(s, RIL, XIHF, dest, val >> 32);
1014 return;
1015 }
Richard Henderson48bb3752010-06-28 19:15:37 -07001016 }
Richard Henderson5bf67a92017-07-25 19:42:51 -04001017
1018 /* Use the constant pool if USE_REG_TB, but not for small constants. */
1019 if (maybe_out_small_movi(s, type, TCG_TMP0, val)) {
1020 if (type == TCG_TYPE_I32) {
1021 tcg_out_insn(s, RR, XR, dest, TCG_TMP0);
1022 } else {
1023 tcg_out_insn(s, RRE, XGR, dest, TCG_TMP0);
1024 }
1025 } else if (USE_REG_TB) {
1026 tcg_out_insn(s, RXY, XG, dest, TCG_REG_TB, TCG_REG_NONE, 0);
1027 new_pool_label(s, val, R_390_20, s->code_ptr - 2,
Richard Hendersondd900432020-11-04 18:00:35 -08001028 tcg_tbrel_diff(s, NULL));
Richard Henderson5bf67a92017-07-25 19:42:51 -04001029 } else {
1030 /* Perform the xor by parts. */
1031 tcg_debug_assert(s390_facilities & FACILITY_EXT_IMM);
1032 if (val & 0xffffffff) {
1033 tcg_out_insn(s, RIL, XILF, dest, val);
1034 }
1035 if (val > 0xffffffff) {
1036 tcg_out_insn(s, RIL, XIHF, dest, val >> 32);
1037 }
Richard Henderson48bb3752010-06-28 19:15:37 -07001038 }
1039}
1040
1041static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
Richard Henderson65839b52016-12-06 22:00:57 -05001042 TCGArg c2, bool c2const, bool need_carry)
Richard Henderson48bb3752010-06-28 19:15:37 -07001043{
Richard Hendersonbcc66562012-09-24 14:21:39 -07001044 bool is_unsigned = is_unsigned_cond(c);
Richard Hendersona534bb12017-07-25 20:10:29 -04001045 S390Opcode op;
1046
Richard Henderson48bb3752010-06-28 19:15:37 -07001047 if (c2const) {
1048 if (c2 == 0) {
Richard Henderson65839b52016-12-06 22:00:57 -05001049 if (!(is_unsigned && need_carry)) {
1050 if (type == TCG_TYPE_I32) {
1051 tcg_out_insn(s, RR, LTR, r1, r1);
1052 } else {
1053 tcg_out_insn(s, RRE, LTGR, r1, r1);
1054 }
1055 return tcg_cond_to_ltr_cond[c];
Richard Henderson48bb3752010-06-28 19:15:37 -07001056 }
Richard Hendersona534bb12017-07-25 20:10:29 -04001057 }
1058
1059 if (!is_unsigned && c2 == (int16_t)c2) {
1060 op = (type == TCG_TYPE_I32 ? RI_CHI : RI_CGHI);
1061 tcg_out_insn_RI(s, op, r1, c2);
1062 goto exit;
1063 }
1064
1065 if (s390_facilities & FACILITY_EXT_IMM) {
1066 if (type == TCG_TYPE_I32) {
1067 op = (is_unsigned ? RIL_CLFI : RIL_CFI);
1068 tcg_out_insn_RIL(s, op, r1, c2);
1069 goto exit;
1070 } else if (c2 == (is_unsigned ? (uint32_t)c2 : (int32_t)c2)) {
1071 op = (is_unsigned ? RIL_CLGFI : RIL_CGFI);
1072 tcg_out_insn_RIL(s, op, r1, c2);
1073 goto exit;
Richard Henderson65839b52016-12-06 22:00:57 -05001074 }
1075 }
Richard Hendersona534bb12017-07-25 20:10:29 -04001076
1077 /* Use the constant pool, but not for small constants. */
1078 if (maybe_out_small_movi(s, type, TCG_TMP0, c2)) {
1079 c2 = TCG_TMP0;
1080 /* fall through to reg-reg */
1081 } else if (USE_REG_TB) {
Richard Henderson65839b52016-12-06 22:00:57 -05001082 if (type == TCG_TYPE_I32) {
Richard Hendersona534bb12017-07-25 20:10:29 -04001083 op = (is_unsigned ? RXY_CLY : RXY_CY);
1084 tcg_out_insn_RXY(s, op, r1, TCG_REG_TB, TCG_REG_NONE, 0);
1085 new_pool_label(s, (uint32_t)c2, R_390_20, s->code_ptr - 2,
Richard Hendersondd900432020-11-04 18:00:35 -08001086 4 - tcg_tbrel_diff(s, NULL));
Richard Henderson48bb3752010-06-28 19:15:37 -07001087 } else {
Richard Hendersona534bb12017-07-25 20:10:29 -04001088 op = (is_unsigned ? RXY_CLG : RXY_CG);
1089 tcg_out_insn_RXY(s, op, r1, TCG_REG_TB, TCG_REG_NONE, 0);
1090 new_pool_label(s, c2, R_390_20, s->code_ptr - 2,
Richard Hendersondd900432020-11-04 18:00:35 -08001091 tcg_tbrel_diff(s, NULL));
Richard Henderson65839b52016-12-06 22:00:57 -05001092 }
Richard Hendersona534bb12017-07-25 20:10:29 -04001093 goto exit;
Richard Henderson65839b52016-12-06 22:00:57 -05001094 } else {
1095 if (type == TCG_TYPE_I32) {
Richard Hendersona534bb12017-07-25 20:10:29 -04001096 op = (is_unsigned ? RIL_CLRL : RIL_CRL);
1097 tcg_out_insn_RIL(s, op, r1, 0);
1098 new_pool_label(s, (uint32_t)c2, R_390_PC32DBL,
1099 s->code_ptr - 2, 2 + 4);
Richard Henderson65839b52016-12-06 22:00:57 -05001100 } else {
Richard Hendersona534bb12017-07-25 20:10:29 -04001101 op = (is_unsigned ? RIL_CLGRL : RIL_CGRL);
1102 tcg_out_insn_RIL(s, op, r1, 0);
1103 new_pool_label(s, c2, R_390_PC32DBL, s->code_ptr - 2, 2);
Richard Henderson48bb3752010-06-28 19:15:37 -07001104 }
Richard Hendersona534bb12017-07-25 20:10:29 -04001105 goto exit;
Richard Henderson48bb3752010-06-28 19:15:37 -07001106 }
1107 }
Richard Hendersona534bb12017-07-25 20:10:29 -04001108
1109 if (type == TCG_TYPE_I32) {
1110 op = (is_unsigned ? RR_CLR : RR_CR);
1111 tcg_out_insn_RR(s, op, r1, c2);
1112 } else {
1113 op = (is_unsigned ? RRE_CLGR : RRE_CGR);
1114 tcg_out_insn_RRE(s, op, r1, c2);
1115 }
1116
1117 exit:
Richard Henderson48bb3752010-06-28 19:15:37 -07001118 return tcg_cond_to_s390_cond[c];
1119}
1120
Richard Henderson7b7066b2014-03-31 12:57:06 -04001121static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
Richard Henderson96a9f092013-03-26 17:28:52 -04001122 TCGReg dest, TCGReg c1, TCGArg c2, int c2const)
Richard Henderson48bb3752010-06-28 19:15:37 -07001123{
Richard Henderson7b7066b2014-03-31 12:57:06 -04001124 int cc;
Richard Henderson7af525a2017-06-16 15:33:28 -07001125 bool have_loc;
Richard Henderson48bb3752010-06-28 19:15:37 -07001126
Richard Henderson7af525a2017-06-16 15:33:28 -07001127 /* With LOC2, we can always emit the minimum 3 insns. */
1128 if (s390_facilities & FACILITY_LOAD_ON_COND2) {
1129 /* Emit: d = 0, d = (cc ? 1 : d). */
1130 cc = tgen_cmp(s, type, cond, c1, c2, c2const, false);
1131 tcg_out_movi(s, TCG_TYPE_I64, dest, 0);
1132 tcg_out_insn(s, RIE, LOCGHI, dest, 1, cc);
1133 return;
1134 }
1135
1136 have_loc = (s390_facilities & FACILITY_LOAD_ON_COND) != 0;
1137
Richard Henderson46091902017-07-25 23:09:17 -04001138 /* For HAVE_LOC, only the paths through GTU/GT/LEU/LE are smaller. */
1139 restart:
Richard Henderson7b7066b2014-03-31 12:57:06 -04001140 switch (cond) {
Richard Henderson46091902017-07-25 23:09:17 -04001141 case TCG_COND_NE:
1142 /* X != 0 is X > 0. */
1143 if (c2const && c2 == 0) {
1144 cond = TCG_COND_GTU;
1145 } else {
1146 break;
1147 }
1148 /* fallthru */
1149
Richard Henderson7b7066b2014-03-31 12:57:06 -04001150 case TCG_COND_GTU:
1151 case TCG_COND_GT:
Richard Henderson7b7066b2014-03-31 12:57:06 -04001152 /* The result of a compare has CC=2 for GT and CC=3 unused.
1153 ADD LOGICAL WITH CARRY considers (CC & 2) the carry bit. */
Richard Henderson65839b52016-12-06 22:00:57 -05001154 tgen_cmp(s, type, cond, c1, c2, c2const, true);
Richard Henderson7b7066b2014-03-31 12:57:06 -04001155 tcg_out_movi(s, type, dest, 0);
1156 tcg_out_insn(s, RRE, ALCGR, dest, dest);
1157 return;
1158
Richard Henderson46091902017-07-25 23:09:17 -04001159 case TCG_COND_EQ:
1160 /* X == 0 is X <= 0. */
1161 if (c2const && c2 == 0) {
1162 cond = TCG_COND_LEU;
Richard Henderson7b7066b2014-03-31 12:57:06 -04001163 } else {
Richard Henderson46091902017-07-25 23:09:17 -04001164 break;
Richard Henderson7af525a2017-06-16 15:33:28 -07001165 }
1166 /* fallthru */
Richard Henderson46091902017-07-25 23:09:17 -04001167
1168 case TCG_COND_LEU:
1169 case TCG_COND_LE:
1170 /* As above, but we're looking for borrow, or !carry.
1171 The second insn computes d - d - borrow, or -1 for true
1172 and 0 for false. So we must mask to 1 bit afterward. */
1173 tgen_cmp(s, type, cond, c1, c2, c2const, true);
1174 tcg_out_insn(s, RRE, SLBGR, dest, dest);
1175 tgen_andi(s, type, dest, 1);
1176 return;
1177
1178 case TCG_COND_GEU:
Richard Henderson7b7066b2014-03-31 12:57:06 -04001179 case TCG_COND_LTU:
1180 case TCG_COND_LT:
Richard Henderson46091902017-07-25 23:09:17 -04001181 case TCG_COND_GE:
1182 /* Swap operands so that we can use LEU/GTU/GT/LE. */
Richard Henderson7b7066b2014-03-31 12:57:06 -04001183 if (c2const) {
Richard Henderson7af525a2017-06-16 15:33:28 -07001184 if (have_loc) {
Richard Henderson46091902017-07-25 23:09:17 -04001185 break;
Richard Henderson7af525a2017-06-16 15:33:28 -07001186 }
Richard Henderson7b7066b2014-03-31 12:57:06 -04001187 tcg_out_movi(s, type, TCG_TMP0, c2);
1188 c2 = c1;
1189 c2const = 0;
1190 c1 = TCG_TMP0;
1191 } else {
1192 TCGReg t = c1;
1193 c1 = c2;
1194 c2 = t;
1195 }
Richard Henderson7b7066b2014-03-31 12:57:06 -04001196 cond = tcg_swap_cond(cond);
Richard Henderson46091902017-07-25 23:09:17 -04001197 goto restart;
Richard Henderson7b7066b2014-03-31 12:57:06 -04001198
1199 default:
Richard Henderson46091902017-07-25 23:09:17 -04001200 g_assert_not_reached();
Richard Henderson7b7066b2014-03-31 12:57:06 -04001201 }
1202
Richard Henderson65839b52016-12-06 22:00:57 -05001203 cc = tgen_cmp(s, type, cond, c1, c2, c2const, false);
Richard Henderson46091902017-07-25 23:09:17 -04001204 if (have_loc) {
1205 /* Emit: d = 0, t = 1, d = (cc ? t : d). */
1206 tcg_out_movi(s, TCG_TYPE_I64, dest, 0);
1207 tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1);
1208 tcg_out_insn(s, RRF, LOCGR, dest, TCG_TMP0, cc);
1209 } else {
1210 /* Emit: d = 1; if (cc) goto over; d = 0; over: */
1211 tcg_out_movi(s, type, dest, 1);
1212 tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1);
1213 tcg_out_movi(s, type, dest, 0);
1214 }
Richard Henderson48bb3752010-06-28 19:15:37 -07001215}
1216
Richard Henderson96a9f092013-03-26 17:28:52 -04001217static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest,
Richard Henderson7af525a2017-06-16 15:33:28 -07001218 TCGReg c1, TCGArg c2, int c2const,
1219 TCGArg v3, int v3const)
Richard Henderson96a9f092013-03-26 17:28:52 -04001220{
1221 int cc;
Richard Hendersonb2c98d92016-10-17 11:24:38 -04001222 if (s390_facilities & FACILITY_LOAD_ON_COND) {
Richard Henderson65839b52016-12-06 22:00:57 -05001223 cc = tgen_cmp(s, type, c, c1, c2, c2const, false);
Richard Henderson7af525a2017-06-16 15:33:28 -07001224 if (v3const) {
1225 tcg_out_insn(s, RIE, LOCGHI, dest, v3, cc);
1226 } else {
1227 tcg_out_insn(s, RRF, LOCGR, dest, v3, cc);
1228 }
Richard Henderson96a9f092013-03-26 17:28:52 -04001229 } else {
1230 c = tcg_invert_cond(c);
Richard Henderson65839b52016-12-06 22:00:57 -05001231 cc = tgen_cmp(s, type, c, c1, c2, c2const, false);
Richard Henderson96a9f092013-03-26 17:28:52 -04001232
1233 /* Emit: if (cc) goto over; dest = r3; over: */
1234 tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1);
Richard Henderson7af525a2017-06-16 15:33:28 -07001235 tcg_out_insn(s, RRE, LGR, dest, v3);
Richard Henderson96a9f092013-03-26 17:28:52 -04001236 }
1237}
1238
Richard Hendersonce411062016-11-16 16:10:37 +01001239static void tgen_clz(TCGContext *s, TCGReg dest, TCGReg a1,
1240 TCGArg a2, int a2const)
1241{
1242 /* Since this sets both R and R+1, we have no choice but to store the
1243 result into R0, allowing R1 == TCG_TMP0 to be clobbered as well. */
1244 QEMU_BUILD_BUG_ON(TCG_TMP0 != TCG_REG_R1);
1245 tcg_out_insn(s, RRE, FLOGR, TCG_REG_R0, a1);
1246
1247 if (a2const && a2 == 64) {
1248 tcg_out_mov(s, TCG_TYPE_I64, dest, TCG_REG_R0);
1249 } else {
1250 if (a2const) {
1251 tcg_out_movi(s, TCG_TYPE_I64, dest, a2);
1252 } else {
1253 tcg_out_mov(s, TCG_TYPE_I64, dest, a2);
1254 }
1255 if (s390_facilities & FACILITY_LOAD_ON_COND) {
1256 /* Emit: if (one bit found) dest = r0. */
1257 tcg_out_insn(s, RRF, LOCGR, dest, TCG_REG_R0, 2);
1258 } else {
1259 /* Emit: if (no one bit found) goto over; dest = r0; over: */
1260 tcg_out_insn(s, RI, BRC, 8, (4 + 4) >> 1);
1261 tcg_out_insn(s, RRE, LGR, dest, TCG_REG_R0);
1262 }
1263 }
1264}
1265
Richard Hendersond5690ea2013-03-27 09:30:58 -04001266static void tgen_deposit(TCGContext *s, TCGReg dest, TCGReg src,
Richard Henderson752b1be2016-10-17 17:00:46 -07001267 int ofs, int len, int z)
Richard Hendersond5690ea2013-03-27 09:30:58 -04001268{
1269 int lsb = (63 - ofs);
1270 int msb = lsb - (len - 1);
Richard Henderson752b1be2016-10-17 17:00:46 -07001271 tcg_out_risbg(s, dest, src, msb, lsb, ofs, z);
Richard Hendersond5690ea2013-03-27 09:30:58 -04001272}
1273
Richard Hendersonb0bf5fe2016-10-14 14:26:40 -05001274static void tgen_extract(TCGContext *s, TCGReg dest, TCGReg src,
1275 int ofs, int len)
1276{
1277 tcg_out_risbg(s, dest, src, 64 - len, 63, 64 - ofs, 1);
1278}
1279
Richard Hendersonffd0e502020-10-30 15:55:28 -07001280static void tgen_gotoi(TCGContext *s, int cc, const tcg_insn_unit *dest)
Richard Henderson48bb3752010-06-28 19:15:37 -07001281{
Richard Henderson79dae4d2020-11-04 20:56:16 -08001282 ptrdiff_t off = tcg_pcrel_diff(s, dest) >> 1;
Richard Henderson8c081b12014-04-25 10:18:59 -04001283 if (off == (int16_t)off) {
Richard Henderson48bb3752010-06-28 19:15:37 -07001284 tcg_out_insn(s, RI, BRC, cc, off);
1285 } else if (off == (int32_t)off) {
1286 tcg_out_insn(s, RIL, BRCL, cc, off);
1287 } else {
Richard Henderson8c081b12014-04-25 10:18:59 -04001288 tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, (uintptr_t)dest);
Richard Henderson48bb3752010-06-28 19:15:37 -07001289 tcg_out_insn(s, RR, BCR, cc, TCG_TMP0);
1290 }
1291}
1292
Richard Hendersonbec16312015-02-13 13:39:54 -08001293static void tgen_branch(TCGContext *s, int cc, TCGLabel *l)
Richard Henderson48bb3752010-06-28 19:15:37 -07001294{
Richard Henderson48bb3752010-06-28 19:15:37 -07001295 if (l->has_value) {
Richard Henderson8c081b12014-04-25 10:18:59 -04001296 tgen_gotoi(s, cc, l->u.value_ptr);
Richard Henderson48bb3752010-06-28 19:15:37 -07001297 } else if (USE_LONG_BRANCHES) {
1298 tcg_out16(s, RIL_BRCL | (cc << 4));
Richard Hendersone692a342017-07-30 13:58:01 -07001299 tcg_out_reloc(s, s->code_ptr, R_390_PC32DBL, l, 2);
Richard Henderson8c081b12014-04-25 10:18:59 -04001300 s->code_ptr += 2;
Richard Henderson48bb3752010-06-28 19:15:37 -07001301 } else {
1302 tcg_out16(s, RI_BRC | (cc << 4));
Richard Hendersone692a342017-07-30 13:58:01 -07001303 tcg_out_reloc(s, s->code_ptr, R_390_PC16DBL, l, 2);
Richard Henderson8c081b12014-04-25 10:18:59 -04001304 s->code_ptr += 1;
Richard Henderson48bb3752010-06-28 19:15:37 -07001305 }
1306}
1307
1308static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc,
Richard Hendersonbec16312015-02-13 13:39:54 -08001309 TCGReg r1, TCGReg r2, TCGLabel *l)
Richard Henderson48bb3752010-06-28 19:15:37 -07001310{
Richard Henderson79dae4d2020-11-04 20:56:16 -08001311 tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2);
Richard Henderson48bb3752010-06-28 19:15:37 -07001312 tcg_out16(s, (opc & 0xff00) | (r1 << 4) | r2);
Richard Henderson79dae4d2020-11-04 20:56:16 -08001313 tcg_out16(s, 0);
Richard Henderson48bb3752010-06-28 19:15:37 -07001314 tcg_out16(s, cc << 12 | (opc & 0xff));
1315}
1316
1317static void tgen_compare_imm_branch(TCGContext *s, S390Opcode opc, int cc,
Richard Hendersonbec16312015-02-13 13:39:54 -08001318 TCGReg r1, int i2, TCGLabel *l)
Richard Henderson48bb3752010-06-28 19:15:37 -07001319{
Richard Henderson79dae4d2020-11-04 20:56:16 -08001320 tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2);
Richard Henderson48bb3752010-06-28 19:15:37 -07001321 tcg_out16(s, (opc & 0xff00) | (r1 << 4) | cc);
Richard Henderson79dae4d2020-11-04 20:56:16 -08001322 tcg_out16(s, 0);
Richard Henderson48bb3752010-06-28 19:15:37 -07001323 tcg_out16(s, (i2 << 8) | (opc & 0xff));
1324}
1325
1326static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
Richard Hendersonbec16312015-02-13 13:39:54 -08001327 TCGReg r1, TCGArg c2, int c2const, TCGLabel *l)
Richard Henderson48bb3752010-06-28 19:15:37 -07001328{
1329 int cc;
1330
Richard Hendersonb2c98d92016-10-17 11:24:38 -04001331 if (s390_facilities & FACILITY_GEN_INST_EXT) {
Richard Hendersonb879f302013-04-05 14:10:28 -04001332 bool is_unsigned = is_unsigned_cond(c);
Richard Henderson48bb3752010-06-28 19:15:37 -07001333 bool in_range;
1334 S390Opcode opc;
1335
1336 cc = tcg_cond_to_s390_cond[c];
1337
1338 if (!c2const) {
1339 opc = (type == TCG_TYPE_I32
1340 ? (is_unsigned ? RIE_CLRJ : RIE_CRJ)
1341 : (is_unsigned ? RIE_CLGRJ : RIE_CGRJ));
Richard Hendersonbec16312015-02-13 13:39:54 -08001342 tgen_compare_branch(s, opc, cc, r1, c2, l);
Richard Henderson48bb3752010-06-28 19:15:37 -07001343 return;
1344 }
1345
1346 /* COMPARE IMMEDIATE AND BRANCH RELATIVE has an 8-bit immediate field.
1347 If the immediate we've been given does not fit that range, we'll
1348 fall back to separate compare and branch instructions using the
1349 larger comparison range afforded by COMPARE IMMEDIATE. */
1350 if (type == TCG_TYPE_I32) {
1351 if (is_unsigned) {
1352 opc = RIE_CLIJ;
1353 in_range = (uint32_t)c2 == (uint8_t)c2;
1354 } else {
1355 opc = RIE_CIJ;
1356 in_range = (int32_t)c2 == (int8_t)c2;
1357 }
1358 } else {
1359 if (is_unsigned) {
1360 opc = RIE_CLGIJ;
1361 in_range = (uint64_t)c2 == (uint8_t)c2;
1362 } else {
1363 opc = RIE_CGIJ;
1364 in_range = (int64_t)c2 == (int8_t)c2;
1365 }
1366 }
1367 if (in_range) {
Richard Hendersonbec16312015-02-13 13:39:54 -08001368 tgen_compare_imm_branch(s, opc, cc, r1, c2, l);
Richard Henderson48bb3752010-06-28 19:15:37 -07001369 return;
1370 }
1371 }
1372
Richard Henderson65839b52016-12-06 22:00:57 -05001373 cc = tgen_cmp(s, type, c, r1, c2, c2const, false);
Richard Hendersonbec16312015-02-13 13:39:54 -08001374 tgen_branch(s, cc, l);
Richard Henderson48bb3752010-06-28 19:15:37 -07001375}
1376
Richard Henderson2be7d762020-10-28 15:29:04 -07001377static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
Richard Henderson48bb3752010-06-28 19:15:37 -07001378{
Richard Henderson79dae4d2020-11-04 20:56:16 -08001379 ptrdiff_t off = tcg_pcrel_diff(s, dest) >> 1;
Richard Henderson48bb3752010-06-28 19:15:37 -07001380 if (off == (int32_t)off) {
1381 tcg_out_insn(s, RIL, BRASL, TCG_REG_R14, off);
1382 } else {
Richard Henderson8c081b12014-04-25 10:18:59 -04001383 tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, (uintptr_t)dest);
Richard Henderson48bb3752010-06-28 19:15:37 -07001384 tcg_out_insn(s, RR, BASR, TCG_REG_R14, TCG_TMP0);
1385 }
1386}
1387
Tony Nguyen14776ab2019-08-24 04:10:58 +10001388static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg data,
Richard Henderson48bb3752010-06-28 19:15:37 -07001389 TCGReg base, TCGReg index, int disp)
1390{
Aurelien Jarno3c8691f2015-07-30 22:13:26 +02001391 switch (opc & (MO_SSIZE | MO_BSWAP)) {
Richard Hendersona5a04f22014-03-23 13:15:50 -07001392 case MO_UB:
Richard Henderson48bb3752010-06-28 19:15:37 -07001393 tcg_out_insn(s, RXY, LLGC, data, base, index, disp);
1394 break;
Richard Hendersona5a04f22014-03-23 13:15:50 -07001395 case MO_SB:
Richard Henderson48bb3752010-06-28 19:15:37 -07001396 tcg_out_insn(s, RXY, LGB, data, base, index, disp);
1397 break;
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001398
1399 case MO_UW | MO_BSWAP:
1400 /* swapped unsigned halfword load with upper bits zeroed */
1401 tcg_out_insn(s, RXY, LRVH, data, base, index, disp);
1402 tgen_ext16u(s, TCG_TYPE_I64, data, data);
1403 break;
Richard Hendersona5a04f22014-03-23 13:15:50 -07001404 case MO_UW:
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001405 tcg_out_insn(s, RXY, LLGH, data, base, index, disp);
1406 break;
1407
1408 case MO_SW | MO_BSWAP:
1409 /* swapped sign-extended halfword load */
1410 tcg_out_insn(s, RXY, LRVH, data, base, index, disp);
1411 tgen_ext16s(s, TCG_TYPE_I64, data, data);
Richard Henderson48bb3752010-06-28 19:15:37 -07001412 break;
Richard Hendersona5a04f22014-03-23 13:15:50 -07001413 case MO_SW:
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001414 tcg_out_insn(s, RXY, LGH, data, base, index, disp);
1415 break;
1416
1417 case MO_UL | MO_BSWAP:
1418 /* swapped unsigned int load with upper bits zeroed */
1419 tcg_out_insn(s, RXY, LRV, data, base, index, disp);
1420 tgen_ext32u(s, data, data);
Richard Henderson48bb3752010-06-28 19:15:37 -07001421 break;
Richard Hendersona5a04f22014-03-23 13:15:50 -07001422 case MO_UL:
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001423 tcg_out_insn(s, RXY, LLGF, data, base, index, disp);
1424 break;
1425
1426 case MO_SL | MO_BSWAP:
1427 /* swapped sign-extended int load */
1428 tcg_out_insn(s, RXY, LRV, data, base, index, disp);
1429 tgen_ext32s(s, data, data);
Richard Henderson48bb3752010-06-28 19:15:37 -07001430 break;
Richard Hendersona5a04f22014-03-23 13:15:50 -07001431 case MO_SL:
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001432 tcg_out_insn(s, RXY, LGF, data, base, index, disp);
1433 break;
1434
1435 case MO_Q | MO_BSWAP:
1436 tcg_out_insn(s, RXY, LRVG, data, base, index, disp);
Richard Henderson48bb3752010-06-28 19:15:37 -07001437 break;
Richard Hendersona5a04f22014-03-23 13:15:50 -07001438 case MO_Q:
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001439 tcg_out_insn(s, RXY, LG, data, base, index, disp);
Richard Henderson48bb3752010-06-28 19:15:37 -07001440 break;
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001441
Richard Henderson48bb3752010-06-28 19:15:37 -07001442 default:
1443 tcg_abort();
1444 }
1445}
1446
Tony Nguyen14776ab2019-08-24 04:10:58 +10001447static void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg data,
Richard Henderson48bb3752010-06-28 19:15:37 -07001448 TCGReg base, TCGReg index, int disp)
1449{
Aurelien Jarno3c8691f2015-07-30 22:13:26 +02001450 switch (opc & (MO_SIZE | MO_BSWAP)) {
Richard Hendersona5a04f22014-03-23 13:15:50 -07001451 case MO_UB:
Richard Henderson48bb3752010-06-28 19:15:37 -07001452 if (disp >= 0 && disp < 0x1000) {
1453 tcg_out_insn(s, RX, STC, data, base, index, disp);
1454 } else {
1455 tcg_out_insn(s, RXY, STCY, data, base, index, disp);
1456 }
1457 break;
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001458
1459 case MO_UW | MO_BSWAP:
1460 tcg_out_insn(s, RXY, STRVH, data, base, index, disp);
1461 break;
Richard Hendersona5a04f22014-03-23 13:15:50 -07001462 case MO_UW:
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001463 if (disp >= 0 && disp < 0x1000) {
Richard Henderson48bb3752010-06-28 19:15:37 -07001464 tcg_out_insn(s, RX, STH, data, base, index, disp);
1465 } else {
1466 tcg_out_insn(s, RXY, STHY, data, base, index, disp);
1467 }
1468 break;
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001469
1470 case MO_UL | MO_BSWAP:
1471 tcg_out_insn(s, RXY, STRV, data, base, index, disp);
1472 break;
Richard Hendersona5a04f22014-03-23 13:15:50 -07001473 case MO_UL:
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001474 if (disp >= 0 && disp < 0x1000) {
Richard Henderson48bb3752010-06-28 19:15:37 -07001475 tcg_out_insn(s, RX, ST, data, base, index, disp);
1476 } else {
1477 tcg_out_insn(s, RXY, STY, data, base, index, disp);
1478 }
1479 break;
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001480
1481 case MO_Q | MO_BSWAP:
1482 tcg_out_insn(s, RXY, STRVG, data, base, index, disp);
Richard Henderson48bb3752010-06-28 19:15:37 -07001483 break;
Richard Hendersonb8dd88b2014-03-23 13:24:53 -07001484 case MO_Q:
1485 tcg_out_insn(s, RXY, STG, data, base, index, disp);
1486 break;
1487
Richard Henderson48bb3752010-06-28 19:15:37 -07001488 default:
1489 tcg_abort();
1490 }
1491}
1492
1493#if defined(CONFIG_SOFTMMU)
Paolo Bonzini139c1832020-02-04 12:41:01 +01001494#include "../tcg-ldst.c.inc"
Richard Henderson659ef5c2017-07-30 12:30:41 -07001495
Richard Henderson269bd5d2019-03-22 22:03:39 -07001496/* We're expecting to use a 20-bit negative offset on the tlb memory ops. */
1497QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0);
1498QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 19));
Richard Hendersonfb596412014-03-23 14:26:15 -07001499
1500/* Load and compare a TLB entry, leaving the flags set. Loads the TLB
1501 addend into R2. Returns a register with the santitized guest address. */
Tony Nguyen14776ab2019-08-24 04:10:58 +10001502static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc,
Richard Hendersonfb596412014-03-23 14:26:15 -07001503 int mem_index, bool is_ld)
Richard Henderson48bb3752010-06-28 19:15:37 -07001504{
Richard Henderson85aa8082016-07-14 12:43:06 -07001505 unsigned s_bits = opc & MO_SIZE;
1506 unsigned a_bits = get_alignment_bits(opc);
1507 unsigned s_mask = (1 << s_bits) - 1;
1508 unsigned a_mask = (1 << a_bits) - 1;
Richard Henderson269bd5d2019-03-22 22:03:39 -07001509 int fast_off = TLB_MASK_TABLE_OFS(mem_index);
1510 int mask_off = fast_off + offsetof(CPUTLBDescFast, mask);
1511 int table_off = fast_off + offsetof(CPUTLBDescFast, table);
Richard Hendersona5e39812015-07-23 13:32:35 -07001512 int ofs, a_off;
1513 uint64_t tlb_mask;
1514
Richard Henderson4f47e332018-12-26 15:41:21 +11001515 tcg_out_sh64(s, RSY_SRLG, TCG_REG_R2, addr_reg, TCG_REG_NONE,
1516 TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
1517 tcg_out_insn(s, RXY, NG, TCG_REG_R2, TCG_AREG0, TCG_REG_NONE, mask_off);
1518 tcg_out_insn(s, RXY, AG, TCG_REG_R2, TCG_AREG0, TCG_REG_NONE, table_off);
1519
Richard Hendersona5e39812015-07-23 13:32:35 -07001520 /* For aligned accesses, we check the first byte and include the alignment
1521 bits within the address. For unaligned access, we check that we don't
1522 cross pages using the address of the last byte of the access. */
Richard Henderson85aa8082016-07-14 12:43:06 -07001523 a_off = (a_bits >= s_bits ? 0 : s_mask - a_mask);
1524 tlb_mask = (uint64_t)TARGET_PAGE_MASK | a_mask;
Richard Henderson4f47e332018-12-26 15:41:21 +11001525 if ((s390_facilities & FACILITY_GEN_INST_EXT) && a_off == 0) {
1526 tgen_andi_risbg(s, TCG_REG_R3, addr_reg, tlb_mask);
Richard Henderson48bb3752010-06-28 19:15:37 -07001527 } else {
Richard Hendersona5e39812015-07-23 13:32:35 -07001528 tcg_out_insn(s, RX, LA, TCG_REG_R3, addr_reg, TCG_REG_NONE, a_off);
Richard Henderson547ec122014-03-23 19:35:44 -04001529 tgen_andi(s, TCG_TYPE_TL, TCG_REG_R3, tlb_mask);
Richard Hendersonfb596412014-03-23 14:26:15 -07001530 }
1531
Richard Hendersonfb596412014-03-23 14:26:15 -07001532 if (is_ld) {
Richard Henderson4f47e332018-12-26 15:41:21 +11001533 ofs = offsetof(CPUTLBEntry, addr_read);
Richard Hendersonfb596412014-03-23 14:26:15 -07001534 } else {
Richard Henderson4f47e332018-12-26 15:41:21 +11001535 ofs = offsetof(CPUTLBEntry, addr_write);
Richard Henderson48bb3752010-06-28 19:15:37 -07001536 }
Richard Henderson48bb3752010-06-28 19:15:37 -07001537 if (TARGET_LONG_BITS == 32) {
Richard Henderson4f47e332018-12-26 15:41:21 +11001538 tcg_out_insn(s, RX, C, TCG_REG_R3, TCG_REG_R2, TCG_REG_NONE, ofs);
Richard Henderson48bb3752010-06-28 19:15:37 -07001539 } else {
Richard Henderson4f47e332018-12-26 15:41:21 +11001540 tcg_out_insn(s, RXY, CG, TCG_REG_R3, TCG_REG_R2, TCG_REG_NONE, ofs);
Richard Henderson48bb3752010-06-28 19:15:37 -07001541 }
1542
Richard Henderson4f47e332018-12-26 15:41:21 +11001543 tcg_out_insn(s, RXY, LG, TCG_REG_R2, TCG_REG_R2, TCG_REG_NONE,
1544 offsetof(CPUTLBEntry, addend));
Richard Henderson48bb3752010-06-28 19:15:37 -07001545
Richard Hendersonfb596412014-03-23 14:26:15 -07001546 if (TARGET_LONG_BITS == 32) {
1547 tgen_ext32u(s, TCG_REG_R3, addr_reg);
1548 return TCG_REG_R3;
1549 }
1550 return addr_reg;
Richard Henderson48bb3752010-06-28 19:15:37 -07001551}
1552
Richard Henderson3972ef62015-05-13 09:10:33 -07001553static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
1554 TCGReg data, TCGReg addr,
Richard Hendersonfb596412014-03-23 14:26:15 -07001555 tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
Richard Henderson48bb3752010-06-28 19:15:37 -07001556{
Richard Hendersonfb596412014-03-23 14:26:15 -07001557 TCGLabelQemuLdst *label = new_ldst_label(s);
1558
1559 label->is_ld = is_ld;
Richard Henderson3972ef62015-05-13 09:10:33 -07001560 label->oi = oi;
Richard Hendersonfb596412014-03-23 14:26:15 -07001561 label->datalo_reg = data;
1562 label->addrlo_reg = addr;
Richard Hendersone5e2e4c2020-11-05 15:46:44 -08001563 label->raddr = tcg_splitwx_to_rx(raddr);
Richard Hendersonfb596412014-03-23 14:26:15 -07001564 label->label_ptr[0] = label_ptr;
1565}
1566
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001567static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
Richard Hendersonfb596412014-03-23 14:26:15 -07001568{
1569 TCGReg addr_reg = lb->addrlo_reg;
1570 TCGReg data_reg = lb->datalo_reg;
Richard Henderson3972ef62015-05-13 09:10:33 -07001571 TCGMemOpIdx oi = lb->oi;
Tony Nguyen14776ab2019-08-24 04:10:58 +10001572 MemOp opc = get_memop(oi);
Richard Hendersonfb596412014-03-23 14:26:15 -07001573
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001574 if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
Richard Henderson79dae4d2020-11-04 20:56:16 -08001575 (intptr_t)tcg_splitwx_to_rx(s->code_ptr), 2)) {
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001576 return false;
1577 }
Richard Hendersonfb596412014-03-23 14:26:15 -07001578
1579 tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R2, TCG_AREG0);
1580 if (TARGET_LONG_BITS == 64) {
1581 tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R3, addr_reg);
1582 }
Richard Henderson3972ef62015-05-13 09:10:33 -07001583 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, oi);
Richard Hendersonfb596412014-03-23 14:26:15 -07001584 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R5, (uintptr_t)lb->raddr);
Richard Henderson2b7ec662015-05-29 09:16:51 -07001585 tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SSIZE)]);
Richard Hendersonfb596412014-03-23 14:26:15 -07001586 tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_R2);
1587
1588 tgen_gotoi(s, S390_CC_ALWAYS, lb->raddr);
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001589 return true;
Richard Hendersonfb596412014-03-23 14:26:15 -07001590}
1591
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001592static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
Richard Hendersonfb596412014-03-23 14:26:15 -07001593{
1594 TCGReg addr_reg = lb->addrlo_reg;
1595 TCGReg data_reg = lb->datalo_reg;
Richard Henderson3972ef62015-05-13 09:10:33 -07001596 TCGMemOpIdx oi = lb->oi;
Tony Nguyen14776ab2019-08-24 04:10:58 +10001597 MemOp opc = get_memop(oi);
Richard Hendersonfb596412014-03-23 14:26:15 -07001598
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001599 if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
Richard Henderson79dae4d2020-11-04 20:56:16 -08001600 (intptr_t)tcg_splitwx_to_rx(s->code_ptr), 2)) {
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001601 return false;
1602 }
Richard Hendersonfb596412014-03-23 14:26:15 -07001603
1604 tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R2, TCG_AREG0);
1605 if (TARGET_LONG_BITS == 64) {
1606 tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R3, addr_reg);
1607 }
1608 switch (opc & MO_SIZE) {
1609 case MO_UB:
1610 tgen_ext8u(s, TCG_TYPE_I64, TCG_REG_R4, data_reg);
1611 break;
1612 case MO_UW:
1613 tgen_ext16u(s, TCG_TYPE_I64, TCG_REG_R4, data_reg);
1614 break;
1615 case MO_UL:
1616 tgen_ext32u(s, TCG_REG_R4, data_reg);
1617 break;
1618 case MO_Q:
1619 tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R4, data_reg);
1620 break;
1621 default:
1622 tcg_abort();
1623 }
Richard Henderson3972ef62015-05-13 09:10:33 -07001624 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R5, oi);
Richard Hendersonfb596412014-03-23 14:26:15 -07001625 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R6, (uintptr_t)lb->raddr);
Richard Henderson2b7ec662015-05-29 09:16:51 -07001626 tcg_out_call(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]);
Richard Hendersonfb596412014-03-23 14:26:15 -07001627
1628 tgen_gotoi(s, S390_CC_ALWAYS, lb->raddr);
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001629 return true;
Richard Henderson48bb3752010-06-28 19:15:37 -07001630}
1631#else
1632static void tcg_prepare_user_ldst(TCGContext *s, TCGReg *addr_reg,
1633 TCGReg *index_reg, tcg_target_long *disp)
1634{
1635 if (TARGET_LONG_BITS == 32) {
1636 tgen_ext32u(s, TCG_TMP0, *addr_reg);
1637 *addr_reg = TCG_TMP0;
1638 }
Laurent Vivierb76f21a2015-08-24 14:53:54 +02001639 if (guest_base < 0x80000) {
Richard Henderson48bb3752010-06-28 19:15:37 -07001640 *index_reg = TCG_REG_NONE;
Laurent Vivierb76f21a2015-08-24 14:53:54 +02001641 *disp = guest_base;
Richard Henderson48bb3752010-06-28 19:15:37 -07001642 } else {
1643 *index_reg = TCG_GUEST_BASE_REG;
1644 *disp = 0;
1645 }
1646}
1647#endif /* CONFIG_SOFTMMU */
1648
Richard Hendersonf24efee2014-03-23 13:36:00 -07001649static void tcg_out_qemu_ld(TCGContext* s, TCGReg data_reg, TCGReg addr_reg,
Richard Henderson59227d52015-05-12 11:51:44 -07001650 TCGMemOpIdx oi)
Richard Henderson48bb3752010-06-28 19:15:37 -07001651{
Tony Nguyen14776ab2019-08-24 04:10:58 +10001652 MemOp opc = get_memop(oi);
Richard Hendersonfb596412014-03-23 14:26:15 -07001653#ifdef CONFIG_SOFTMMU
Richard Henderson59227d52015-05-12 11:51:44 -07001654 unsigned mem_index = get_mmuidx(oi);
Richard Hendersonfb596412014-03-23 14:26:15 -07001655 tcg_insn_unit *label_ptr;
1656 TCGReg base_reg;
Richard Henderson48bb3752010-06-28 19:15:37 -07001657
Richard Hendersonfb596412014-03-23 14:26:15 -07001658 base_reg = tcg_out_tlb_read(s, addr_reg, opc, mem_index, 1);
1659
Aurelien Jarnocd3b29b2015-06-16 07:11:41 +02001660 tcg_out16(s, RI_BRC | (S390_CC_NE << 4));
1661 label_ptr = s->code_ptr;
1662 s->code_ptr += 1;
Richard Hendersonfb596412014-03-23 14:26:15 -07001663
1664 tcg_out_qemu_ld_direct(s, opc, data_reg, base_reg, TCG_REG_R2, 0);
1665
Richard Henderson3972ef62015-05-13 09:10:33 -07001666 add_qemu_ldst_label(s, 1, oi, data_reg, addr_reg, s->code_ptr, label_ptr);
Richard Henderson48bb3752010-06-28 19:15:37 -07001667#else
Richard Hendersonf24efee2014-03-23 13:36:00 -07001668 TCGReg index_reg;
1669 tcg_target_long disp;
1670
Richard Henderson48bb3752010-06-28 19:15:37 -07001671 tcg_prepare_user_ldst(s, &addr_reg, &index_reg, &disp);
1672 tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg, index_reg, disp);
1673#endif
1674}
1675
Richard Hendersonf24efee2014-03-23 13:36:00 -07001676static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg,
Richard Henderson59227d52015-05-12 11:51:44 -07001677 TCGMemOpIdx oi)
Richard Henderson48bb3752010-06-28 19:15:37 -07001678{
Tony Nguyen14776ab2019-08-24 04:10:58 +10001679 MemOp opc = get_memop(oi);
Richard Hendersonfb596412014-03-23 14:26:15 -07001680#ifdef CONFIG_SOFTMMU
Richard Henderson59227d52015-05-12 11:51:44 -07001681 unsigned mem_index = get_mmuidx(oi);
Richard Hendersonfb596412014-03-23 14:26:15 -07001682 tcg_insn_unit *label_ptr;
1683 TCGReg base_reg;
Richard Henderson48bb3752010-06-28 19:15:37 -07001684
Richard Hendersonfb596412014-03-23 14:26:15 -07001685 base_reg = tcg_out_tlb_read(s, addr_reg, opc, mem_index, 0);
1686
Aurelien Jarnocd3b29b2015-06-16 07:11:41 +02001687 tcg_out16(s, RI_BRC | (S390_CC_NE << 4));
1688 label_ptr = s->code_ptr;
1689 s->code_ptr += 1;
Richard Hendersonfb596412014-03-23 14:26:15 -07001690
1691 tcg_out_qemu_st_direct(s, opc, data_reg, base_reg, TCG_REG_R2, 0);
1692
Richard Henderson3972ef62015-05-13 09:10:33 -07001693 add_qemu_ldst_label(s, 0, oi, data_reg, addr_reg, s->code_ptr, label_ptr);
Richard Henderson48bb3752010-06-28 19:15:37 -07001694#else
Richard Hendersonf24efee2014-03-23 13:36:00 -07001695 TCGReg index_reg;
1696 tcg_target_long disp;
1697
Richard Henderson48bb3752010-06-28 19:15:37 -07001698 tcg_prepare_user_ldst(s, &addr_reg, &index_reg, &disp);
1699 tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg, index_reg, disp);
1700#endif
1701}
1702
Richard Henderson48bb3752010-06-28 19:15:37 -07001703# define OP_32_64(x) \
1704 case glue(glue(INDEX_op_,x),_i32): \
1705 case glue(glue(INDEX_op_,x),_i64)
Richard Henderson48bb3752010-06-28 19:15:37 -07001706
Richard Hendersona9751602010-03-19 11:12:29 -07001707static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
Alexander Graf28278222009-12-05 12:44:23 +01001708 const TCGArg *args, const int *const_args)
1709{
Richard Hendersonc2097132017-06-16 13:43:17 -07001710 S390Opcode op, op2;
Richard Henderson0db921e2013-03-27 14:23:26 -04001711 TCGArg a0, a1, a2;
Richard Henderson48bb3752010-06-28 19:15:37 -07001712
1713 switch (opc) {
1714 case INDEX_op_exit_tb:
Richard Henderson46644482017-04-26 18:40:59 -04001715 /* Reuse the zeroing that exists for goto_ptr. */
1716 a0 = args[0];
1717 if (a0 == 0) {
Richard Henderson8b5c2b62020-10-28 14:48:55 -07001718 tgen_gotoi(s, S390_CC_ALWAYS, tcg_code_gen_epilogue);
Richard Henderson46644482017-04-26 18:40:59 -04001719 } else {
1720 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, a0);
1721 tgen_gotoi(s, S390_CC_ALWAYS, tb_ret_addr);
1722 }
Richard Henderson48bb3752010-06-28 19:15:37 -07001723 break;
1724
1725 case INDEX_op_goto_tb:
Richard Henderson829e1372017-07-25 11:53:50 -07001726 a0 = args[0];
Sergey Fedorovf3091012016-04-10 23:35:45 +03001727 if (s->tb_jmp_insn_offset) {
Richard Henderson79dae4d2020-11-04 20:56:16 -08001728 /*
1729 * branch displacement must be aligned for atomic patching;
Sergey Fedoroved3d51e2016-04-22 19:08:48 +03001730 * see if we need to add extra nop before branch
1731 */
1732 if (!QEMU_PTR_IS_ALIGNED(s->code_ptr + 1, 4)) {
1733 tcg_out16(s, NOP);
1734 }
Richard Henderson829e1372017-07-25 11:53:50 -07001735 tcg_debug_assert(!USE_REG_TB);
Richard Hendersona10c64e2014-05-14 17:14:51 -04001736 tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4));
Richard Henderson829e1372017-07-25 11:53:50 -07001737 s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
Richard Hendersona10c64e2014-05-14 17:14:51 -04001738 s->code_ptr += 2;
Richard Henderson48bb3752010-06-28 19:15:37 -07001739 } else {
Richard Henderson829e1372017-07-25 11:53:50 -07001740 /* load address stored at s->tb_jmp_target_addr + a0 */
1741 tcg_out_ld_abs(s, TCG_TYPE_PTR, TCG_REG_TB,
Richard Henderson79dae4d2020-11-04 20:56:16 -08001742 tcg_splitwx_to_rx(s->tb_jmp_target_addr + a0));
Richard Henderson48bb3752010-06-28 19:15:37 -07001743 /* and go there */
Richard Henderson829e1372017-07-25 11:53:50 -07001744 tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_TB);
Richard Henderson48bb3752010-06-28 19:15:37 -07001745 }
Richard Henderson9f754622018-06-14 19:57:03 -10001746 set_jmp_reset_offset(s, a0);
Richard Henderson829e1372017-07-25 11:53:50 -07001747
1748 /* For the unlinked path of goto_tb, we need to reset
1749 TCG_REG_TB to the beginning of this TB. */
1750 if (USE_REG_TB) {
1751 int ofs = -tcg_current_code_size(s);
Richard Henderson79dae4d2020-11-04 20:56:16 -08001752 /* All TB are restricted to 64KiB by unwind info. */
1753 tcg_debug_assert(ofs == sextract64(ofs, 0, 20));
1754 tcg_out_insn(s, RXY, LAY, TCG_REG_TB,
1755 TCG_REG_TB, TCG_REG_NONE, ofs);
Richard Henderson829e1372017-07-25 11:53:50 -07001756 }
Richard Henderson48bb3752010-06-28 19:15:37 -07001757 break;
1758
Richard Henderson46644482017-04-26 18:40:59 -04001759 case INDEX_op_goto_ptr:
Richard Henderson829e1372017-07-25 11:53:50 -07001760 a0 = args[0];
1761 if (USE_REG_TB) {
1762 tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, a0);
1763 }
1764 tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, a0);
Richard Henderson46644482017-04-26 18:40:59 -04001765 break;
1766
Richard Henderson48bb3752010-06-28 19:15:37 -07001767 OP_32_64(ld8u):
1768 /* ??? LLC (RXY format) is only present with the extended-immediate
1769 facility, whereas LLGC is always present. */
1770 tcg_out_mem(s, 0, RXY_LLGC, args[0], args[1], TCG_REG_NONE, args[2]);
1771 break;
1772
1773 OP_32_64(ld8s):
1774 /* ??? LB is no smaller than LGB, so no point to using it. */
1775 tcg_out_mem(s, 0, RXY_LGB, args[0], args[1], TCG_REG_NONE, args[2]);
1776 break;
1777
1778 OP_32_64(ld16u):
1779 /* ??? LLH (RXY format) is only present with the extended-immediate
1780 facility, whereas LLGH is always present. */
1781 tcg_out_mem(s, 0, RXY_LLGH, args[0], args[1], TCG_REG_NONE, args[2]);
1782 break;
1783
1784 case INDEX_op_ld16s_i32:
1785 tcg_out_mem(s, RX_LH, RXY_LHY, args[0], args[1], TCG_REG_NONE, args[2]);
1786 break;
1787
1788 case INDEX_op_ld_i32:
1789 tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]);
1790 break;
1791
1792 OP_32_64(st8):
1793 tcg_out_mem(s, RX_STC, RXY_STCY, args[0], args[1],
1794 TCG_REG_NONE, args[2]);
1795 break;
1796
1797 OP_32_64(st16):
1798 tcg_out_mem(s, RX_STH, RXY_STHY, args[0], args[1],
1799 TCG_REG_NONE, args[2]);
1800 break;
1801
1802 case INDEX_op_st_i32:
1803 tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
1804 break;
1805
1806 case INDEX_op_add_i32:
Richard Henderson0db921e2013-03-27 14:23:26 -04001807 a0 = args[0], a1 = args[1], a2 = (int32_t)args[2];
Richard Henderson48bb3752010-06-28 19:15:37 -07001808 if (const_args[2]) {
Richard Henderson0db921e2013-03-27 14:23:26 -04001809 do_addi_32:
1810 if (a0 == a1) {
1811 if (a2 == (int16_t)a2) {
1812 tcg_out_insn(s, RI, AHI, a0, a2);
1813 break;
1814 }
Richard Hendersonb2c98d92016-10-17 11:24:38 -04001815 if (s390_facilities & FACILITY_EXT_IMM) {
Richard Henderson0db921e2013-03-27 14:23:26 -04001816 tcg_out_insn(s, RIL, AFI, a0, a2);
1817 break;
1818 }
1819 }
1820 tcg_out_mem(s, RX_LA, RXY_LAY, a0, a1, TCG_REG_NONE, a2);
1821 } else if (a0 == a1) {
1822 tcg_out_insn(s, RR, AR, a0, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07001823 } else {
Richard Henderson0db921e2013-03-27 14:23:26 -04001824 tcg_out_insn(s, RX, LA, a0, a1, a2, 0);
Richard Henderson48bb3752010-06-28 19:15:37 -07001825 }
1826 break;
1827 case INDEX_op_sub_i32:
Richard Henderson0db921e2013-03-27 14:23:26 -04001828 a0 = args[0], a1 = args[1], a2 = (int32_t)args[2];
Richard Henderson48bb3752010-06-28 19:15:37 -07001829 if (const_args[2]) {
Richard Henderson0db921e2013-03-27 14:23:26 -04001830 a2 = -a2;
1831 goto do_addi_32;
Richard Hendersonc2097132017-06-16 13:43:17 -07001832 } else if (a0 == a1) {
1833 tcg_out_insn(s, RR, SR, a0, a2);
1834 } else {
1835 tcg_out_insn(s, RRF, SRK, a0, a1, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07001836 }
1837 break;
1838
1839 case INDEX_op_and_i32:
Richard Hendersonc2097132017-06-16 13:43:17 -07001840 a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2];
Richard Henderson48bb3752010-06-28 19:15:37 -07001841 if (const_args[2]) {
Richard Hendersonc2097132017-06-16 13:43:17 -07001842 tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
1843 tgen_andi(s, TCG_TYPE_I32, a0, a2);
1844 } else if (a0 == a1) {
1845 tcg_out_insn(s, RR, NR, a0, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07001846 } else {
Richard Hendersonc2097132017-06-16 13:43:17 -07001847 tcg_out_insn(s, RRF, NRK, a0, a1, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07001848 }
1849 break;
1850 case INDEX_op_or_i32:
Richard Hendersonc2097132017-06-16 13:43:17 -07001851 a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2];
Richard Henderson48bb3752010-06-28 19:15:37 -07001852 if (const_args[2]) {
Richard Hendersonc2097132017-06-16 13:43:17 -07001853 tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
Richard Henderson4046d9c2017-07-25 19:21:36 -04001854 tgen_ori(s, TCG_TYPE_I32, a0, a2);
Richard Hendersonc2097132017-06-16 13:43:17 -07001855 } else if (a0 == a1) {
1856 tcg_out_insn(s, RR, OR, a0, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07001857 } else {
Richard Hendersonc2097132017-06-16 13:43:17 -07001858 tcg_out_insn(s, RRF, ORK, a0, a1, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07001859 }
1860 break;
1861 case INDEX_op_xor_i32:
Richard Hendersonc2097132017-06-16 13:43:17 -07001862 a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2];
Richard Henderson48bb3752010-06-28 19:15:37 -07001863 if (const_args[2]) {
Richard Hendersonc2097132017-06-16 13:43:17 -07001864 tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
Richard Henderson5bf67a92017-07-25 19:42:51 -04001865 tgen_xori(s, TCG_TYPE_I32, a0, a2);
Richard Hendersonc2097132017-06-16 13:43:17 -07001866 } else if (a0 == a1) {
Richard Henderson48bb3752010-06-28 19:15:37 -07001867 tcg_out_insn(s, RR, XR, args[0], args[2]);
Richard Hendersonc2097132017-06-16 13:43:17 -07001868 } else {
1869 tcg_out_insn(s, RRF, XRK, a0, a1, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07001870 }
1871 break;
1872
1873 case INDEX_op_neg_i32:
1874 tcg_out_insn(s, RR, LCR, args[0], args[1]);
1875 break;
1876
1877 case INDEX_op_mul_i32:
1878 if (const_args[2]) {
1879 if ((int32_t)args[2] == (int16_t)args[2]) {
1880 tcg_out_insn(s, RI, MHI, args[0], args[2]);
1881 } else {
1882 tcg_out_insn(s, RIL, MSFI, args[0], args[2]);
1883 }
1884 } else {
1885 tcg_out_insn(s, RRE, MSR, args[0], args[2]);
1886 }
1887 break;
1888
1889 case INDEX_op_div2_i32:
1890 tcg_out_insn(s, RR, DR, TCG_REG_R2, args[4]);
1891 break;
1892 case INDEX_op_divu2_i32:
1893 tcg_out_insn(s, RRE, DLR, TCG_REG_R2, args[4]);
1894 break;
1895
1896 case INDEX_op_shl_i32:
1897 op = RS_SLL;
Richard Hendersonc2097132017-06-16 13:43:17 -07001898 op2 = RSY_SLLK;
Richard Henderson48bb3752010-06-28 19:15:37 -07001899 do_shift32:
Richard Hendersonc2097132017-06-16 13:43:17 -07001900 a0 = args[0], a1 = args[1], a2 = (int32_t)args[2];
1901 if (a0 == a1) {
1902 if (const_args[2]) {
1903 tcg_out_sh32(s, op, a0, TCG_REG_NONE, a2);
1904 } else {
1905 tcg_out_sh32(s, op, a0, a2, 0);
1906 }
Richard Henderson48bb3752010-06-28 19:15:37 -07001907 } else {
Richard Hendersonc2097132017-06-16 13:43:17 -07001908 /* Using tcg_out_sh64 here for the format; it is a 32-bit shift. */
1909 if (const_args[2]) {
1910 tcg_out_sh64(s, op2, a0, a1, TCG_REG_NONE, a2);
1911 } else {
1912 tcg_out_sh64(s, op2, a0, a1, a2, 0);
1913 }
Richard Henderson48bb3752010-06-28 19:15:37 -07001914 }
1915 break;
1916 case INDEX_op_shr_i32:
1917 op = RS_SRL;
Richard Hendersonc2097132017-06-16 13:43:17 -07001918 op2 = RSY_SRLK;
Richard Henderson48bb3752010-06-28 19:15:37 -07001919 goto do_shift32;
1920 case INDEX_op_sar_i32:
1921 op = RS_SRA;
Richard Hendersonc2097132017-06-16 13:43:17 -07001922 op2 = RSY_SRAK;
Richard Henderson48bb3752010-06-28 19:15:37 -07001923 goto do_shift32;
1924
1925 case INDEX_op_rotl_i32:
1926 /* ??? Using tcg_out_sh64 here for the format; it is a 32-bit rol. */
1927 if (const_args[2]) {
1928 tcg_out_sh64(s, RSY_RLL, args[0], args[1], TCG_REG_NONE, args[2]);
1929 } else {
1930 tcg_out_sh64(s, RSY_RLL, args[0], args[1], args[2], 0);
1931 }
1932 break;
1933 case INDEX_op_rotr_i32:
1934 if (const_args[2]) {
1935 tcg_out_sh64(s, RSY_RLL, args[0], args[1],
1936 TCG_REG_NONE, (32 - args[2]) & 31);
1937 } else {
1938 tcg_out_insn(s, RR, LCR, TCG_TMP0, args[2]);
1939 tcg_out_sh64(s, RSY_RLL, args[0], args[1], TCG_TMP0, 0);
1940 }
1941 break;
1942
1943 case INDEX_op_ext8s_i32:
1944 tgen_ext8s(s, TCG_TYPE_I32, args[0], args[1]);
1945 break;
1946 case INDEX_op_ext16s_i32:
1947 tgen_ext16s(s, TCG_TYPE_I32, args[0], args[1]);
1948 break;
1949 case INDEX_op_ext8u_i32:
1950 tgen_ext8u(s, TCG_TYPE_I32, args[0], args[1]);
1951 break;
1952 case INDEX_op_ext16u_i32:
1953 tgen_ext16u(s, TCG_TYPE_I32, args[0], args[1]);
1954 break;
1955
1956 OP_32_64(bswap16):
1957 /* The TCG bswap definition requires bits 0-47 already be zero.
1958 Thus we don't need the G-type insns to implement bswap16_i64. */
1959 tcg_out_insn(s, RRE, LRVR, args[0], args[1]);
1960 tcg_out_sh32(s, RS_SRL, args[0], TCG_REG_NONE, 16);
1961 break;
1962 OP_32_64(bswap32):
1963 tcg_out_insn(s, RRE, LRVR, args[0], args[1]);
1964 break;
1965
Richard Henderson3790b912013-03-26 16:41:45 -04001966 case INDEX_op_add2_i32:
Richard Hendersonad19b352014-03-31 03:16:37 -04001967 if (const_args[4]) {
1968 tcg_out_insn(s, RIL, ALFI, args[0], args[4]);
1969 } else {
1970 tcg_out_insn(s, RR, ALR, args[0], args[4]);
1971 }
Richard Henderson3790b912013-03-26 16:41:45 -04001972 tcg_out_insn(s, RRE, ALCR, args[1], args[5]);
1973 break;
1974 case INDEX_op_sub2_i32:
Richard Hendersonad19b352014-03-31 03:16:37 -04001975 if (const_args[4]) {
1976 tcg_out_insn(s, RIL, SLFI, args[0], args[4]);
1977 } else {
1978 tcg_out_insn(s, RR, SLR, args[0], args[4]);
1979 }
Richard Henderson3790b912013-03-26 16:41:45 -04001980 tcg_out_insn(s, RRE, SLBR, args[1], args[5]);
1981 break;
1982
Richard Henderson48bb3752010-06-28 19:15:37 -07001983 case INDEX_op_br:
Richard Hendersonbec16312015-02-13 13:39:54 -08001984 tgen_branch(s, S390_CC_ALWAYS, arg_label(args[0]));
Richard Henderson48bb3752010-06-28 19:15:37 -07001985 break;
1986
1987 case INDEX_op_brcond_i32:
1988 tgen_brcond(s, TCG_TYPE_I32, args[2], args[0],
Richard Hendersonbec16312015-02-13 13:39:54 -08001989 args[1], const_args[1], arg_label(args[3]));
Richard Henderson48bb3752010-06-28 19:15:37 -07001990 break;
1991 case INDEX_op_setcond_i32:
1992 tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1],
1993 args[2], const_args[2]);
1994 break;
Richard Henderson96a9f092013-03-26 17:28:52 -04001995 case INDEX_op_movcond_i32:
1996 tgen_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1],
Richard Henderson7af525a2017-06-16 15:33:28 -07001997 args[2], const_args[2], args[3], const_args[3]);
Richard Henderson96a9f092013-03-26 17:28:52 -04001998 break;
Richard Henderson48bb3752010-06-28 19:15:37 -07001999
Richard Hendersonf24efee2014-03-23 13:36:00 -07002000 case INDEX_op_qemu_ld_i32:
Richard Henderson48bb3752010-06-28 19:15:37 -07002001 /* ??? Technically we can use a non-extending instruction. */
Richard Hendersonf24efee2014-03-23 13:36:00 -07002002 case INDEX_op_qemu_ld_i64:
Richard Henderson59227d52015-05-12 11:51:44 -07002003 tcg_out_qemu_ld(s, args[0], args[1], args[2]);
Richard Henderson48bb3752010-06-28 19:15:37 -07002004 break;
Richard Hendersonf24efee2014-03-23 13:36:00 -07002005 case INDEX_op_qemu_st_i32:
2006 case INDEX_op_qemu_st_i64:
Richard Henderson59227d52015-05-12 11:51:44 -07002007 tcg_out_qemu_st(s, args[0], args[1], args[2]);
Richard Henderson48bb3752010-06-28 19:15:37 -07002008 break;
2009
Richard Henderson48bb3752010-06-28 19:15:37 -07002010 case INDEX_op_ld16s_i64:
2011 tcg_out_mem(s, 0, RXY_LGH, args[0], args[1], TCG_REG_NONE, args[2]);
2012 break;
2013 case INDEX_op_ld32u_i64:
2014 tcg_out_mem(s, 0, RXY_LLGF, args[0], args[1], TCG_REG_NONE, args[2]);
2015 break;
2016 case INDEX_op_ld32s_i64:
2017 tcg_out_mem(s, 0, RXY_LGF, args[0], args[1], TCG_REG_NONE, args[2]);
2018 break;
2019 case INDEX_op_ld_i64:
2020 tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]);
2021 break;
2022
2023 case INDEX_op_st32_i64:
2024 tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
2025 break;
2026 case INDEX_op_st_i64:
2027 tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]);
2028 break;
2029
2030 case INDEX_op_add_i64:
Richard Henderson0db921e2013-03-27 14:23:26 -04002031 a0 = args[0], a1 = args[1], a2 = args[2];
Richard Henderson48bb3752010-06-28 19:15:37 -07002032 if (const_args[2]) {
Richard Henderson0db921e2013-03-27 14:23:26 -04002033 do_addi_64:
2034 if (a0 == a1) {
2035 if (a2 == (int16_t)a2) {
2036 tcg_out_insn(s, RI, AGHI, a0, a2);
2037 break;
2038 }
Richard Hendersonb2c98d92016-10-17 11:24:38 -04002039 if (s390_facilities & FACILITY_EXT_IMM) {
Richard Henderson0db921e2013-03-27 14:23:26 -04002040 if (a2 == (int32_t)a2) {
2041 tcg_out_insn(s, RIL, AGFI, a0, a2);
2042 break;
2043 } else if (a2 == (uint32_t)a2) {
2044 tcg_out_insn(s, RIL, ALGFI, a0, a2);
2045 break;
2046 } else if (-a2 == (uint32_t)-a2) {
2047 tcg_out_insn(s, RIL, SLGFI, a0, -a2);
2048 break;
2049 }
2050 }
2051 }
2052 tcg_out_mem(s, RX_LA, RXY_LAY, a0, a1, TCG_REG_NONE, a2);
2053 } else if (a0 == a1) {
2054 tcg_out_insn(s, RRE, AGR, a0, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07002055 } else {
Richard Henderson0db921e2013-03-27 14:23:26 -04002056 tcg_out_insn(s, RX, LA, a0, a1, a2, 0);
Richard Henderson48bb3752010-06-28 19:15:37 -07002057 }
2058 break;
2059 case INDEX_op_sub_i64:
Richard Henderson0db921e2013-03-27 14:23:26 -04002060 a0 = args[0], a1 = args[1], a2 = args[2];
Richard Henderson48bb3752010-06-28 19:15:37 -07002061 if (const_args[2]) {
Richard Henderson0db921e2013-03-27 14:23:26 -04002062 a2 = -a2;
2063 goto do_addi_64;
Richard Hendersonc2097132017-06-16 13:43:17 -07002064 } else if (a0 == a1) {
2065 tcg_out_insn(s, RRE, SGR, a0, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07002066 } else {
Richard Hendersonc2097132017-06-16 13:43:17 -07002067 tcg_out_insn(s, RRF, SGRK, a0, a1, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07002068 }
2069 break;
2070
2071 case INDEX_op_and_i64:
Richard Hendersonc2097132017-06-16 13:43:17 -07002072 a0 = args[0], a1 = args[1], a2 = args[2];
Richard Henderson48bb3752010-06-28 19:15:37 -07002073 if (const_args[2]) {
Richard Hendersonc2097132017-06-16 13:43:17 -07002074 tcg_out_mov(s, TCG_TYPE_I64, a0, a1);
Richard Henderson07ff7982013-03-27 11:47:54 -04002075 tgen_andi(s, TCG_TYPE_I64, args[0], args[2]);
Richard Hendersonc2097132017-06-16 13:43:17 -07002076 } else if (a0 == a1) {
Richard Henderson48bb3752010-06-28 19:15:37 -07002077 tcg_out_insn(s, RRE, NGR, args[0], args[2]);
Richard Hendersonc2097132017-06-16 13:43:17 -07002078 } else {
2079 tcg_out_insn(s, RRF, NGRK, a0, a1, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07002080 }
2081 break;
2082 case INDEX_op_or_i64:
Richard Hendersonc2097132017-06-16 13:43:17 -07002083 a0 = args[0], a1 = args[1], a2 = args[2];
Richard Henderson48bb3752010-06-28 19:15:37 -07002084 if (const_args[2]) {
Richard Hendersonc2097132017-06-16 13:43:17 -07002085 tcg_out_mov(s, TCG_TYPE_I64, a0, a1);
Richard Henderson4046d9c2017-07-25 19:21:36 -04002086 tgen_ori(s, TCG_TYPE_I64, a0, a2);
Richard Hendersonc2097132017-06-16 13:43:17 -07002087 } else if (a0 == a1) {
2088 tcg_out_insn(s, RRE, OGR, a0, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07002089 } else {
Richard Hendersonc2097132017-06-16 13:43:17 -07002090 tcg_out_insn(s, RRF, OGRK, a0, a1, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07002091 }
2092 break;
2093 case INDEX_op_xor_i64:
Richard Hendersonc2097132017-06-16 13:43:17 -07002094 a0 = args[0], a1 = args[1], a2 = args[2];
Richard Henderson48bb3752010-06-28 19:15:37 -07002095 if (const_args[2]) {
Richard Hendersonc2097132017-06-16 13:43:17 -07002096 tcg_out_mov(s, TCG_TYPE_I64, a0, a1);
Richard Henderson5bf67a92017-07-25 19:42:51 -04002097 tgen_xori(s, TCG_TYPE_I64, a0, a2);
Richard Hendersonc2097132017-06-16 13:43:17 -07002098 } else if (a0 == a1) {
2099 tcg_out_insn(s, RRE, XGR, a0, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07002100 } else {
Richard Hendersonc2097132017-06-16 13:43:17 -07002101 tcg_out_insn(s, RRF, XGRK, a0, a1, a2);
Richard Henderson48bb3752010-06-28 19:15:37 -07002102 }
2103 break;
2104
2105 case INDEX_op_neg_i64:
2106 tcg_out_insn(s, RRE, LCGR, args[0], args[1]);
2107 break;
2108 case INDEX_op_bswap64_i64:
2109 tcg_out_insn(s, RRE, LRVGR, args[0], args[1]);
2110 break;
2111
2112 case INDEX_op_mul_i64:
2113 if (const_args[2]) {
2114 if (args[2] == (int16_t)args[2]) {
2115 tcg_out_insn(s, RI, MGHI, args[0], args[2]);
2116 } else {
2117 tcg_out_insn(s, RIL, MSGFI, args[0], args[2]);
2118 }
2119 } else {
2120 tcg_out_insn(s, RRE, MSGR, args[0], args[2]);
2121 }
2122 break;
2123
2124 case INDEX_op_div2_i64:
2125 /* ??? We get an unnecessary sign-extension of the dividend
2126 into R3 with this definition, but as we do in fact always
2127 produce both quotient and remainder using INDEX_op_div_i64
2128 instead requires jumping through even more hoops. */
2129 tcg_out_insn(s, RRE, DSGR, TCG_REG_R2, args[4]);
2130 break;
2131 case INDEX_op_divu2_i64:
2132 tcg_out_insn(s, RRE, DLGR, TCG_REG_R2, args[4]);
2133 break;
Richard Henderson36017dc2013-03-26 16:50:29 -04002134 case INDEX_op_mulu2_i64:
2135 tcg_out_insn(s, RRE, MLGR, TCG_REG_R2, args[3]);
2136 break;
Richard Henderson48bb3752010-06-28 19:15:37 -07002137
2138 case INDEX_op_shl_i64:
2139 op = RSY_SLLG;
2140 do_shift64:
2141 if (const_args[2]) {
2142 tcg_out_sh64(s, op, args[0], args[1], TCG_REG_NONE, args[2]);
2143 } else {
2144 tcg_out_sh64(s, op, args[0], args[1], args[2], 0);
2145 }
2146 break;
2147 case INDEX_op_shr_i64:
2148 op = RSY_SRLG;
2149 goto do_shift64;
2150 case INDEX_op_sar_i64:
2151 op = RSY_SRAG;
2152 goto do_shift64;
2153
2154 case INDEX_op_rotl_i64:
2155 if (const_args[2]) {
2156 tcg_out_sh64(s, RSY_RLLG, args[0], args[1],
2157 TCG_REG_NONE, args[2]);
2158 } else {
2159 tcg_out_sh64(s, RSY_RLLG, args[0], args[1], args[2], 0);
2160 }
2161 break;
2162 case INDEX_op_rotr_i64:
2163 if (const_args[2]) {
2164 tcg_out_sh64(s, RSY_RLLG, args[0], args[1],
2165 TCG_REG_NONE, (64 - args[2]) & 63);
2166 } else {
2167 /* We can use the smaller 32-bit negate because only the
2168 low 6 bits are examined for the rotate. */
2169 tcg_out_insn(s, RR, LCR, TCG_TMP0, args[2]);
2170 tcg_out_sh64(s, RSY_RLLG, args[0], args[1], TCG_TMP0, 0);
2171 }
2172 break;
2173
2174 case INDEX_op_ext8s_i64:
2175 tgen_ext8s(s, TCG_TYPE_I64, args[0], args[1]);
2176 break;
2177 case INDEX_op_ext16s_i64:
2178 tgen_ext16s(s, TCG_TYPE_I64, args[0], args[1]);
2179 break;
Aurelien Jarno4f2331e2015-07-27 12:41:45 +02002180 case INDEX_op_ext_i32_i64:
Richard Henderson48bb3752010-06-28 19:15:37 -07002181 case INDEX_op_ext32s_i64:
2182 tgen_ext32s(s, args[0], args[1]);
2183 break;
2184 case INDEX_op_ext8u_i64:
2185 tgen_ext8u(s, TCG_TYPE_I64, args[0], args[1]);
2186 break;
2187 case INDEX_op_ext16u_i64:
2188 tgen_ext16u(s, TCG_TYPE_I64, args[0], args[1]);
2189 break;
Aurelien Jarno4f2331e2015-07-27 12:41:45 +02002190 case INDEX_op_extu_i32_i64:
Richard Henderson48bb3752010-06-28 19:15:37 -07002191 case INDEX_op_ext32u_i64:
2192 tgen_ext32u(s, args[0], args[1]);
2193 break;
2194
Richard Henderson3790b912013-03-26 16:41:45 -04002195 case INDEX_op_add2_i64:
Richard Hendersonad19b352014-03-31 03:16:37 -04002196 if (const_args[4]) {
2197 if ((int64_t)args[4] >= 0) {
2198 tcg_out_insn(s, RIL, ALGFI, args[0], args[4]);
2199 } else {
2200 tcg_out_insn(s, RIL, SLGFI, args[0], -args[4]);
2201 }
2202 } else {
2203 tcg_out_insn(s, RRE, ALGR, args[0], args[4]);
2204 }
Richard Henderson3790b912013-03-26 16:41:45 -04002205 tcg_out_insn(s, RRE, ALCGR, args[1], args[5]);
2206 break;
2207 case INDEX_op_sub2_i64:
Richard Hendersonad19b352014-03-31 03:16:37 -04002208 if (const_args[4]) {
2209 if ((int64_t)args[4] >= 0) {
2210 tcg_out_insn(s, RIL, SLGFI, args[0], args[4]);
2211 } else {
2212 tcg_out_insn(s, RIL, ALGFI, args[0], -args[4]);
2213 }
2214 } else {
2215 tcg_out_insn(s, RRE, SLGR, args[0], args[4]);
2216 }
Richard Henderson3790b912013-03-26 16:41:45 -04002217 tcg_out_insn(s, RRE, SLBGR, args[1], args[5]);
2218 break;
2219
Richard Henderson48bb3752010-06-28 19:15:37 -07002220 case INDEX_op_brcond_i64:
2221 tgen_brcond(s, TCG_TYPE_I64, args[2], args[0],
Richard Hendersonbec16312015-02-13 13:39:54 -08002222 args[1], const_args[1], arg_label(args[3]));
Richard Henderson48bb3752010-06-28 19:15:37 -07002223 break;
2224 case INDEX_op_setcond_i64:
2225 tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1],
2226 args[2], const_args[2]);
2227 break;
Richard Henderson96a9f092013-03-26 17:28:52 -04002228 case INDEX_op_movcond_i64:
2229 tgen_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1],
Richard Henderson7af525a2017-06-16 15:33:28 -07002230 args[2], const_args[2], args[3], const_args[3]);
Richard Henderson96a9f092013-03-26 17:28:52 -04002231 break;
Richard Henderson48bb3752010-06-28 19:15:37 -07002232
Richard Hendersond5690ea2013-03-27 09:30:58 -04002233 OP_32_64(deposit):
Richard Henderson752b1be2016-10-17 17:00:46 -07002234 a0 = args[0], a1 = args[1], a2 = args[2];
2235 if (const_args[1]) {
2236 tgen_deposit(s, a0, a2, args[3], args[4], 1);
2237 } else {
2238 /* Since we can't support "0Z" as a constraint, we allow a1 in
2239 any register. Fix things up as if a matching constraint. */
2240 if (a0 != a1) {
2241 TCGType type = (opc == INDEX_op_deposit_i64);
2242 if (a0 == a2) {
2243 tcg_out_mov(s, type, TCG_TMP0, a2);
2244 a2 = TCG_TMP0;
2245 }
2246 tcg_out_mov(s, type, a0, a1);
2247 }
2248 tgen_deposit(s, a0, a2, args[3], args[4], 0);
2249 }
Richard Hendersond5690ea2013-03-27 09:30:58 -04002250 break;
Richard Henderson752b1be2016-10-17 17:00:46 -07002251
Richard Hendersonb0bf5fe2016-10-14 14:26:40 -05002252 OP_32_64(extract):
2253 tgen_extract(s, args[0], args[1], args[2], args[3]);
2254 break;
Richard Hendersond5690ea2013-03-27 09:30:58 -04002255
Richard Hendersonce411062016-11-16 16:10:37 +01002256 case INDEX_op_clz_i64:
2257 tgen_clz(s, args[0], args[1], args[2], const_args[2]);
2258 break;
2259
Pranith Kumarc9314d62016-07-14 16:20:20 -04002260 case INDEX_op_mb:
2261 /* The host memory model is quite strong, we simply need to
2262 serialize the instruction stream. */
2263 if (args[0] & TCG_MO_ST_LD) {
2264 tcg_out_insn(s, RR, BCR,
Richard Hendersonb2c98d92016-10-17 11:24:38 -04002265 s390_facilities & FACILITY_FAST_BCR_SER ? 14 : 15, 0);
Pranith Kumarc9314d62016-07-14 16:20:20 -04002266 }
2267 break;
2268
Richard Henderson96d0ee72014-04-25 15:19:33 -04002269 case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
2270 case INDEX_op_mov_i64:
Richard Henderson96d0ee72014-04-25 15:19:33 -04002271 case INDEX_op_call: /* Always emitted via tcg_out_call. */
Richard Henderson48bb3752010-06-28 19:15:37 -07002272 default:
Richard Henderson48bb3752010-06-28 19:15:37 -07002273 tcg_abort();
2274 }
2275}
2276
Richard Hendersonf69d2772016-11-18 09:31:40 +01002277static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
2278{
Richard Henderson9b5500b2017-06-16 12:44:18 -07002279 static const TCGTargetOpDef r = { .args_ct_str = { "r" } };
2280 static const TCGTargetOpDef r_r = { .args_ct_str = { "r", "r" } };
2281 static const TCGTargetOpDef r_L = { .args_ct_str = { "r", "L" } };
2282 static const TCGTargetOpDef L_L = { .args_ct_str = { "L", "L" } };
Richard Henderson07952d92017-06-16 14:45:59 -07002283 static const TCGTargetOpDef r_ri = { .args_ct_str = { "r", "ri" } };
Richard Henderson9b5500b2017-06-16 12:44:18 -07002284 static const TCGTargetOpDef r_r_ri = { .args_ct_str = { "r", "r", "ri" } };
2285 static const TCGTargetOpDef r_0_ri = { .args_ct_str = { "r", "0", "ri" } };
Richard Hendersona8f02692017-06-16 14:52:32 -07002286 static const TCGTargetOpDef r_0_rI = { .args_ct_str = { "r", "0", "rI" } };
2287 static const TCGTargetOpDef r_0_rJ = { .args_ct_str = { "r", "0", "rJ" } };
Richard Hendersonba18b072017-06-16 14:59:55 -07002288 static const TCGTargetOpDef a2_r
2289 = { .args_ct_str = { "r", "r", "0", "1", "r", "r" } };
2290 static const TCGTargetOpDef a2_ri
2291 = { .args_ct_str = { "r", "r", "0", "1", "ri", "r" } };
2292 static const TCGTargetOpDef a2_rA
2293 = { .args_ct_str = { "r", "r", "0", "1", "rA", "r" } };
Richard Hendersonf69d2772016-11-18 09:31:40 +01002294
Richard Henderson9b5500b2017-06-16 12:44:18 -07002295 switch (op) {
2296 case INDEX_op_goto_ptr:
2297 return &r;
2298
2299 case INDEX_op_ld8u_i32:
2300 case INDEX_op_ld8u_i64:
2301 case INDEX_op_ld8s_i32:
2302 case INDEX_op_ld8s_i64:
2303 case INDEX_op_ld16u_i32:
2304 case INDEX_op_ld16u_i64:
2305 case INDEX_op_ld16s_i32:
2306 case INDEX_op_ld16s_i64:
2307 case INDEX_op_ld_i32:
2308 case INDEX_op_ld32u_i64:
2309 case INDEX_op_ld32s_i64:
2310 case INDEX_op_ld_i64:
2311 case INDEX_op_st8_i32:
2312 case INDEX_op_st8_i64:
2313 case INDEX_op_st16_i32:
2314 case INDEX_op_st16_i64:
2315 case INDEX_op_st_i32:
2316 case INDEX_op_st32_i64:
2317 case INDEX_op_st_i64:
2318 return &r_r;
2319
2320 case INDEX_op_add_i32:
2321 case INDEX_op_add_i64:
2322 return &r_r_ri;
2323 case INDEX_op_sub_i32:
2324 case INDEX_op_sub_i64:
Richard Hendersonbdcd5d12017-07-25 18:59:13 -04002325 case INDEX_op_and_i32:
2326 case INDEX_op_and_i64:
Richard Henderson4046d9c2017-07-25 19:21:36 -04002327 case INDEX_op_or_i32:
2328 case INDEX_op_or_i64:
Richard Henderson5bf67a92017-07-25 19:42:51 -04002329 case INDEX_op_xor_i32:
2330 case INDEX_op_xor_i64:
Richard Hendersonc2097132017-06-16 13:43:17 -07002331 return (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_ri : &r_0_ri);
Richard Hendersona8f02692017-06-16 14:52:32 -07002332
Richard Henderson9b5500b2017-06-16 12:44:18 -07002333 case INDEX_op_mul_i32:
Richard Hendersona8f02692017-06-16 14:52:32 -07002334 /* If we have the general-instruction-extensions, then we have
2335 MULTIPLY SINGLE IMMEDIATE with a signed 32-bit, otherwise we
2336 have only MULTIPLY HALFWORD IMMEDIATE, with a signed 16-bit. */
2337 return (s390_facilities & FACILITY_GEN_INST_EXT ? &r_0_ri : &r_0_rI);
Richard Henderson9b5500b2017-06-16 12:44:18 -07002338 case INDEX_op_mul_i64:
Richard Hendersona8f02692017-06-16 14:52:32 -07002339 return (s390_facilities & FACILITY_GEN_INST_EXT ? &r_0_rJ : &r_0_rI);
2340
Richard Henderson9b5500b2017-06-16 12:44:18 -07002341 case INDEX_op_shl_i32:
2342 case INDEX_op_shr_i32:
2343 case INDEX_op_sar_i32:
Richard Hendersonc2097132017-06-16 13:43:17 -07002344 return (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_ri : &r_0_ri);
Richard Henderson9b5500b2017-06-16 12:44:18 -07002345
2346 case INDEX_op_shl_i64:
2347 case INDEX_op_shr_i64:
2348 case INDEX_op_sar_i64:
2349 return &r_r_ri;
2350
2351 case INDEX_op_rotl_i32:
2352 case INDEX_op_rotl_i64:
2353 case INDEX_op_rotr_i32:
2354 case INDEX_op_rotr_i64:
2355 return &r_r_ri;
2356
2357 case INDEX_op_brcond_i32:
2358 case INDEX_op_brcond_i64:
Richard Hendersona534bb12017-07-25 20:10:29 -04002359 return &r_ri;
Richard Henderson9b5500b2017-06-16 12:44:18 -07002360
2361 case INDEX_op_bswap16_i32:
2362 case INDEX_op_bswap16_i64:
2363 case INDEX_op_bswap32_i32:
2364 case INDEX_op_bswap32_i64:
2365 case INDEX_op_bswap64_i64:
2366 case INDEX_op_neg_i32:
2367 case INDEX_op_neg_i64:
2368 case INDEX_op_ext8s_i32:
2369 case INDEX_op_ext8s_i64:
2370 case INDEX_op_ext8u_i32:
2371 case INDEX_op_ext8u_i64:
2372 case INDEX_op_ext16s_i32:
2373 case INDEX_op_ext16s_i64:
2374 case INDEX_op_ext16u_i32:
2375 case INDEX_op_ext16u_i64:
2376 case INDEX_op_ext32s_i64:
2377 case INDEX_op_ext32u_i64:
2378 case INDEX_op_ext_i32_i64:
2379 case INDEX_op_extu_i32_i64:
2380 case INDEX_op_extract_i32:
2381 case INDEX_op_extract_i64:
2382 return &r_r;
2383
2384 case INDEX_op_clz_i64:
Richard Hendersona534bb12017-07-25 20:10:29 -04002385 case INDEX_op_setcond_i32:
2386 case INDEX_op_setcond_i64:
Richard Henderson9b5500b2017-06-16 12:44:18 -07002387 return &r_r_ri;
2388
2389 case INDEX_op_qemu_ld_i32:
2390 case INDEX_op_qemu_ld_i64:
2391 return &r_L;
2392 case INDEX_op_qemu_st_i64:
2393 case INDEX_op_qemu_st_i32:
2394 return &L_L;
2395
2396 case INDEX_op_deposit_i32:
2397 case INDEX_op_deposit_i64:
2398 {
2399 static const TCGTargetOpDef dep
2400 = { .args_ct_str = { "r", "rZ", "r" } };
2401 return &dep;
Richard Hendersonf69d2772016-11-18 09:31:40 +01002402 }
Richard Henderson9b5500b2017-06-16 12:44:18 -07002403 case INDEX_op_movcond_i32:
2404 case INDEX_op_movcond_i64:
2405 {
Richard Hendersona534bb12017-07-25 20:10:29 -04002406 static const TCGTargetOpDef movc
2407 = { .args_ct_str = { "r", "r", "ri", "r", "0" } };
Richard Henderson7af525a2017-06-16 15:33:28 -07002408 static const TCGTargetOpDef movc_l
Richard Hendersona534bb12017-07-25 20:10:29 -04002409 = { .args_ct_str = { "r", "r", "ri", "rI", "0" } };
2410 return (s390_facilities & FACILITY_LOAD_ON_COND2 ? &movc_l : &movc);
Richard Henderson9b5500b2017-06-16 12:44:18 -07002411 }
2412 case INDEX_op_div2_i32:
2413 case INDEX_op_div2_i64:
2414 case INDEX_op_divu2_i32:
2415 case INDEX_op_divu2_i64:
2416 {
2417 static const TCGTargetOpDef div2
2418 = { .args_ct_str = { "b", "a", "0", "1", "r" } };
2419 return &div2;
2420 }
2421 case INDEX_op_mulu2_i64:
2422 {
2423 static const TCGTargetOpDef mul2
2424 = { .args_ct_str = { "b", "a", "0", "r" } };
2425 return &mul2;
2426 }
Richard Hendersonba18b072017-06-16 14:59:55 -07002427
Richard Henderson9b5500b2017-06-16 12:44:18 -07002428 case INDEX_op_add2_i32:
Richard Henderson9b5500b2017-06-16 12:44:18 -07002429 case INDEX_op_sub2_i32:
Richard Hendersonba18b072017-06-16 14:59:55 -07002430 return (s390_facilities & FACILITY_EXT_IMM ? &a2_ri : &a2_r);
2431 case INDEX_op_add2_i64:
Richard Henderson9b5500b2017-06-16 12:44:18 -07002432 case INDEX_op_sub2_i64:
Richard Hendersonba18b072017-06-16 14:59:55 -07002433 return (s390_facilities & FACILITY_EXT_IMM ? &a2_rA : &a2_r);
Richard Henderson9b5500b2017-06-16 12:44:18 -07002434
2435 default:
2436 break;
Richard Hendersonf69d2772016-11-18 09:31:40 +01002437 }
2438 return NULL;
2439}
2440
Richard Hendersonb2c98d92016-10-17 11:24:38 -04002441static void query_s390_facilities(void)
Richard Henderson48bb3752010-06-28 19:15:37 -07002442{
Richard Hendersonc9baa302013-06-07 07:43:33 -07002443 unsigned long hwcap = qemu_getauxval(AT_HWCAP);
Richard Henderson48bb3752010-06-28 19:15:37 -07002444
Richard Hendersonc9baa302013-06-07 07:43:33 -07002445 /* Is STORE FACILITY LIST EXTENDED available? Honestly, I believe this
2446 is present on all 64-bit systems, but let's check for it anyway. */
2447 if (hwcap & HWCAP_S390_STFLE) {
2448 register int r0 __asm__("0");
2449 register void *r1 __asm__("1");
Richard Henderson48bb3752010-06-28 19:15:37 -07002450
Richard Hendersonc9baa302013-06-07 07:43:33 -07002451 /* stfle 0(%r1) */
Richard Hendersonb2c98d92016-10-17 11:24:38 -04002452 r1 = &s390_facilities;
Richard Hendersonc9baa302013-06-07 07:43:33 -07002453 asm volatile(".word 0xb2b0,0x1000"
2454 : "=r"(r0) : "0"(0), "r"(r1) : "memory", "cc");
Richard Henderson48bb3752010-06-28 19:15:37 -07002455 }
Alexander Graf28278222009-12-05 12:44:23 +01002456}
2457
Richard Hendersone4d58b42010-06-02 17:26:56 -07002458static void tcg_target_init(TCGContext *s)
Alexander Graf28278222009-12-05 12:44:23 +01002459{
Richard Hendersonb2c98d92016-10-17 11:24:38 -04002460 query_s390_facilities();
Richard Henderson48bb3752010-06-28 19:15:37 -07002461
Richard Hendersonf46934d2017-09-11 12:44:30 -07002462 tcg_target_available_regs[TCG_TYPE_I32] = 0xffff;
2463 tcg_target_available_regs[TCG_TYPE_I64] = 0xffff;
Richard Henderson48bb3752010-06-28 19:15:37 -07002464
Richard Hendersonccb1bb62017-09-11 11:25:55 -07002465 tcg_target_call_clobber_regs = 0;
Richard Henderson48bb3752010-06-28 19:15:37 -07002466 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R0);
2467 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R1);
2468 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R2);
2469 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R3);
2470 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R4);
2471 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R5);
Richard Hendersonf24efee2014-03-23 13:36:00 -07002472 /* The r6 register is technically call-saved, but it's also a parameter
2473 register, so it can get killed by setup for the qemu_st helper. */
2474 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R6);
Richard Henderson48bb3752010-06-28 19:15:37 -07002475 /* The return register can be considered call-clobbered. */
2476 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R14);
2477
Richard Hendersonccb1bb62017-09-11 11:25:55 -07002478 s->reserved_regs = 0;
Richard Henderson48bb3752010-06-28 19:15:37 -07002479 tcg_regset_set_reg(s->reserved_regs, TCG_TMP0);
2480 /* XXX many insns can't be used with R0, so we better avoid it for now */
2481 tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);
2482 tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
Richard Henderson829e1372017-07-25 11:53:50 -07002483 if (USE_REG_TB) {
2484 tcg_regset_set_reg(s->reserved_regs, TCG_REG_TB);
2485 }
Alexander Graf28278222009-12-05 12:44:23 +01002486}
2487
Richard Hendersonf167dc32014-03-23 21:04:40 -04002488#define FRAME_SIZE ((int)(TCG_TARGET_CALL_STACK_OFFSET \
2489 + TCG_STATIC_CALL_ARGS_SIZE \
2490 + CPU_TEMP_BUF_NLONGS * sizeof(long)))
2491
Richard Hendersone4d58b42010-06-02 17:26:56 -07002492static void tcg_target_qemu_prologue(TCGContext *s)
Alexander Graf28278222009-12-05 12:44:23 +01002493{
Richard Henderson48bb3752010-06-28 19:15:37 -07002494 /* stmg %r6,%r15,48(%r15) (save registers) */
2495 tcg_out_insn(s, RXY, STMG, TCG_REG_R6, TCG_REG_R15, TCG_REG_R15, 48);
Alexander Graf28278222009-12-05 12:44:23 +01002496
Richard Hendersona4924e82013-03-25 20:54:30 -07002497 /* aghi %r15,-frame_size */
Richard Hendersonf167dc32014-03-23 21:04:40 -04002498 tcg_out_insn(s, RI, AGHI, TCG_REG_R15, -FRAME_SIZE);
Richard Hendersona4924e82013-03-25 20:54:30 -07002499
2500 tcg_set_frame(s, TCG_REG_CALL_STACK,
2501 TCG_STATIC_CALL_ARGS_SIZE + TCG_TARGET_CALL_STACK_OFFSET,
2502 CPU_TEMP_BUF_NLONGS * sizeof(long));
Richard Henderson48bb3752010-06-28 19:15:37 -07002503
Laurent Vivier090d0bf2015-08-28 12:23:41 +02002504#ifndef CONFIG_SOFTMMU
Laurent Vivierb76f21a2015-08-24 14:53:54 +02002505 if (guest_base >= 0x80000) {
Richard Henderson829e1372017-07-25 11:53:50 -07002506 tcg_out_movi_int(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base, true);
Richard Henderson48bb3752010-06-28 19:15:37 -07002507 tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
2508 }
Laurent Vivier090d0bf2015-08-28 12:23:41 +02002509#endif
Richard Henderson48bb3752010-06-28 19:15:37 -07002510
Blue Swirlcea5f9a2011-05-15 16:03:25 +00002511 tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
Richard Henderson829e1372017-07-25 11:53:50 -07002512 if (USE_REG_TB) {
2513 tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB,
2514 tcg_target_call_iarg_regs[1]);
2515 }
2516
Blue Swirlcea5f9a2011-05-15 16:03:25 +00002517 /* br %r3 (go to TB) */
2518 tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, tcg_target_call_iarg_regs[1]);
Richard Henderson48bb3752010-06-28 19:15:37 -07002519
Richard Henderson46644482017-04-26 18:40:59 -04002520 /*
2521 * Return path for goto_ptr. Set return value to 0, a-la exit_tb,
2522 * and fall through to the rest of the epilogue.
2523 */
Richard Hendersonc8bc1162020-11-05 15:41:38 -08002524 tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr);
Richard Henderson46644482017-04-26 18:40:59 -04002525 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, 0);
2526
2527 /* TB epilogue */
Richard Henderson79dae4d2020-11-04 20:56:16 -08002528 tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr);
Richard Henderson48bb3752010-06-28 19:15:37 -07002529
Richard Hendersona4924e82013-03-25 20:54:30 -07002530 /* lmg %r6,%r15,fs+48(%r15) (restore registers) */
2531 tcg_out_insn(s, RXY, LMG, TCG_REG_R6, TCG_REG_R15, TCG_REG_R15,
Richard Hendersonf167dc32014-03-23 21:04:40 -04002532 FRAME_SIZE + 48);
Richard Henderson48bb3752010-06-28 19:15:37 -07002533
2534 /* br %r14 (return) */
2535 tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
Alexander Graf28278222009-12-05 12:44:23 +01002536}
Richard Hendersonf167dc32014-03-23 21:04:40 -04002537
Richard Henderson28eef8a2017-07-31 19:16:02 -07002538static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
2539{
2540 memset(p, 0x07, count * sizeof(tcg_insn_unit));
2541}
2542
Richard Hendersonf167dc32014-03-23 21:04:40 -04002543typedef struct {
Richard Hendersond2e16f22014-05-15 12:49:42 -07002544 DebugFrameHeader h;
Richard Hendersonf167dc32014-03-23 21:04:40 -04002545 uint8_t fde_def_cfa[4];
2546 uint8_t fde_reg_ofs[18];
2547} DebugFrame;
2548
2549/* We're expecting a 2 byte uleb128 encoded value. */
2550QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14));
2551
2552#define ELF_HOST_MACHINE EM_S390
2553
Richard Hendersond2e16f22014-05-15 12:49:42 -07002554static const DebugFrame debug_frame = {
2555 .h.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
2556 .h.cie.id = -1,
2557 .h.cie.version = 1,
2558 .h.cie.code_align = 1,
2559 .h.cie.data_align = 8, /* sleb128 8 */
2560 .h.cie.return_column = TCG_REG_R14,
Richard Hendersonf167dc32014-03-23 21:04:40 -04002561
2562 /* Total FDE size does not include the "len" member. */
Richard Hendersond2e16f22014-05-15 12:49:42 -07002563 .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset),
Richard Hendersonf167dc32014-03-23 21:04:40 -04002564
2565 .fde_def_cfa = {
2566 12, TCG_REG_CALL_STACK, /* DW_CFA_def_cfa %r15, ... */
2567 (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */
2568 (FRAME_SIZE >> 7)
2569 },
2570 .fde_reg_ofs = {
2571 0x86, 6, /* DW_CFA_offset, %r6, 48 */
2572 0x87, 7, /* DW_CFA_offset, %r7, 56 */
2573 0x88, 8, /* DW_CFA_offset, %r8, 64 */
2574 0x89, 9, /* DW_CFA_offset, %r92, 72 */
2575 0x8a, 10, /* DW_CFA_offset, %r10, 80 */
2576 0x8b, 11, /* DW_CFA_offset, %r11, 88 */
2577 0x8c, 12, /* DW_CFA_offset, %r12, 96 */
2578 0x8d, 13, /* DW_CFA_offset, %r13, 104 */
2579 0x8e, 14, /* DW_CFA_offset, %r14, 112 */
2580 }
2581};
2582
Richard Henderson755bf9e2020-10-29 09:17:30 -07002583void tcg_register_jit(const void *buf, size_t buf_size)
Richard Hendersonf167dc32014-03-23 21:04:40 -04002584{
Richard Hendersonf167dc32014-03-23 21:04:40 -04002585 tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
2586}