1 /* 2 * Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "qemu/osdep.h" 19 #include "cpu.h" 20 #include "internal.h" 21 #include "tcg/tcg-op.h" 22 #include "tcg/tcg-op-gvec.h" 23 #include "insn.h" 24 #include "opcodes.h" 25 #include "translate.h" 26 #define QEMU_GENERATE /* Used internally by macros.h */ 27 #include "macros.h" 28 #include "mmvec/macros.h" 29 #undef QEMU_GENERATE 30 #include "gen_tcg.h" 31 #include "gen_tcg_hvx.h" 32 #include "genptr.h" 33 34 TCGv gen_read_reg(TCGv result, int num) 35 { 36 tcg_gen_mov_tl(result, hex_gpr[num]); 37 return result; 38 } 39 40 TCGv gen_read_preg(TCGv pred, uint8_t num) 41 { 42 tcg_gen_mov_tl(pred, hex_pred[num]); 43 return pred; 44 } 45 46 #define IMMUTABLE (~0) 47 48 static const target_ulong reg_immut_masks[TOTAL_PER_THREAD_REGS] = { 49 [HEX_REG_USR] = 0xc13000c0, 50 [HEX_REG_PC] = IMMUTABLE, 51 [HEX_REG_GP] = 0x3f, 52 [HEX_REG_UPCYCLELO] = IMMUTABLE, 53 [HEX_REG_UPCYCLEHI] = IMMUTABLE, 54 [HEX_REG_UTIMERLO] = IMMUTABLE, 55 [HEX_REG_UTIMERHI] = IMMUTABLE, 56 }; 57 58 static inline void gen_masked_reg_write(TCGv new_val, TCGv cur_val, 59 target_ulong reg_mask) 60 { 61 if (reg_mask) { 62 TCGv tmp = tcg_temp_new(); 63 64 /* new_val = (new_val & ~reg_mask) | (cur_val & reg_mask) */ 65 tcg_gen_andi_tl(new_val, new_val, ~reg_mask); 66 tcg_gen_andi_tl(tmp, cur_val, reg_mask); 67 tcg_gen_or_tl(new_val, new_val, tmp); 68 69 tcg_temp_free(tmp); 70 } 71 } 72 73 static inline void gen_log_predicated_reg_write(int rnum, TCGv val, 74 uint32_t slot) 75 { 76 TCGv zero = tcg_constant_tl(0); 77 TCGv slot_mask = tcg_temp_new(); 78 79 tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot); 80 tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], slot_mask, zero, 81 val, hex_new_value[rnum]); 82 if (HEX_DEBUG) { 83 /* 84 * Do this so HELPER(debug_commit_end) will know 85 * 86 * Note that slot_mask indicates the value is not written 87 * (i.e., slot was cancelled), so we create a true/false value before 88 * or'ing with hex_reg_written[rnum]. 89 */ 90 tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero); 91 tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask); 92 } 93 94 tcg_temp_free(slot_mask); 95 } 96 97 void gen_log_reg_write(int rnum, TCGv val) 98 { 99 const target_ulong reg_mask = reg_immut_masks[rnum]; 100 101 gen_masked_reg_write(val, hex_gpr[rnum], reg_mask); 102 tcg_gen_mov_tl(hex_new_value[rnum], val); 103 if (HEX_DEBUG) { 104 /* Do this so HELPER(debug_commit_end) will know */ 105 tcg_gen_movi_tl(hex_reg_written[rnum], 1); 106 } 107 } 108 109 static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, 110 uint32_t slot) 111 { 112 TCGv val32 = tcg_temp_new(); 113 TCGv zero = tcg_constant_tl(0); 114 TCGv slot_mask = tcg_temp_new(); 115 116 tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot); 117 /* Low word */ 118 tcg_gen_extrl_i64_i32(val32, val); 119 tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], 120 slot_mask, zero, 121 val32, hex_new_value[rnum]); 122 /* High word */ 123 tcg_gen_extrh_i64_i32(val32, val); 124 tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum + 1], 125 slot_mask, zero, 126 val32, hex_new_value[rnum + 1]); 127 if (HEX_DEBUG) { 128 /* 129 * Do this so HELPER(debug_commit_end) will know 130 * 131 * Note that slot_mask indicates the value is not written 132 * (i.e., slot was cancelled), so we create a true/false value before 133 * or'ing with hex_reg_written[rnum]. 134 */ 135 tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero); 136 tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask); 137 tcg_gen_or_tl(hex_reg_written[rnum + 1], hex_reg_written[rnum + 1], 138 slot_mask); 139 } 140 141 tcg_temp_free(val32); 142 tcg_temp_free(slot_mask); 143 } 144 145 static void gen_log_reg_write_pair(int rnum, TCGv_i64 val) 146 { 147 const target_ulong reg_mask_low = reg_immut_masks[rnum]; 148 const target_ulong reg_mask_high = reg_immut_masks[rnum + 1]; 149 TCGv val32 = tcg_temp_new(); 150 151 /* Low word */ 152 tcg_gen_extrl_i64_i32(val32, val); 153 gen_masked_reg_write(val32, hex_gpr[rnum], reg_mask_low); 154 tcg_gen_mov_tl(hex_new_value[rnum], val32); 155 if (HEX_DEBUG) { 156 /* Do this so HELPER(debug_commit_end) will know */ 157 tcg_gen_movi_tl(hex_reg_written[rnum], 1); 158 } 159 160 /* High word */ 161 tcg_gen_extrh_i64_i32(val32, val); 162 gen_masked_reg_write(val32, hex_gpr[rnum + 1], reg_mask_high); 163 tcg_gen_mov_tl(hex_new_value[rnum + 1], val32); 164 if (HEX_DEBUG) { 165 /* Do this so HELPER(debug_commit_end) will know */ 166 tcg_gen_movi_tl(hex_reg_written[rnum + 1], 1); 167 } 168 169 tcg_temp_free(val32); 170 } 171 172 void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val) 173 { 174 TCGv base_val = tcg_temp_new(); 175 176 tcg_gen_andi_tl(base_val, val, 0xff); 177 178 /* 179 * Section 6.1.3 of the Hexagon V67 Programmer's Reference Manual 180 * 181 * Multiple writes to the same preg are and'ed together 182 * If this is the first predicate write in the packet, do a 183 * straight assignment. Otherwise, do an and. 184 */ 185 if (!test_bit(pnum, ctx->pregs_written)) { 186 tcg_gen_mov_tl(hex_new_pred_value[pnum], base_val); 187 } else { 188 tcg_gen_and_tl(hex_new_pred_value[pnum], 189 hex_new_pred_value[pnum], base_val); 190 } 191 tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << pnum); 192 193 tcg_temp_free(base_val); 194 } 195 196 static inline void gen_read_p3_0(TCGv control_reg) 197 { 198 tcg_gen_movi_tl(control_reg, 0); 199 for (int i = 0; i < NUM_PREGS; i++) { 200 tcg_gen_deposit_tl(control_reg, control_reg, hex_pred[i], i * 8, 8); 201 } 202 } 203 204 /* 205 * Certain control registers require special handling on read 206 * HEX_REG_P3_0_ALIASED aliased to the predicate registers 207 * -> concat the 4 predicate registers together 208 * HEX_REG_PC actual value stored in DisasContext 209 * -> assign from ctx->base.pc_next 210 * HEX_REG_QEMU_*_CNT changes in current TB in DisasContext 211 * -> add current TB changes to existing reg value 212 */ 213 static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num, 214 TCGv dest) 215 { 216 if (reg_num == HEX_REG_P3_0_ALIASED) { 217 gen_read_p3_0(dest); 218 } else if (reg_num == HEX_REG_PC) { 219 tcg_gen_movi_tl(dest, ctx->base.pc_next); 220 } else if (reg_num == HEX_REG_QEMU_PKT_CNT) { 221 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_PKT_CNT], 222 ctx->num_packets); 223 } else if (reg_num == HEX_REG_QEMU_INSN_CNT) { 224 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_INSN_CNT], 225 ctx->num_insns); 226 } else if (reg_num == HEX_REG_QEMU_HVX_CNT) { 227 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_HVX_CNT], 228 ctx->num_hvx_insns); 229 } else { 230 tcg_gen_mov_tl(dest, hex_gpr[reg_num]); 231 } 232 } 233 234 static inline void gen_read_ctrl_reg_pair(DisasContext *ctx, const int reg_num, 235 TCGv_i64 dest) 236 { 237 if (reg_num == HEX_REG_P3_0_ALIASED) { 238 TCGv p3_0 = tcg_temp_new(); 239 gen_read_p3_0(p3_0); 240 tcg_gen_concat_i32_i64(dest, p3_0, hex_gpr[reg_num + 1]); 241 tcg_temp_free(p3_0); 242 } else if (reg_num == HEX_REG_PC - 1) { 243 TCGv pc = tcg_constant_tl(ctx->base.pc_next); 244 tcg_gen_concat_i32_i64(dest, hex_gpr[reg_num], pc); 245 } else if (reg_num == HEX_REG_QEMU_PKT_CNT) { 246 TCGv pkt_cnt = tcg_temp_new(); 247 TCGv insn_cnt = tcg_temp_new(); 248 tcg_gen_addi_tl(pkt_cnt, hex_gpr[HEX_REG_QEMU_PKT_CNT], 249 ctx->num_packets); 250 tcg_gen_addi_tl(insn_cnt, hex_gpr[HEX_REG_QEMU_INSN_CNT], 251 ctx->num_insns); 252 tcg_gen_concat_i32_i64(dest, pkt_cnt, insn_cnt); 253 tcg_temp_free(pkt_cnt); 254 tcg_temp_free(insn_cnt); 255 } else if (reg_num == HEX_REG_QEMU_HVX_CNT) { 256 TCGv hvx_cnt = tcg_temp_new(); 257 tcg_gen_addi_tl(hvx_cnt, hex_gpr[HEX_REG_QEMU_HVX_CNT], 258 ctx->num_hvx_insns); 259 tcg_gen_concat_i32_i64(dest, hvx_cnt, hex_gpr[reg_num + 1]); 260 tcg_temp_free(hvx_cnt); 261 } else { 262 tcg_gen_concat_i32_i64(dest, 263 hex_gpr[reg_num], 264 hex_gpr[reg_num + 1]); 265 } 266 } 267 268 static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg) 269 { 270 TCGv hex_p8 = tcg_temp_new(); 271 for (int i = 0; i < NUM_PREGS; i++) { 272 tcg_gen_extract_tl(hex_p8, control_reg, i * 8, 8); 273 gen_log_pred_write(ctx, i, hex_p8); 274 ctx_log_pred_write(ctx, i); 275 } 276 tcg_temp_free(hex_p8); 277 } 278 279 /* 280 * Certain control registers require special handling on write 281 * HEX_REG_P3_0_ALIASED aliased to the predicate registers 282 * -> break the value across 4 predicate registers 283 * HEX_REG_QEMU_*_CNT changes in current TB in DisasContext 284 * -> clear the changes 285 */ 286 static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num, 287 TCGv val) 288 { 289 if (reg_num == HEX_REG_P3_0_ALIASED) { 290 gen_write_p3_0(ctx, val); 291 } else { 292 gen_log_reg_write(reg_num, val); 293 ctx_log_reg_write(ctx, reg_num); 294 if (reg_num == HEX_REG_QEMU_PKT_CNT) { 295 ctx->num_packets = 0; 296 } 297 if (reg_num == HEX_REG_QEMU_INSN_CNT) { 298 ctx->num_insns = 0; 299 } 300 if (reg_num == HEX_REG_QEMU_HVX_CNT) { 301 ctx->num_hvx_insns = 0; 302 } 303 } 304 } 305 306 static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num, 307 TCGv_i64 val) 308 { 309 if (reg_num == HEX_REG_P3_0_ALIASED) { 310 TCGv val32 = tcg_temp_new(); 311 tcg_gen_extrl_i64_i32(val32, val); 312 gen_write_p3_0(ctx, val32); 313 tcg_gen_extrh_i64_i32(val32, val); 314 gen_log_reg_write(reg_num + 1, val32); 315 tcg_temp_free(val32); 316 ctx_log_reg_write(ctx, reg_num + 1); 317 } else { 318 gen_log_reg_write_pair(reg_num, val); 319 ctx_log_reg_write_pair(ctx, reg_num); 320 if (reg_num == HEX_REG_QEMU_PKT_CNT) { 321 ctx->num_packets = 0; 322 ctx->num_insns = 0; 323 } 324 if (reg_num == HEX_REG_QEMU_HVX_CNT) { 325 ctx->num_hvx_insns = 0; 326 } 327 } 328 } 329 330 TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign) 331 { 332 if (sign) { 333 tcg_gen_sextract_tl(result, src, N * 8, 8); 334 } else { 335 tcg_gen_extract_tl(result, src, N * 8, 8); 336 } 337 return result; 338 } 339 340 TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign) 341 { 342 TCGv_i64 res64 = tcg_temp_new_i64(); 343 if (sign) { 344 tcg_gen_sextract_i64(res64, src, N * 8, 8); 345 } else { 346 tcg_gen_extract_i64(res64, src, N * 8, 8); 347 } 348 tcg_gen_extrl_i64_i32(result, res64); 349 tcg_temp_free_i64(res64); 350 351 return result; 352 } 353 354 TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign) 355 { 356 if (sign) { 357 tcg_gen_sextract_tl(result, src, N * 16, 16); 358 } else { 359 tcg_gen_extract_tl(result, src, N * 16, 16); 360 } 361 return result; 362 } 363 364 void gen_set_half(int N, TCGv result, TCGv src) 365 { 366 tcg_gen_deposit_tl(result, result, src, N * 16, 16); 367 } 368 369 void gen_set_half_i64(int N, TCGv_i64 result, TCGv src) 370 { 371 TCGv_i64 src64 = tcg_temp_new_i64(); 372 tcg_gen_extu_i32_i64(src64, src); 373 tcg_gen_deposit_i64(result, result, src64, N * 16, 16); 374 tcg_temp_free_i64(src64); 375 } 376 377 void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src) 378 { 379 TCGv_i64 src64 = tcg_temp_new_i64(); 380 tcg_gen_extu_i32_i64(src64, src); 381 tcg_gen_deposit_i64(result, result, src64, N * 8, 8); 382 tcg_temp_free_i64(src64); 383 } 384 385 static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index) 386 { 387 tcg_gen_qemu_ld32u(dest, vaddr, mem_index); 388 tcg_gen_mov_tl(hex_llsc_addr, vaddr); 389 tcg_gen_mov_tl(hex_llsc_val, dest); 390 } 391 392 static inline void gen_load_locked8u(TCGv_i64 dest, TCGv vaddr, int mem_index) 393 { 394 tcg_gen_qemu_ld64(dest, vaddr, mem_index); 395 tcg_gen_mov_tl(hex_llsc_addr, vaddr); 396 tcg_gen_mov_i64(hex_llsc_val_i64, dest); 397 } 398 399 static inline void gen_store_conditional4(DisasContext *ctx, 400 TCGv pred, TCGv vaddr, TCGv src) 401 { 402 TCGLabel *fail = gen_new_label(); 403 TCGLabel *done = gen_new_label(); 404 TCGv one, zero, tmp; 405 406 tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail); 407 408 one = tcg_constant_tl(0xff); 409 zero = tcg_constant_tl(0); 410 tmp = tcg_temp_new(); 411 tcg_gen_atomic_cmpxchg_tl(tmp, hex_llsc_addr, hex_llsc_val, src, 412 ctx->mem_idx, MO_32); 413 tcg_gen_movcond_tl(TCG_COND_EQ, pred, tmp, hex_llsc_val, 414 one, zero); 415 tcg_temp_free(tmp); 416 tcg_gen_br(done); 417 418 gen_set_label(fail); 419 tcg_gen_movi_tl(pred, 0); 420 421 gen_set_label(done); 422 tcg_gen_movi_tl(hex_llsc_addr, ~0); 423 } 424 425 static inline void gen_store_conditional8(DisasContext *ctx, 426 TCGv pred, TCGv vaddr, TCGv_i64 src) 427 { 428 TCGLabel *fail = gen_new_label(); 429 TCGLabel *done = gen_new_label(); 430 TCGv_i64 one, zero, tmp; 431 432 tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail); 433 434 one = tcg_constant_i64(0xff); 435 zero = tcg_constant_i64(0); 436 tmp = tcg_temp_new_i64(); 437 tcg_gen_atomic_cmpxchg_i64(tmp, hex_llsc_addr, hex_llsc_val_i64, src, 438 ctx->mem_idx, MO_64); 439 tcg_gen_movcond_i64(TCG_COND_EQ, tmp, tmp, hex_llsc_val_i64, 440 one, zero); 441 tcg_gen_extrl_i64_i32(pred, tmp); 442 tcg_temp_free_i64(tmp); 443 tcg_gen_br(done); 444 445 gen_set_label(fail); 446 tcg_gen_movi_tl(pred, 0); 447 448 gen_set_label(done); 449 tcg_gen_movi_tl(hex_llsc_addr, ~0); 450 } 451 452 void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot) 453 { 454 tcg_gen_mov_tl(hex_store_addr[slot], vaddr); 455 tcg_gen_movi_tl(hex_store_width[slot], width); 456 tcg_gen_mov_tl(hex_store_val32[slot], src); 457 } 458 459 void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot) 460 { 461 gen_store32(vaddr, src, 1, slot); 462 } 463 464 void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot) 465 { 466 TCGv tmp = tcg_constant_tl(src); 467 gen_store1(cpu_env, vaddr, tmp, slot); 468 } 469 470 void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot) 471 { 472 gen_store32(vaddr, src, 2, slot); 473 } 474 475 void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot) 476 { 477 TCGv tmp = tcg_constant_tl(src); 478 gen_store2(cpu_env, vaddr, tmp, slot); 479 } 480 481 void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot) 482 { 483 gen_store32(vaddr, src, 4, slot); 484 } 485 486 void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot) 487 { 488 TCGv tmp = tcg_constant_tl(src); 489 gen_store4(cpu_env, vaddr, tmp, slot); 490 } 491 492 void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, uint32_t slot) 493 { 494 tcg_gen_mov_tl(hex_store_addr[slot], vaddr); 495 tcg_gen_movi_tl(hex_store_width[slot], 8); 496 tcg_gen_mov_i64(hex_store_val64[slot], src); 497 } 498 499 void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, uint32_t slot) 500 { 501 TCGv_i64 tmp = tcg_constant_i64(src); 502 gen_store8(cpu_env, vaddr, tmp, slot); 503 } 504 505 TCGv gen_8bitsof(TCGv result, TCGv value) 506 { 507 TCGv zero = tcg_constant_tl(0); 508 TCGv ones = tcg_constant_tl(0xff); 509 tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero); 510 511 return result; 512 } 513 514 static void gen_write_new_pc_addr(DisasContext *ctx, TCGv addr, 515 TCGCond cond, TCGv pred) 516 { 517 TCGLabel *pred_false = NULL; 518 if (cond != TCG_COND_ALWAYS) { 519 pred_false = gen_new_label(); 520 tcg_gen_brcondi_tl(cond, pred, 0, pred_false); 521 } 522 523 if (ctx->pkt->pkt_has_multi_cof) { 524 /* If there are multiple branches in a packet, ignore the second one */ 525 tcg_gen_movcond_tl(TCG_COND_NE, hex_gpr[HEX_REG_PC], 526 hex_branch_taken, tcg_constant_tl(0), 527 hex_gpr[HEX_REG_PC], addr); 528 tcg_gen_movi_tl(hex_branch_taken, 1); 529 } else { 530 tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], addr); 531 } 532 533 if (cond != TCG_COND_ALWAYS) { 534 gen_set_label(pred_false); 535 } 536 } 537 538 static void gen_write_new_pc_pcrel(DisasContext *ctx, int pc_off, 539 TCGCond cond, TCGv pred) 540 { 541 target_ulong dest = ctx->pkt->pc + pc_off; 542 if (ctx->pkt->pkt_has_multi_cof) { 543 gen_write_new_pc_addr(ctx, tcg_constant_tl(dest), cond, pred); 544 } else { 545 /* Defer this jump to the end of the TB */ 546 ctx->branch_cond = TCG_COND_ALWAYS; 547 if (pred != NULL) { 548 ctx->branch_cond = cond; 549 tcg_gen_mov_tl(hex_branch_taken, pred); 550 } 551 ctx->branch_dest = dest; 552 } 553 } 554 555 void gen_set_usr_field(int field, TCGv val) 556 { 557 tcg_gen_deposit_tl(hex_new_value[HEX_REG_USR], hex_new_value[HEX_REG_USR], 558 val, 559 reg_field_info[field].offset, 560 reg_field_info[field].width); 561 } 562 563 void gen_set_usr_fieldi(int field, int x) 564 { 565 if (reg_field_info[field].width == 1) { 566 target_ulong bit = 1 << reg_field_info[field].offset; 567 if ((x & 1) == 1) { 568 tcg_gen_ori_tl(hex_new_value[HEX_REG_USR], 569 hex_new_value[HEX_REG_USR], 570 bit); 571 } else { 572 tcg_gen_andi_tl(hex_new_value[HEX_REG_USR], 573 hex_new_value[HEX_REG_USR], 574 ~bit); 575 } 576 } else { 577 TCGv val = tcg_constant_tl(x); 578 gen_set_usr_field(field, val); 579 } 580 } 581 582 static void gen_compare(TCGCond cond, TCGv res, TCGv arg1, TCGv arg2) 583 { 584 TCGv one = tcg_constant_tl(0xff); 585 TCGv zero = tcg_constant_tl(0); 586 587 tcg_gen_movcond_tl(cond, res, arg1, arg2, one, zero); 588 } 589 590 static void gen_cond_jumpr(DisasContext *ctx, TCGv dst_pc, 591 TCGCond cond, TCGv pred) 592 { 593 gen_write_new_pc_addr(ctx, dst_pc, cond, pred); 594 } 595 596 static void gen_cond_jump(DisasContext *ctx, TCGCond cond, TCGv pred, 597 int pc_off) 598 { 599 gen_write_new_pc_pcrel(ctx, pc_off, cond, pred); 600 } 601 602 static void gen_cmpnd_cmp_jmp(DisasContext *ctx, 603 int pnum, TCGCond cond1, TCGv arg1, TCGv arg2, 604 TCGCond cond2, int pc_off) 605 { 606 if (ctx->insn->part1) { 607 TCGv pred = tcg_temp_new(); 608 gen_compare(cond1, pred, arg1, arg2); 609 gen_log_pred_write(ctx, pnum, pred); 610 tcg_temp_free(pred); 611 } else { 612 TCGv pred = tcg_temp_new(); 613 tcg_gen_mov_tl(pred, hex_new_pred_value[pnum]); 614 gen_cond_jump(ctx, cond2, pred, pc_off); 615 tcg_temp_free(pred); 616 } 617 } 618 619 static void gen_cmpnd_cmp_jmp_t(DisasContext *ctx, 620 int pnum, TCGCond cond, TCGv arg1, TCGv arg2, 621 int pc_off) 622 { 623 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_EQ, pc_off); 624 } 625 626 static void gen_cmpnd_cmp_jmp_f(DisasContext *ctx, 627 int pnum, TCGCond cond, TCGv arg1, TCGv arg2, 628 int pc_off) 629 { 630 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_NE, pc_off); 631 } 632 633 static void gen_cmpnd_cmpi_jmp_t(DisasContext *ctx, 634 int pnum, TCGCond cond, TCGv arg1, int arg2, 635 int pc_off) 636 { 637 TCGv tmp = tcg_constant_tl(arg2); 638 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_EQ, pc_off); 639 } 640 641 static void gen_cmpnd_cmpi_jmp_f(DisasContext *ctx, 642 int pnum, TCGCond cond, TCGv arg1, int arg2, 643 int pc_off) 644 { 645 TCGv tmp = tcg_constant_tl(arg2); 646 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_NE, pc_off); 647 } 648 649 static void gen_cmpnd_cmp_n1_jmp_t(DisasContext *ctx, int pnum, TCGCond cond, 650 TCGv arg, int pc_off) 651 { 652 gen_cmpnd_cmpi_jmp_t(ctx, pnum, cond, arg, -1, pc_off); 653 } 654 655 static void gen_cmpnd_cmp_n1_jmp_f(DisasContext *ctx, int pnum, TCGCond cond, 656 TCGv arg, int pc_off) 657 { 658 gen_cmpnd_cmpi_jmp_f(ctx, pnum, cond, arg, -1, pc_off); 659 } 660 661 static void gen_cmpnd_tstbit0_jmp(DisasContext *ctx, 662 int pnum, TCGv arg, TCGCond cond, int pc_off) 663 { 664 if (ctx->insn->part1) { 665 TCGv pred = tcg_temp_new(); 666 tcg_gen_andi_tl(pred, arg, 1); 667 gen_8bitsof(pred, pred); 668 gen_log_pred_write(ctx, pnum, pred); 669 tcg_temp_free(pred); 670 } else { 671 TCGv pred = tcg_temp_new(); 672 tcg_gen_mov_tl(pred, hex_new_pred_value[pnum]); 673 gen_cond_jump(ctx, cond, pred, pc_off); 674 tcg_temp_free(pred); 675 } 676 } 677 678 static void gen_testbit0_jumpnv(DisasContext *ctx, 679 TCGv arg, TCGCond cond, int pc_off) 680 { 681 TCGv pred = tcg_temp_new(); 682 tcg_gen_andi_tl(pred, arg, 1); 683 gen_cond_jump(ctx, cond, pred, pc_off); 684 tcg_temp_free(pred); 685 } 686 687 static void gen_jump(DisasContext *ctx, int pc_off) 688 { 689 gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL); 690 } 691 692 static void gen_jumpr(DisasContext *ctx, TCGv new_pc) 693 { 694 gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL); 695 } 696 697 static void gen_call(DisasContext *ctx, int pc_off) 698 { 699 TCGv next_PC = 700 tcg_constant_tl(ctx->pkt->pc + ctx->pkt->encod_pkt_size_in_bytes); 701 gen_log_reg_write(HEX_REG_LR, next_PC); 702 gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL); 703 } 704 705 static void gen_cond_call(DisasContext *ctx, TCGv pred, 706 TCGCond cond, int pc_off) 707 { 708 TCGv next_PC; 709 TCGv lsb = tcg_temp_local_new(); 710 TCGLabel *skip = gen_new_label(); 711 tcg_gen_andi_tl(lsb, pred, 1); 712 gen_write_new_pc_pcrel(ctx, pc_off, cond, lsb); 713 tcg_gen_brcondi_tl(cond, lsb, 0, skip); 714 tcg_temp_free(lsb); 715 next_PC = 716 tcg_constant_tl(ctx->pkt->pc + ctx->pkt->encod_pkt_size_in_bytes); 717 gen_log_reg_write(HEX_REG_LR, next_PC); 718 gen_set_label(skip); 719 } 720 721 static void gen_endloop0(DisasContext *ctx) 722 { 723 TCGv lpcfg = tcg_temp_local_new(); 724 725 GET_USR_FIELD(USR_LPCFG, lpcfg); 726 727 /* 728 * if (lpcfg == 1) { 729 * hex_new_pred_value[3] = 0xff; 730 * hex_pred_written |= 1 << 3; 731 * } 732 */ 733 TCGLabel *label1 = gen_new_label(); 734 tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1); 735 { 736 tcg_gen_movi_tl(hex_new_pred_value[3], 0xff); 737 tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << 3); 738 } 739 gen_set_label(label1); 740 741 /* 742 * if (lpcfg) { 743 * SET_USR_FIELD(USR_LPCFG, lpcfg - 1); 744 * } 745 */ 746 TCGLabel *label2 = gen_new_label(); 747 tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2); 748 { 749 tcg_gen_subi_tl(lpcfg, lpcfg, 1); 750 SET_USR_FIELD(USR_LPCFG, lpcfg); 751 } 752 gen_set_label(label2); 753 754 /* 755 * If we're in a tight loop, we'll do this at the end of the TB to take 756 * advantage of direct block chaining. 757 */ 758 if (!ctx->is_tight_loop) { 759 /* 760 * if (hex_gpr[HEX_REG_LC0] > 1) { 761 * PC = hex_gpr[HEX_REG_SA0]; 762 * hex_new_value[HEX_REG_LC0] = hex_gpr[HEX_REG_LC0] - 1; 763 * } 764 */ 765 TCGLabel *label3 = gen_new_label(); 766 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3); 767 { 768 gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]); 769 tcg_gen_subi_tl(hex_new_value[HEX_REG_LC0], 770 hex_gpr[HEX_REG_LC0], 1); 771 } 772 gen_set_label(label3); 773 } 774 775 tcg_temp_free(lpcfg); 776 } 777 778 static void gen_cmp_jumpnv(DisasContext *ctx, 779 TCGCond cond, TCGv val, TCGv src, int pc_off) 780 { 781 TCGv pred = tcg_temp_new(); 782 tcg_gen_setcond_tl(cond, pred, val, src); 783 gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off); 784 tcg_temp_free(pred); 785 } 786 787 static void gen_cmpi_jumpnv(DisasContext *ctx, 788 TCGCond cond, TCGv val, int src, int pc_off) 789 { 790 TCGv pred = tcg_temp_new(); 791 tcg_gen_setcondi_tl(cond, pred, val, src); 792 gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off); 793 tcg_temp_free(pred); 794 } 795 796 /* Shift left with saturation */ 797 static void gen_shl_sat(TCGv dst, TCGv src, TCGv shift_amt) 798 { 799 TCGv sh32 = tcg_temp_new(); 800 TCGv dst_sar = tcg_temp_new(); 801 TCGv ovf = tcg_temp_new(); 802 TCGv satval = tcg_temp_new(); 803 TCGv min = tcg_constant_tl(0x80000000); 804 TCGv max = tcg_constant_tl(0x7fffffff); 805 806 /* 807 * Possible values for shift_amt are 0 .. 64 808 * We need special handling for values above 31 809 * 810 * sh32 = shift & 31; 811 * dst = sh32 == shift ? src : 0; 812 * dst <<= sh32; 813 * dst_sar = dst >> sh32; 814 * satval = src < 0 ? min : max; 815 * if (dst_asr != src) { 816 * usr.OVF |= 1; 817 * dst = satval; 818 * } 819 */ 820 821 tcg_gen_andi_tl(sh32, shift_amt, 31); 822 tcg_gen_movcond_tl(TCG_COND_EQ, dst, sh32, shift_amt, 823 src, tcg_constant_tl(0)); 824 tcg_gen_shl_tl(dst, dst, sh32); 825 tcg_gen_sar_tl(dst_sar, dst, sh32); 826 tcg_gen_movcond_tl(TCG_COND_LT, satval, src, tcg_constant_tl(0), min, max); 827 828 tcg_gen_setcond_tl(TCG_COND_NE, ovf, dst_sar, src); 829 tcg_gen_shli_tl(ovf, ovf, reg_field_info[USR_OVF].offset); 830 tcg_gen_or_tl(hex_new_value[HEX_REG_USR], hex_new_value[HEX_REG_USR], ovf); 831 832 tcg_gen_movcond_tl(TCG_COND_EQ, dst, dst_sar, src, dst, satval); 833 834 tcg_temp_free(sh32); 835 tcg_temp_free(dst_sar); 836 tcg_temp_free(ovf); 837 tcg_temp_free(satval); 838 } 839 840 static void gen_sar(TCGv dst, TCGv src, TCGv shift_amt) 841 { 842 /* 843 * Shift arithmetic right 844 * Robust when shift_amt is >31 bits 845 */ 846 TCGv tmp = tcg_temp_new(); 847 tcg_gen_umin_tl(tmp, shift_amt, tcg_constant_tl(31)); 848 tcg_gen_sar_tl(dst, src, tmp); 849 tcg_temp_free(tmp); 850 } 851 852 /* Bidirectional shift right with saturation */ 853 static void gen_asr_r_r_sat(TCGv RdV, TCGv RsV, TCGv RtV) 854 { 855 TCGv shift_amt = tcg_temp_local_new(); 856 TCGLabel *positive = gen_new_label(); 857 TCGLabel *done = gen_new_label(); 858 859 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7); 860 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive); 861 862 /* Negative shift amount => shift left */ 863 tcg_gen_neg_tl(shift_amt, shift_amt); 864 gen_shl_sat(RdV, RsV, shift_amt); 865 tcg_gen_br(done); 866 867 gen_set_label(positive); 868 /* Positive shift amount => shift right */ 869 gen_sar(RdV, RsV, shift_amt); 870 871 gen_set_label(done); 872 873 tcg_temp_free(shift_amt); 874 } 875 876 /* Bidirectional shift left with saturation */ 877 static void gen_asl_r_r_sat(TCGv RdV, TCGv RsV, TCGv RtV) 878 { 879 TCGv shift_amt = tcg_temp_local_new(); 880 TCGLabel *positive = gen_new_label(); 881 TCGLabel *done = gen_new_label(); 882 883 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7); 884 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive); 885 886 /* Negative shift amount => shift right */ 887 tcg_gen_neg_tl(shift_amt, shift_amt); 888 gen_sar(RdV, RsV, shift_amt); 889 tcg_gen_br(done); 890 891 gen_set_label(positive); 892 /* Positive shift amount => shift left */ 893 gen_shl_sat(RdV, RsV, shift_amt); 894 895 gen_set_label(done); 896 897 tcg_temp_free(shift_amt); 898 } 899 900 static intptr_t vreg_src_off(DisasContext *ctx, int num) 901 { 902 intptr_t offset = offsetof(CPUHexagonState, VRegs[num]); 903 904 if (test_bit(num, ctx->vregs_select)) { 905 offset = ctx_future_vreg_off(ctx, num, 1, false); 906 } 907 if (test_bit(num, ctx->vregs_updated_tmp)) { 908 offset = ctx_tmp_vreg_off(ctx, num, 1, false); 909 } 910 return offset; 911 } 912 913 static void gen_log_vreg_write(DisasContext *ctx, intptr_t srcoff, int num, 914 VRegWriteType type, int slot_num, 915 bool is_predicated) 916 { 917 TCGLabel *label_end = NULL; 918 intptr_t dstoff; 919 920 if (is_predicated) { 921 TCGv cancelled = tcg_temp_local_new(); 922 label_end = gen_new_label(); 923 924 /* Don't do anything if the slot was cancelled */ 925 tcg_gen_extract_tl(cancelled, hex_slot_cancelled, slot_num, 1); 926 tcg_gen_brcondi_tl(TCG_COND_NE, cancelled, 0, label_end); 927 tcg_temp_free(cancelled); 928 } 929 930 if (type != EXT_TMP) { 931 dstoff = ctx_future_vreg_off(ctx, num, 1, true); 932 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, 933 sizeof(MMVector), sizeof(MMVector)); 934 tcg_gen_ori_tl(hex_VRegs_updated, hex_VRegs_updated, 1 << num); 935 } else { 936 dstoff = ctx_tmp_vreg_off(ctx, num, 1, false); 937 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, 938 sizeof(MMVector), sizeof(MMVector)); 939 } 940 941 if (is_predicated) { 942 gen_set_label(label_end); 943 } 944 } 945 946 static void gen_log_vreg_write_pair(DisasContext *ctx, intptr_t srcoff, int num, 947 VRegWriteType type, int slot_num, 948 bool is_predicated) 949 { 950 gen_log_vreg_write(ctx, srcoff, num ^ 0, type, slot_num, is_predicated); 951 srcoff += sizeof(MMVector); 952 gen_log_vreg_write(ctx, srcoff, num ^ 1, type, slot_num, is_predicated); 953 } 954 955 static void gen_log_qreg_write(intptr_t srcoff, int num, int vnew, 956 int slot_num, bool is_predicated) 957 { 958 TCGLabel *label_end = NULL; 959 intptr_t dstoff; 960 961 if (is_predicated) { 962 TCGv cancelled = tcg_temp_local_new(); 963 label_end = gen_new_label(); 964 965 /* Don't do anything if the slot was cancelled */ 966 tcg_gen_extract_tl(cancelled, hex_slot_cancelled, slot_num, 1); 967 tcg_gen_brcondi_tl(TCG_COND_NE, cancelled, 0, label_end); 968 tcg_temp_free(cancelled); 969 } 970 971 dstoff = offsetof(CPUHexagonState, future_QRegs[num]); 972 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMQReg), sizeof(MMQReg)); 973 974 if (is_predicated) { 975 tcg_gen_ori_tl(hex_QRegs_updated, hex_QRegs_updated, 1 << num); 976 gen_set_label(label_end); 977 } 978 } 979 980 static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src, 981 bool aligned) 982 { 983 TCGv_i64 tmp = tcg_temp_new_i64(); 984 if (aligned) { 985 tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1)); 986 } 987 for (int i = 0; i < sizeof(MMVector) / 8; i++) { 988 tcg_gen_qemu_ld64(tmp, src, ctx->mem_idx); 989 tcg_gen_addi_tl(src, src, 8); 990 tcg_gen_st_i64(tmp, cpu_env, dstoff + i * 8); 991 } 992 tcg_temp_free_i64(tmp); 993 } 994 995 static void gen_vreg_store(DisasContext *ctx, TCGv EA, intptr_t srcoff, 996 int slot, bool aligned) 997 { 998 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data); 999 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask); 1000 1001 if (is_gather_store_insn(ctx)) { 1002 TCGv sl = tcg_constant_tl(slot); 1003 gen_helper_gather_store(cpu_env, EA, sl); 1004 return; 1005 } 1006 1007 tcg_gen_movi_tl(hex_vstore_pending[slot], 1); 1008 if (aligned) { 1009 tcg_gen_andi_tl(hex_vstore_addr[slot], EA, 1010 ~((int32_t)sizeof(MMVector) - 1)); 1011 } else { 1012 tcg_gen_mov_tl(hex_vstore_addr[slot], EA); 1013 } 1014 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector)); 1015 1016 /* Copy the data to the vstore buffer */ 1017 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector)); 1018 /* Set the mask to all 1's */ 1019 tcg_gen_gvec_dup_imm(MO_64, maskoff, sizeof(MMQReg), sizeof(MMQReg), ~0LL); 1020 } 1021 1022 static void gen_vreg_masked_store(DisasContext *ctx, TCGv EA, intptr_t srcoff, 1023 intptr_t bitsoff, int slot, bool invert) 1024 { 1025 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data); 1026 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask); 1027 1028 tcg_gen_movi_tl(hex_vstore_pending[slot], 1); 1029 tcg_gen_andi_tl(hex_vstore_addr[slot], EA, 1030 ~((int32_t)sizeof(MMVector) - 1)); 1031 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector)); 1032 1033 /* Copy the data to the vstore buffer */ 1034 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector)); 1035 /* Copy the mask */ 1036 tcg_gen_gvec_mov(MO_64, maskoff, bitsoff, sizeof(MMQReg), sizeof(MMQReg)); 1037 if (invert) { 1038 tcg_gen_gvec_not(MO_64, maskoff, maskoff, 1039 sizeof(MMQReg), sizeof(MMQReg)); 1040 } 1041 } 1042 1043 static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff) 1044 { 1045 TCGv_i64 tmp = tcg_temp_new_i64(); 1046 TCGv_i64 word = tcg_temp_new_i64(); 1047 TCGv_i64 bits = tcg_temp_new_i64(); 1048 TCGv_i64 mask = tcg_temp_new_i64(); 1049 TCGv_i64 zero = tcg_constant_i64(0); 1050 TCGv_i64 ones = tcg_constant_i64(~0); 1051 1052 for (int i = 0; i < sizeof(MMVector) / 8; i++) { 1053 tcg_gen_ld_i64(tmp, cpu_env, srcoff + i * 8); 1054 tcg_gen_movi_i64(mask, 0); 1055 1056 for (int j = 0; j < 8; j += size) { 1057 tcg_gen_extract_i64(word, tmp, j * 8, size * 8); 1058 tcg_gen_movcond_i64(TCG_COND_NE, bits, word, zero, ones, zero); 1059 tcg_gen_deposit_i64(mask, mask, bits, j, size); 1060 } 1061 1062 tcg_gen_st8_i64(mask, cpu_env, dstoff + i); 1063 } 1064 tcg_temp_free_i64(tmp); 1065 tcg_temp_free_i64(word); 1066 tcg_temp_free_i64(bits); 1067 tcg_temp_free_i64(mask); 1068 } 1069 1070 void probe_noshuf_load(TCGv va, int s, int mi) 1071 { 1072 TCGv size = tcg_constant_tl(s); 1073 TCGv mem_idx = tcg_constant_tl(mi); 1074 gen_helper_probe_noshuf_load(cpu_env, va, size, mem_idx); 1075 } 1076 1077 /* 1078 * Note: Since this function might branch, `val` is 1079 * required to be a `tcg_temp_local`. 1080 */ 1081 void gen_set_usr_field_if(int field, TCGv val) 1082 { 1083 /* Sets the USR field if `val` is non-zero */ 1084 if (reg_field_info[field].width == 1) { 1085 TCGv tmp = tcg_temp_new(); 1086 tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width); 1087 tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset); 1088 tcg_gen_or_tl(hex_new_value[HEX_REG_USR], 1089 hex_new_value[HEX_REG_USR], 1090 tmp); 1091 tcg_temp_free(tmp); 1092 } else { 1093 TCGLabel *skip_label = gen_new_label(); 1094 tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label); 1095 gen_set_usr_field(field, val); 1096 gen_set_label(skip_label); 1097 } 1098 } 1099 1100 void gen_sat_i32(TCGv dest, TCGv source, int width) 1101 { 1102 TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1); 1103 TCGv min_val = tcg_constant_tl(-(1 << (width - 1))); 1104 tcg_gen_smin_tl(dest, source, max_val); 1105 tcg_gen_smax_tl(dest, dest, min_val); 1106 } 1107 1108 void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width) 1109 { 1110 gen_sat_i32(dest, source, width); 1111 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, dest); 1112 } 1113 1114 void gen_satu_i32(TCGv dest, TCGv source, int width) 1115 { 1116 TCGv max_val = tcg_constant_tl((1 << width) - 1); 1117 TCGv zero = tcg_constant_tl(0); 1118 tcg_gen_movcond_tl(TCG_COND_GTU, dest, source, max_val, max_val, source); 1119 tcg_gen_movcond_tl(TCG_COND_LT, dest, source, zero, zero, dest); 1120 } 1121 1122 void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width) 1123 { 1124 gen_satu_i32(dest, source, width); 1125 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, dest); 1126 } 1127 1128 void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width) 1129 { 1130 TCGv_i64 max_val = tcg_constant_i64((1LL << (width - 1)) - 1LL); 1131 TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1))); 1132 tcg_gen_smin_i64(dest, source, max_val); 1133 tcg_gen_smax_i64(dest, dest, min_val); 1134 } 1135 1136 void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width) 1137 { 1138 TCGv_i64 ovfl_64; 1139 gen_sat_i64(dest, source, width); 1140 ovfl_64 = tcg_temp_new_i64(); 1141 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source); 1142 tcg_gen_trunc_i64_tl(ovfl, ovfl_64); 1143 tcg_temp_free_i64(ovfl_64); 1144 } 1145 1146 void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width) 1147 { 1148 TCGv_i64 max_val = tcg_constant_i64((1LL << width) - 1LL); 1149 TCGv_i64 zero = tcg_constant_i64(0); 1150 tcg_gen_movcond_i64(TCG_COND_GTU, dest, source, max_val, max_val, source); 1151 tcg_gen_movcond_i64(TCG_COND_LT, dest, source, zero, zero, dest); 1152 } 1153 1154 void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width) 1155 { 1156 TCGv_i64 ovfl_64; 1157 gen_satu_i64(dest, source, width); 1158 ovfl_64 = tcg_temp_new_i64(); 1159 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source); 1160 tcg_gen_trunc_i64_tl(ovfl, ovfl_64); 1161 tcg_temp_free_i64(ovfl_64); 1162 } 1163 1164 /* Implements the fADDSAT64 macro in TCG */ 1165 void gen_add_sat_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 1166 { 1167 TCGv_i64 sum = tcg_temp_local_new_i64(); 1168 TCGv_i64 xor = tcg_temp_new_i64(); 1169 TCGv_i64 cond1 = tcg_temp_new_i64(); 1170 TCGv_i64 cond2 = tcg_temp_local_new_i64(); 1171 TCGv_i64 cond3 = tcg_temp_new_i64(); 1172 TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL); 1173 TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL); 1174 TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL); 1175 TCGv_i64 zero = tcg_constant_i64(0); 1176 TCGLabel *no_ovfl_label = gen_new_label(); 1177 TCGLabel *ovfl_label = gen_new_label(); 1178 TCGLabel *ret_label = gen_new_label(); 1179 1180 tcg_gen_add_i64(sum, a, b); 1181 tcg_gen_xor_i64(xor, a, b); 1182 1183 /* if (xor & mask) */ 1184 tcg_gen_and_i64(cond1, xor, mask); 1185 tcg_temp_free_i64(xor); 1186 tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label); 1187 tcg_temp_free_i64(cond1); 1188 1189 /* else if ((a ^ sum) & mask) */ 1190 tcg_gen_xor_i64(cond2, a, sum); 1191 tcg_gen_and_i64(cond2, cond2, mask); 1192 tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label); 1193 tcg_temp_free_i64(cond2); 1194 /* fallthrough to no_ovfl_label branch */ 1195 1196 /* if branch */ 1197 gen_set_label(no_ovfl_label); 1198 tcg_gen_mov_i64(ret, sum); 1199 tcg_gen_br(ret_label); 1200 1201 /* else if branch */ 1202 gen_set_label(ovfl_label); 1203 tcg_gen_and_i64(cond3, sum, mask); 1204 tcg_temp_free_i64(mask); 1205 tcg_temp_free_i64(sum); 1206 tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg); 1207 tcg_temp_free_i64(cond3); 1208 SET_USR_FIELD(USR_OVF, 1); 1209 1210 gen_set_label(ret_label); 1211 } 1212 1213 #include "tcg_funcs_generated.c.inc" 1214 #include "tcg_func_table_generated.c.inc" 1215