]>
Commit | Line | Data |
---|---|---|
505e75c5 AF |
1 | /* |
2 | * Tiny Code Generator for QEMU | |
3 | * | |
4 | * Copyright (c) 2018 SiFive, Inc | |
5 | * Copyright (c) 2008-2009 Arnaud Patard <[email protected]> | |
6 | * Copyright (c) 2009 Aurelien Jarno <[email protected]> | |
7 | * Copyright (c) 2008 Fabrice Bellard | |
8 | * | |
9 | * Based on i386/tcg-target.c and mips/tcg-target.c | |
10 | * | |
11 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
12 | * of this software and associated documentation files (the "Software"), to deal | |
13 | * in the Software without restriction, including without limitation the rights | |
14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
15 | * copies of the Software, and to permit persons to whom the Software is | |
16 | * furnished to do so, subject to the following conditions: | |
17 | * | |
18 | * The above copyright notice and this permission notice shall be included in | |
19 | * all copies or substantial portions of the Software. | |
20 | * | |
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
24 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
27 | * THE SOFTWARE. | |
28 | */ | |
29 | ||
30 | #include "tcg-pool.inc.c" | |
31 | ||
32 | #ifdef CONFIG_DEBUG_TCG | |
33 | static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { | |
34 | "zero", | |
35 | "ra", | |
36 | "sp", | |
37 | "gp", | |
38 | "tp", | |
39 | "t0", | |
40 | "t1", | |
41 | "t2", | |
42 | "s0", | |
43 | "s1", | |
44 | "a0", | |
45 | "a1", | |
46 | "a2", | |
47 | "a3", | |
48 | "a4", | |
49 | "a5", | |
50 | "a6", | |
51 | "a7", | |
52 | "s2", | |
53 | "s3", | |
54 | "s4", | |
55 | "s5", | |
56 | "s6", | |
57 | "s7", | |
58 | "s8", | |
59 | "s9", | |
60 | "s10", | |
61 | "s11", | |
62 | "t3", | |
63 | "t4", | |
64 | "t5", | |
65 | "t6" | |
66 | }; | |
67 | #endif | |
68 | ||
69 | static const int tcg_target_reg_alloc_order[] = { | |
70 | /* Call saved registers */ | |
71 | /* TCG_REG_S0 reservered for TCG_AREG0 */ | |
72 | TCG_REG_S1, | |
73 | TCG_REG_S2, | |
74 | TCG_REG_S3, | |
75 | TCG_REG_S4, | |
76 | TCG_REG_S5, | |
77 | TCG_REG_S6, | |
78 | TCG_REG_S7, | |
79 | TCG_REG_S8, | |
80 | TCG_REG_S9, | |
81 | TCG_REG_S10, | |
82 | TCG_REG_S11, | |
83 | ||
84 | /* Call clobbered registers */ | |
85 | TCG_REG_T0, | |
86 | TCG_REG_T1, | |
87 | TCG_REG_T2, | |
88 | TCG_REG_T3, | |
89 | TCG_REG_T4, | |
90 | TCG_REG_T5, | |
91 | TCG_REG_T6, | |
92 | ||
93 | /* Argument registers */ | |
94 | TCG_REG_A0, | |
95 | TCG_REG_A1, | |
96 | TCG_REG_A2, | |
97 | TCG_REG_A3, | |
98 | TCG_REG_A4, | |
99 | TCG_REG_A5, | |
100 | TCG_REG_A6, | |
101 | TCG_REG_A7, | |
102 | }; | |
103 | ||
104 | static const int tcg_target_call_iarg_regs[] = { | |
105 | TCG_REG_A0, | |
106 | TCG_REG_A1, | |
107 | TCG_REG_A2, | |
108 | TCG_REG_A3, | |
109 | TCG_REG_A4, | |
110 | TCG_REG_A5, | |
111 | TCG_REG_A6, | |
112 | TCG_REG_A7, | |
113 | }; | |
114 | ||
115 | static const int tcg_target_call_oarg_regs[] = { | |
116 | TCG_REG_A0, | |
117 | TCG_REG_A1, | |
118 | }; | |
8ce23a13 AF |
119 | |
120 | #define TCG_CT_CONST_ZERO 0x100 | |
121 | #define TCG_CT_CONST_S12 0x200 | |
122 | #define TCG_CT_CONST_N12 0x400 | |
123 | #define TCG_CT_CONST_M12 0x800 | |
124 | ||
125 | static inline tcg_target_long sextreg(tcg_target_long val, int pos, int len) | |
126 | { | |
127 | if (TCG_TARGET_REG_BITS == 32) { | |
128 | return sextract32(val, pos, len); | |
129 | } else { | |
130 | return sextract64(val, pos, len); | |
131 | } | |
132 | } | |
133 | ||
134 | /* parse target specific constraints */ | |
135 | static const char *target_parse_constraint(TCGArgConstraint *ct, | |
136 | const char *ct_str, TCGType type) | |
137 | { | |
138 | switch (*ct_str++) { | |
139 | case 'r': | |
140 | ct->ct |= TCG_CT_REG; | |
141 | ct->u.regs = 0xffffffff; | |
142 | break; | |
143 | case 'L': | |
144 | /* qemu_ld/qemu_st constraint */ | |
145 | ct->ct |= TCG_CT_REG; | |
146 | ct->u.regs = 0xffffffff; | |
147 | /* qemu_ld/qemu_st uses TCG_REG_TMP0 */ | |
148 | #if defined(CONFIG_SOFTMMU) | |
149 | tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[0]); | |
150 | tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[1]); | |
151 | tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[2]); | |
152 | tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[3]); | |
153 | tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[4]); | |
154 | #endif | |
155 | break; | |
156 | case 'I': | |
157 | ct->ct |= TCG_CT_CONST_S12; | |
158 | break; | |
159 | case 'N': | |
160 | ct->ct |= TCG_CT_CONST_N12; | |
161 | break; | |
162 | case 'M': | |
163 | ct->ct |= TCG_CT_CONST_M12; | |
164 | break; | |
165 | case 'Z': | |
166 | /* we can use a zero immediate as a zero register argument. */ | |
167 | ct->ct |= TCG_CT_CONST_ZERO; | |
168 | break; | |
169 | default: | |
170 | return NULL; | |
171 | } | |
172 | return ct_str; | |
173 | } | |
174 | ||
175 | /* test if a constant matches the constraint */ | |
176 | static int tcg_target_const_match(tcg_target_long val, TCGType type, | |
177 | const TCGArgConstraint *arg_ct) | |
178 | { | |
179 | int ct = arg_ct->ct; | |
180 | if (ct & TCG_CT_CONST) { | |
181 | return 1; | |
182 | } | |
183 | if ((ct & TCG_CT_CONST_ZERO) && val == 0) { | |
184 | return 1; | |
185 | } | |
186 | if ((ct & TCG_CT_CONST_S12) && val == sextreg(val, 0, 12)) { | |
187 | return 1; | |
188 | } | |
189 | if ((ct & TCG_CT_CONST_N12) && -val == sextreg(-val, 0, 12)) { | |
190 | return 1; | |
191 | } | |
192 | if ((ct & TCG_CT_CONST_M12) && val >= -0xfff && val <= 0xfff) { | |
193 | return 1; | |
194 | } | |
195 | return 0; | |
196 | } | |
197 | ||
198 | /* | |
199 | * RISC-V Base ISA opcodes (IM) | |
200 | */ | |
201 | ||
202 | typedef enum { | |
203 | OPC_ADD = 0x33, | |
204 | OPC_ADDI = 0x13, | |
205 | OPC_AND = 0x7033, | |
206 | OPC_ANDI = 0x7013, | |
207 | OPC_AUIPC = 0x17, | |
208 | OPC_BEQ = 0x63, | |
209 | OPC_BGE = 0x5063, | |
210 | OPC_BGEU = 0x7063, | |
211 | OPC_BLT = 0x4063, | |
212 | OPC_BLTU = 0x6063, | |
213 | OPC_BNE = 0x1063, | |
214 | OPC_DIV = 0x2004033, | |
215 | OPC_DIVU = 0x2005033, | |
216 | OPC_JAL = 0x6f, | |
217 | OPC_JALR = 0x67, | |
218 | OPC_LB = 0x3, | |
219 | OPC_LBU = 0x4003, | |
220 | OPC_LD = 0x3003, | |
221 | OPC_LH = 0x1003, | |
222 | OPC_LHU = 0x5003, | |
223 | OPC_LUI = 0x37, | |
224 | OPC_LW = 0x2003, | |
225 | OPC_LWU = 0x6003, | |
226 | OPC_MUL = 0x2000033, | |
227 | OPC_MULH = 0x2001033, | |
228 | OPC_MULHSU = 0x2002033, | |
229 | OPC_MULHU = 0x2003033, | |
230 | OPC_OR = 0x6033, | |
231 | OPC_ORI = 0x6013, | |
232 | OPC_REM = 0x2006033, | |
233 | OPC_REMU = 0x2007033, | |
234 | OPC_SB = 0x23, | |
235 | OPC_SD = 0x3023, | |
236 | OPC_SH = 0x1023, | |
237 | OPC_SLL = 0x1033, | |
238 | OPC_SLLI = 0x1013, | |
239 | OPC_SLT = 0x2033, | |
240 | OPC_SLTI = 0x2013, | |
241 | OPC_SLTIU = 0x3013, | |
242 | OPC_SLTU = 0x3033, | |
243 | OPC_SRA = 0x40005033, | |
244 | OPC_SRAI = 0x40005013, | |
245 | OPC_SRL = 0x5033, | |
246 | OPC_SRLI = 0x5013, | |
247 | OPC_SUB = 0x40000033, | |
248 | OPC_SW = 0x2023, | |
249 | OPC_XOR = 0x4033, | |
250 | OPC_XORI = 0x4013, | |
251 | ||
252 | #if TCG_TARGET_REG_BITS == 64 | |
253 | OPC_ADDIW = 0x1b, | |
254 | OPC_ADDW = 0x3b, | |
255 | OPC_DIVUW = 0x200503b, | |
256 | OPC_DIVW = 0x200403b, | |
257 | OPC_MULW = 0x200003b, | |
258 | OPC_REMUW = 0x200703b, | |
259 | OPC_REMW = 0x200603b, | |
260 | OPC_SLLIW = 0x101b, | |
261 | OPC_SLLW = 0x103b, | |
262 | OPC_SRAIW = 0x4000501b, | |
263 | OPC_SRAW = 0x4000503b, | |
264 | OPC_SRLIW = 0x501b, | |
265 | OPC_SRLW = 0x503b, | |
266 | OPC_SUBW = 0x4000003b, | |
267 | #else | |
268 | /* Simplify code throughout by defining aliases for RV32. */ | |
269 | OPC_ADDIW = OPC_ADDI, | |
270 | OPC_ADDW = OPC_ADD, | |
271 | OPC_DIVUW = OPC_DIVU, | |
272 | OPC_DIVW = OPC_DIV, | |
273 | OPC_MULW = OPC_MUL, | |
274 | OPC_REMUW = OPC_REMU, | |
275 | OPC_REMW = OPC_REM, | |
276 | OPC_SLLIW = OPC_SLLI, | |
277 | OPC_SLLW = OPC_SLL, | |
278 | OPC_SRAIW = OPC_SRAI, | |
279 | OPC_SRAW = OPC_SRA, | |
280 | OPC_SRLIW = OPC_SRLI, | |
281 | OPC_SRLW = OPC_SRL, | |
282 | OPC_SUBW = OPC_SUB, | |
283 | #endif | |
284 | ||
285 | OPC_FENCE = 0x0000000f, | |
286 | } RISCVInsn; | |
54a9ce0f AF |
287 | |
288 | /* | |
289 | * RISC-V immediate and instruction encoders (excludes 16-bit RVC) | |
290 | */ | |
291 | ||
292 | /* Type-R */ | |
293 | ||
294 | static int32_t encode_r(RISCVInsn opc, TCGReg rd, TCGReg rs1, TCGReg rs2) | |
295 | { | |
296 | return opc | (rd & 0x1f) << 7 | (rs1 & 0x1f) << 15 | (rs2 & 0x1f) << 20; | |
297 | } | |
298 | ||
299 | /* Type-I */ | |
300 | ||
301 | static int32_t encode_imm12(uint32_t imm) | |
302 | { | |
303 | return (imm & 0xfff) << 20; | |
304 | } | |
305 | ||
306 | static int32_t encode_i(RISCVInsn opc, TCGReg rd, TCGReg rs1, uint32_t imm) | |
307 | { | |
308 | return opc | (rd & 0x1f) << 7 | (rs1 & 0x1f) << 15 | encode_imm12(imm); | |
309 | } | |
310 | ||
311 | /* Type-S */ | |
312 | ||
313 | static int32_t encode_simm12(uint32_t imm) | |
314 | { | |
315 | int32_t ret = 0; | |
316 | ||
317 | ret |= (imm & 0xFE0) << 20; | |
318 | ret |= (imm & 0x1F) << 7; | |
319 | ||
320 | return ret; | |
321 | } | |
322 | ||
323 | static int32_t encode_s(RISCVInsn opc, TCGReg rs1, TCGReg rs2, uint32_t imm) | |
324 | { | |
325 | return opc | (rs1 & 0x1f) << 15 | (rs2 & 0x1f) << 20 | encode_simm12(imm); | |
326 | } | |
327 | ||
328 | /* Type-SB */ | |
329 | ||
330 | static int32_t encode_sbimm12(uint32_t imm) | |
331 | { | |
332 | int32_t ret = 0; | |
333 | ||
334 | ret |= (imm & 0x1000) << 19; | |
335 | ret |= (imm & 0x7e0) << 20; | |
336 | ret |= (imm & 0x1e) << 7; | |
337 | ret |= (imm & 0x800) >> 4; | |
338 | ||
339 | return ret; | |
340 | } | |
341 | ||
342 | static int32_t encode_sb(RISCVInsn opc, TCGReg rs1, TCGReg rs2, uint32_t imm) | |
343 | { | |
344 | return opc | (rs1 & 0x1f) << 15 | (rs2 & 0x1f) << 20 | encode_sbimm12(imm); | |
345 | } | |
346 | ||
347 | /* Type-U */ | |
348 | ||
349 | static int32_t encode_uimm20(uint32_t imm) | |
350 | { | |
351 | return imm & 0xfffff000; | |
352 | } | |
353 | ||
354 | static int32_t encode_u(RISCVInsn opc, TCGReg rd, uint32_t imm) | |
355 | { | |
356 | return opc | (rd & 0x1f) << 7 | encode_uimm20(imm); | |
357 | } | |
358 | ||
359 | /* Type-UJ */ | |
360 | ||
361 | static int32_t encode_ujimm20(uint32_t imm) | |
362 | { | |
363 | int32_t ret = 0; | |
364 | ||
365 | ret |= (imm & 0x0007fe) << (21 - 1); | |
366 | ret |= (imm & 0x000800) << (20 - 11); | |
367 | ret |= (imm & 0x0ff000) << (12 - 12); | |
368 | ret |= (imm & 0x100000) << (31 - 20); | |
369 | ||
370 | return ret; | |
371 | } | |
372 | ||
373 | static int32_t encode_uj(RISCVInsn opc, TCGReg rd, uint32_t imm) | |
374 | { | |
375 | return opc | (rd & 0x1f) << 7 | encode_ujimm20(imm); | |
376 | } | |
bedf14e3 AF |
377 | |
378 | /* | |
379 | * RISC-V instruction emitters | |
380 | */ | |
381 | ||
382 | static void tcg_out_opc_reg(TCGContext *s, RISCVInsn opc, | |
383 | TCGReg rd, TCGReg rs1, TCGReg rs2) | |
384 | { | |
385 | tcg_out32(s, encode_r(opc, rd, rs1, rs2)); | |
386 | } | |
387 | ||
388 | static void tcg_out_opc_imm(TCGContext *s, RISCVInsn opc, | |
389 | TCGReg rd, TCGReg rs1, TCGArg imm) | |
390 | { | |
391 | tcg_out32(s, encode_i(opc, rd, rs1, imm)); | |
392 | } | |
393 | ||
394 | static void tcg_out_opc_store(TCGContext *s, RISCVInsn opc, | |
395 | TCGReg rs1, TCGReg rs2, uint32_t imm) | |
396 | { | |
397 | tcg_out32(s, encode_s(opc, rs1, rs2, imm)); | |
398 | } | |
399 | ||
400 | static void tcg_out_opc_branch(TCGContext *s, RISCVInsn opc, | |
401 | TCGReg rs1, TCGReg rs2, uint32_t imm) | |
402 | { | |
403 | tcg_out32(s, encode_sb(opc, rs1, rs2, imm)); | |
404 | } | |
405 | ||
406 | static void tcg_out_opc_upper(TCGContext *s, RISCVInsn opc, | |
407 | TCGReg rd, uint32_t imm) | |
408 | { | |
409 | tcg_out32(s, encode_u(opc, rd, imm)); | |
410 | } | |
411 | ||
412 | static void tcg_out_opc_jump(TCGContext *s, RISCVInsn opc, | |
413 | TCGReg rd, uint32_t imm) | |
414 | { | |
415 | tcg_out32(s, encode_uj(opc, rd, imm)); | |
416 | } | |
417 | ||
418 | static void tcg_out_nop_fill(tcg_insn_unit *p, int count) | |
419 | { | |
420 | int i; | |
421 | for (i = 0; i < count; ++i) { | |
422 | p[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0); | |
423 | } | |
424 | } | |
dfa8e74f AF |
425 | |
426 | /* | |
427 | * Relocations | |
428 | */ | |
429 | ||
430 | static bool reloc_sbimm12(tcg_insn_unit *code_ptr, tcg_insn_unit *target) | |
431 | { | |
432 | intptr_t offset = (intptr_t)target - (intptr_t)code_ptr; | |
433 | ||
434 | if (offset == sextreg(offset, 1, 12) << 1) { | |
435 | code_ptr[0] |= encode_sbimm12(offset); | |
436 | return true; | |
437 | } | |
438 | ||
439 | return false; | |
440 | } | |
441 | ||
442 | static bool reloc_jimm20(tcg_insn_unit *code_ptr, tcg_insn_unit *target) | |
443 | { | |
444 | intptr_t offset = (intptr_t)target - (intptr_t)code_ptr; | |
445 | ||
446 | if (offset == sextreg(offset, 1, 20) << 1) { | |
447 | code_ptr[0] |= encode_ujimm20(offset); | |
448 | return true; | |
449 | } | |
450 | ||
451 | return false; | |
452 | } | |
453 | ||
454 | static bool reloc_call(tcg_insn_unit *code_ptr, tcg_insn_unit *target) | |
455 | { | |
456 | intptr_t offset = (intptr_t)target - (intptr_t)code_ptr; | |
457 | int32_t lo = sextreg(offset, 0, 12); | |
458 | int32_t hi = offset - lo; | |
459 | ||
460 | if (offset == hi + lo) { | |
461 | code_ptr[0] |= encode_uimm20(hi); | |
462 | code_ptr[1] |= encode_imm12(lo); | |
463 | return true; | |
464 | } | |
465 | ||
466 | return false; | |
467 | } | |
468 | ||
469 | static bool patch_reloc(tcg_insn_unit *code_ptr, int type, | |
470 | intptr_t value, intptr_t addend) | |
471 | { | |
472 | uint32_t insn = *code_ptr; | |
473 | intptr_t diff; | |
474 | bool short_jmp; | |
475 | ||
476 | tcg_debug_assert(addend == 0); | |
477 | ||
478 | switch (type) { | |
479 | case R_RISCV_BRANCH: | |
480 | diff = value - (uintptr_t)code_ptr; | |
481 | short_jmp = diff == sextreg(diff, 0, 12); | |
482 | if (short_jmp) { | |
483 | return reloc_sbimm12(code_ptr, (tcg_insn_unit *)value); | |
484 | } else { | |
485 | /* Invert the condition */ | |
486 | insn = insn ^ (1 << 12); | |
487 | /* Clear the offset */ | |
488 | insn &= 0x01fff07f; | |
489 | /* Set the offset to the PC + 8 */ | |
490 | insn |= encode_sbimm12(8); | |
491 | ||
492 | /* Move forward */ | |
493 | code_ptr[0] = insn; | |
494 | ||
495 | /* Overwrite the NOP with jal x0,value */ | |
496 | diff = value - (uintptr_t)(code_ptr + 1); | |
497 | insn = encode_uj(OPC_JAL, TCG_REG_ZERO, diff); | |
498 | code_ptr[1] = insn; | |
499 | ||
500 | return true; | |
501 | } | |
502 | break; | |
503 | case R_RISCV_JAL: | |
504 | return reloc_jimm20(code_ptr, (tcg_insn_unit *)value); | |
505 | break; | |
506 | case R_RISCV_CALL: | |
507 | return reloc_call(code_ptr, (tcg_insn_unit *)value); | |
508 | break; | |
509 | default: | |
510 | tcg_abort(); | |
511 | } | |
512 | } | |
6cd2eda3 AF |
513 | |
514 | /* | |
515 | * TCG intrinsics | |
516 | */ | |
517 | ||
518 | static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) | |
519 | { | |
520 | if (ret == arg) { | |
521 | return; | |
522 | } | |
523 | switch (type) { | |
524 | case TCG_TYPE_I32: | |
525 | case TCG_TYPE_I64: | |
526 | tcg_out_opc_imm(s, OPC_ADDI, ret, arg, 0); | |
527 | break; | |
528 | default: | |
529 | g_assert_not_reached(); | |
530 | } | |
531 | } | |
532 | ||
533 | static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, | |
534 | tcg_target_long val) | |
535 | { | |
536 | tcg_target_long lo, hi, tmp; | |
537 | int shift, ret; | |
538 | ||
539 | if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) { | |
540 | val = (int32_t)val; | |
541 | } | |
542 | ||
543 | lo = sextreg(val, 0, 12); | |
544 | if (val == lo) { | |
545 | tcg_out_opc_imm(s, OPC_ADDI, rd, TCG_REG_ZERO, lo); | |
546 | return; | |
547 | } | |
548 | ||
549 | hi = val - lo; | |
550 | if (TCG_TARGET_REG_BITS == 32 || val == (int32_t)val) { | |
551 | tcg_out_opc_upper(s, OPC_LUI, rd, hi); | |
552 | if (lo != 0) { | |
553 | tcg_out_opc_imm(s, OPC_ADDIW, rd, rd, lo); | |
554 | } | |
555 | return; | |
556 | } | |
557 | ||
558 | /* We can only be here if TCG_TARGET_REG_BITS != 32 */ | |
559 | tmp = tcg_pcrel_diff(s, (void *)val); | |
560 | if (tmp == (int32_t)tmp) { | |
561 | tcg_out_opc_upper(s, OPC_AUIPC, rd, 0); | |
562 | tcg_out_opc_imm(s, OPC_ADDI, rd, rd, 0); | |
563 | ret = reloc_call(s->code_ptr - 2, (tcg_insn_unit *)val); | |
564 | tcg_debug_assert(ret == true); | |
565 | return; | |
566 | } | |
567 | ||
568 | /* Look for a single 20-bit section. */ | |
569 | shift = ctz64(val); | |
570 | tmp = val >> shift; | |
571 | if (tmp == sextreg(tmp, 0, 20)) { | |
572 | tcg_out_opc_upper(s, OPC_LUI, rd, tmp << 12); | |
573 | if (shift > 12) { | |
574 | tcg_out_opc_imm(s, OPC_SLLI, rd, rd, shift - 12); | |
575 | } else { | |
576 | tcg_out_opc_imm(s, OPC_SRAI, rd, rd, 12 - shift); | |
577 | } | |
578 | return; | |
579 | } | |
580 | ||
581 | /* Look for a few high zero bits, with lots of bits set in the middle. */ | |
582 | shift = clz64(val); | |
583 | tmp = val << shift; | |
584 | if (tmp == sextreg(tmp, 12, 20) << 12) { | |
585 | tcg_out_opc_upper(s, OPC_LUI, rd, tmp); | |
586 | tcg_out_opc_imm(s, OPC_SRLI, rd, rd, shift); | |
587 | return; | |
588 | } else if (tmp == sextreg(tmp, 0, 12)) { | |
589 | tcg_out_opc_imm(s, OPC_ADDI, rd, TCG_REG_ZERO, tmp); | |
590 | tcg_out_opc_imm(s, OPC_SRLI, rd, rd, shift); | |
591 | return; | |
592 | } | |
593 | ||
594 | /* Drop into the constant pool. */ | |
595 | new_pool_label(s, val, R_RISCV_CALL, s->code_ptr, 0); | |
596 | tcg_out_opc_upper(s, OPC_AUIPC, rd, 0); | |
597 | tcg_out_opc_imm(s, OPC_LD, rd, rd, 0); | |
598 | } |