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