1951c6300SRichard Henderson /* 2951c6300SRichard Henderson * Tiny Code Generator for QEMU 3951c6300SRichard Henderson * 4951c6300SRichard Henderson * Copyright (c) 2008 Fabrice Bellard 5951c6300SRichard Henderson * 6951c6300SRichard Henderson * Permission is hereby granted, free of charge, to any person obtaining a copy 7951c6300SRichard Henderson * of this software and associated documentation files (the "Software"), to deal 8951c6300SRichard Henderson * in the Software without restriction, including without limitation the rights 9951c6300SRichard Henderson * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10951c6300SRichard Henderson * copies of the Software, and to permit persons to whom the Software is 11951c6300SRichard Henderson * furnished to do so, subject to the following conditions: 12951c6300SRichard Henderson * 13951c6300SRichard Henderson * The above copyright notice and this permission notice shall be included in 14951c6300SRichard Henderson * all copies or substantial portions of the Software. 15951c6300SRichard Henderson * 16951c6300SRichard Henderson * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17951c6300SRichard Henderson * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18951c6300SRichard Henderson * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19951c6300SRichard Henderson * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20951c6300SRichard Henderson * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21951c6300SRichard Henderson * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22951c6300SRichard Henderson * THE SOFTWARE. 23951c6300SRichard Henderson */ 24951c6300SRichard Henderson 25757e725bSPeter Maydell #include "qemu/osdep.h" 2663c91552SPaolo Bonzini #include "exec/exec-all.h" 27dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg.h" 28dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 29dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-mo.h" 30dcdaadb6SLluís Vilanova #include "trace-tcg.h" 31dcdaadb6SLluís Vilanova #include "trace/mem.h" 32e6d86bedSEmilio G. Cota #include "exec/plugin-gen.h" 33951c6300SRichard Henderson 343a13c3f3SRichard Henderson /* Reduce the number of ifdefs below. This assumes that all uses of 353a13c3f3SRichard Henderson TCGV_HIGH and TCGV_LOW are properly protected by a conditional that 363a13c3f3SRichard Henderson the compiler can eliminate. */ 373a13c3f3SRichard Henderson #if TCG_TARGET_REG_BITS == 64 383a13c3f3SRichard Henderson extern TCGv_i32 TCGV_LOW_link_error(TCGv_i64); 393a13c3f3SRichard Henderson extern TCGv_i32 TCGV_HIGH_link_error(TCGv_i64); 403a13c3f3SRichard Henderson #define TCGV_LOW TCGV_LOW_link_error 413a13c3f3SRichard Henderson #define TCGV_HIGH TCGV_HIGH_link_error 423a13c3f3SRichard Henderson #endif 43951c6300SRichard Henderson 44b7e8b17aSRichard Henderson void tcg_gen_op1(TCGOpcode opc, TCGArg a1) 45951c6300SRichard Henderson { 46b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 4775e8b9b7SRichard Henderson op->args[0] = a1; 48951c6300SRichard Henderson } 49951c6300SRichard Henderson 50b7e8b17aSRichard Henderson void tcg_gen_op2(TCGOpcode opc, TCGArg a1, TCGArg a2) 51951c6300SRichard Henderson { 52b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 5375e8b9b7SRichard Henderson op->args[0] = a1; 5475e8b9b7SRichard Henderson op->args[1] = a2; 55951c6300SRichard Henderson } 56951c6300SRichard Henderson 57b7e8b17aSRichard Henderson void tcg_gen_op3(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3) 58951c6300SRichard Henderson { 59b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 6075e8b9b7SRichard Henderson op->args[0] = a1; 6175e8b9b7SRichard Henderson op->args[1] = a2; 6275e8b9b7SRichard Henderson op->args[2] = a3; 63951c6300SRichard Henderson } 64951c6300SRichard Henderson 65b7e8b17aSRichard Henderson void tcg_gen_op4(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, TCGArg a4) 66951c6300SRichard Henderson { 67b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 6875e8b9b7SRichard Henderson op->args[0] = a1; 6975e8b9b7SRichard Henderson op->args[1] = a2; 7075e8b9b7SRichard Henderson op->args[2] = a3; 7175e8b9b7SRichard Henderson op->args[3] = a4; 72951c6300SRichard Henderson } 73951c6300SRichard Henderson 74b7e8b17aSRichard Henderson void tcg_gen_op5(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, 75b7e8b17aSRichard Henderson TCGArg a4, TCGArg a5) 76951c6300SRichard Henderson { 77b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 7875e8b9b7SRichard Henderson op->args[0] = a1; 7975e8b9b7SRichard Henderson op->args[1] = a2; 8075e8b9b7SRichard Henderson op->args[2] = a3; 8175e8b9b7SRichard Henderson op->args[3] = a4; 8275e8b9b7SRichard Henderson op->args[4] = a5; 83951c6300SRichard Henderson } 84951c6300SRichard Henderson 85b7e8b17aSRichard Henderson void tcg_gen_op6(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, 86b7e8b17aSRichard Henderson TCGArg a4, TCGArg a5, TCGArg a6) 87951c6300SRichard Henderson { 88b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 8975e8b9b7SRichard Henderson op->args[0] = a1; 9075e8b9b7SRichard Henderson op->args[1] = a2; 9175e8b9b7SRichard Henderson op->args[2] = a3; 9275e8b9b7SRichard Henderson op->args[3] = a4; 9375e8b9b7SRichard Henderson op->args[4] = a5; 9475e8b9b7SRichard Henderson op->args[5] = a6; 95951c6300SRichard Henderson } 96951c6300SRichard Henderson 97f65e19bcSPranith Kumar void tcg_gen_mb(TCGBar mb_type) 98f65e19bcSPranith Kumar { 99b1311c4aSEmilio G. Cota if (tcg_ctx->tb_cflags & CF_PARALLEL) { 100b7e8b17aSRichard Henderson tcg_gen_op1(INDEX_op_mb, mb_type); 101f65e19bcSPranith Kumar } 102f65e19bcSPranith Kumar } 103f65e19bcSPranith Kumar 104951c6300SRichard Henderson /* 32 bit ops */ 105951c6300SRichard Henderson 10611d11d61SRichard Henderson void tcg_gen_movi_i32(TCGv_i32 ret, int32_t arg) 10711d11d61SRichard Henderson { 10811d11d61SRichard Henderson tcg_gen_mov_i32(ret, tcg_constant_i32(arg)); 10911d11d61SRichard Henderson } 11011d11d61SRichard Henderson 111951c6300SRichard Henderson void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 112951c6300SRichard Henderson { 113951c6300SRichard Henderson /* some cases can be optimized here */ 114951c6300SRichard Henderson if (arg2 == 0) { 115951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 116951c6300SRichard Henderson } else { 11711d11d61SRichard Henderson tcg_gen_add_i32(ret, arg1, tcg_constant_i32(arg2)); 118951c6300SRichard Henderson } 119951c6300SRichard Henderson } 120951c6300SRichard Henderson 121951c6300SRichard Henderson void tcg_gen_subfi_i32(TCGv_i32 ret, int32_t arg1, TCGv_i32 arg2) 122951c6300SRichard Henderson { 123951c6300SRichard Henderson if (arg1 == 0 && TCG_TARGET_HAS_neg_i32) { 124951c6300SRichard Henderson /* Don't recurse with tcg_gen_neg_i32. */ 125951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg2); 126951c6300SRichard Henderson } else { 12711d11d61SRichard Henderson tcg_gen_sub_i32(ret, tcg_constant_i32(arg1), arg2); 128951c6300SRichard Henderson } 129951c6300SRichard Henderson } 130951c6300SRichard Henderson 131951c6300SRichard Henderson void tcg_gen_subi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 132951c6300SRichard Henderson { 133951c6300SRichard Henderson /* some cases can be optimized here */ 134951c6300SRichard Henderson if (arg2 == 0) { 135951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 136951c6300SRichard Henderson } else { 13711d11d61SRichard Henderson tcg_gen_sub_i32(ret, arg1, tcg_constant_i32(arg2)); 138951c6300SRichard Henderson } 139951c6300SRichard Henderson } 140951c6300SRichard Henderson 141474b2e8fSRichard Henderson void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 142951c6300SRichard Henderson { 143951c6300SRichard Henderson /* Some cases can be optimized here. */ 144951c6300SRichard Henderson switch (arg2) { 145951c6300SRichard Henderson case 0: 146951c6300SRichard Henderson tcg_gen_movi_i32(ret, 0); 147951c6300SRichard Henderson return; 148474b2e8fSRichard Henderson case -1: 149951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 150951c6300SRichard Henderson return; 151474b2e8fSRichard Henderson case 0xff: 152951c6300SRichard Henderson /* Don't recurse with tcg_gen_ext8u_i32. */ 153951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 154951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg1); 155951c6300SRichard Henderson return; 156951c6300SRichard Henderson } 157951c6300SRichard Henderson break; 158474b2e8fSRichard Henderson case 0xffff: 159951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 160951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg1); 161951c6300SRichard Henderson return; 162951c6300SRichard Henderson } 163951c6300SRichard Henderson break; 164951c6300SRichard Henderson } 16511d11d61SRichard Henderson 16611d11d61SRichard Henderson tcg_gen_and_i32(ret, arg1, tcg_constant_i32(arg2)); 167951c6300SRichard Henderson } 168951c6300SRichard Henderson 169951c6300SRichard Henderson void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 170951c6300SRichard Henderson { 171951c6300SRichard Henderson /* Some cases can be optimized here. */ 172951c6300SRichard Henderson if (arg2 == -1) { 173951c6300SRichard Henderson tcg_gen_movi_i32(ret, -1); 174951c6300SRichard Henderson } else if (arg2 == 0) { 175951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 176951c6300SRichard Henderson } else { 17711d11d61SRichard Henderson tcg_gen_or_i32(ret, arg1, tcg_constant_i32(arg2)); 178951c6300SRichard Henderson } 179951c6300SRichard Henderson } 180951c6300SRichard Henderson 181951c6300SRichard Henderson void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 182951c6300SRichard Henderson { 183951c6300SRichard Henderson /* Some cases can be optimized here. */ 184951c6300SRichard Henderson if (arg2 == 0) { 185951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 186951c6300SRichard Henderson } else if (arg2 == -1 && TCG_TARGET_HAS_not_i32) { 187951c6300SRichard Henderson /* Don't recurse with tcg_gen_not_i32. */ 188951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg1); 189951c6300SRichard Henderson } else { 19011d11d61SRichard Henderson tcg_gen_xor_i32(ret, arg1, tcg_constant_i32(arg2)); 191951c6300SRichard Henderson } 192951c6300SRichard Henderson } 193951c6300SRichard Henderson 194474b2e8fSRichard Henderson void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 195951c6300SRichard Henderson { 196474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 197951c6300SRichard Henderson if (arg2 == 0) { 198951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 199951c6300SRichard Henderson } else { 20011d11d61SRichard Henderson tcg_gen_shl_i32(ret, arg1, tcg_constant_i32(arg2)); 201951c6300SRichard Henderson } 202951c6300SRichard Henderson } 203951c6300SRichard Henderson 204474b2e8fSRichard Henderson void tcg_gen_shri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 205951c6300SRichard Henderson { 206474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 207951c6300SRichard Henderson if (arg2 == 0) { 208951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 209951c6300SRichard Henderson } else { 21011d11d61SRichard Henderson tcg_gen_shr_i32(ret, arg1, tcg_constant_i32(arg2)); 211951c6300SRichard Henderson } 212951c6300SRichard Henderson } 213951c6300SRichard Henderson 214474b2e8fSRichard Henderson void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 215951c6300SRichard Henderson { 216474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 217951c6300SRichard Henderson if (arg2 == 0) { 218951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 219951c6300SRichard Henderson } else { 22011d11d61SRichard Henderson tcg_gen_sar_i32(ret, arg1, tcg_constant_i32(arg2)); 221951c6300SRichard Henderson } 222951c6300SRichard Henderson } 223951c6300SRichard Henderson 22442a268c2SRichard Henderson void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1, TCGv_i32 arg2, TCGLabel *l) 225951c6300SRichard Henderson { 226951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 22742a268c2SRichard Henderson tcg_gen_br(l); 228951c6300SRichard Henderson } else if (cond != TCG_COND_NEVER) { 229d88a117eSRichard Henderson l->refs++; 23042a268c2SRichard Henderson tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_arg(l)); 231951c6300SRichard Henderson } 232951c6300SRichard Henderson } 233951c6300SRichard Henderson 23442a268c2SRichard Henderson void tcg_gen_brcondi_i32(TCGCond cond, TCGv_i32 arg1, int32_t arg2, TCGLabel *l) 235951c6300SRichard Henderson { 23637ed3bf1SRichard Henderson if (cond == TCG_COND_ALWAYS) { 23737ed3bf1SRichard Henderson tcg_gen_br(l); 23837ed3bf1SRichard Henderson } else if (cond != TCG_COND_NEVER) { 23911d11d61SRichard Henderson tcg_gen_brcond_i32(cond, arg1, tcg_constant_i32(arg2), l); 240951c6300SRichard Henderson } 24137ed3bf1SRichard Henderson } 242951c6300SRichard Henderson 243951c6300SRichard Henderson void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret, 244951c6300SRichard Henderson TCGv_i32 arg1, TCGv_i32 arg2) 245951c6300SRichard Henderson { 246951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 247951c6300SRichard Henderson tcg_gen_movi_i32(ret, 1); 248951c6300SRichard Henderson } else if (cond == TCG_COND_NEVER) { 249951c6300SRichard Henderson tcg_gen_movi_i32(ret, 0); 250951c6300SRichard Henderson } else { 251951c6300SRichard Henderson tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond); 252951c6300SRichard Henderson } 253951c6300SRichard Henderson } 254951c6300SRichard Henderson 255951c6300SRichard Henderson void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret, 256951c6300SRichard Henderson TCGv_i32 arg1, int32_t arg2) 257951c6300SRichard Henderson { 25811d11d61SRichard Henderson tcg_gen_setcond_i32(cond, ret, arg1, tcg_constant_i32(arg2)); 259951c6300SRichard Henderson } 260951c6300SRichard Henderson 261951c6300SRichard Henderson void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 262951c6300SRichard Henderson { 263b2e3ae94SRichard Henderson if (arg2 == 0) { 264b2e3ae94SRichard Henderson tcg_gen_movi_i32(ret, 0); 265b2e3ae94SRichard Henderson } else if (is_power_of_2(arg2)) { 266b2e3ae94SRichard Henderson tcg_gen_shli_i32(ret, arg1, ctz32(arg2)); 267b2e3ae94SRichard Henderson } else { 26811d11d61SRichard Henderson tcg_gen_mul_i32(ret, arg1, tcg_constant_i32(arg2)); 269951c6300SRichard Henderson } 270b2e3ae94SRichard Henderson } 271951c6300SRichard Henderson 272951c6300SRichard Henderson void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 273951c6300SRichard Henderson { 274951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i32) { 275951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2); 276951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 277951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 278951c6300SRichard Henderson tcg_gen_sari_i32(t0, arg1, 31); 279951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2); 280951c6300SRichard Henderson tcg_temp_free_i32(t0); 281951c6300SRichard Henderson } else { 282951c6300SRichard Henderson gen_helper_div_i32(ret, arg1, arg2); 283951c6300SRichard Henderson } 284951c6300SRichard Henderson } 285951c6300SRichard Henderson 286951c6300SRichard Henderson void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 287951c6300SRichard Henderson { 288951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i32) { 289951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2); 290951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i32) { 291951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 292951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_div_i32, t0, arg1, arg2); 293951c6300SRichard Henderson tcg_gen_mul_i32(t0, t0, arg2); 294951c6300SRichard Henderson tcg_gen_sub_i32(ret, arg1, t0); 295951c6300SRichard Henderson tcg_temp_free_i32(t0); 296951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 297951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 298951c6300SRichard Henderson tcg_gen_sari_i32(t0, arg1, 31); 299951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2); 300951c6300SRichard Henderson tcg_temp_free_i32(t0); 301951c6300SRichard Henderson } else { 302951c6300SRichard Henderson gen_helper_rem_i32(ret, arg1, arg2); 303951c6300SRichard Henderson } 304951c6300SRichard Henderson } 305951c6300SRichard Henderson 306951c6300SRichard Henderson void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 307951c6300SRichard Henderson { 308951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i32) { 309951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2); 310951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 311951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 312951c6300SRichard Henderson tcg_gen_movi_i32(t0, 0); 313951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2); 314951c6300SRichard Henderson tcg_temp_free_i32(t0); 315951c6300SRichard Henderson } else { 316951c6300SRichard Henderson gen_helper_divu_i32(ret, arg1, arg2); 317951c6300SRichard Henderson } 318951c6300SRichard Henderson } 319951c6300SRichard Henderson 320951c6300SRichard Henderson void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 321951c6300SRichard Henderson { 322951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i32) { 323951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2); 324951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i32) { 325951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 326951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_divu_i32, t0, arg1, arg2); 327951c6300SRichard Henderson tcg_gen_mul_i32(t0, t0, arg2); 328951c6300SRichard Henderson tcg_gen_sub_i32(ret, arg1, t0); 329951c6300SRichard Henderson tcg_temp_free_i32(t0); 330951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 331951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 332951c6300SRichard Henderson tcg_gen_movi_i32(t0, 0); 333951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2); 334951c6300SRichard Henderson tcg_temp_free_i32(t0); 335951c6300SRichard Henderson } else { 336951c6300SRichard Henderson gen_helper_remu_i32(ret, arg1, arg2); 337951c6300SRichard Henderson } 338951c6300SRichard Henderson } 339951c6300SRichard Henderson 340951c6300SRichard Henderson void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 341951c6300SRichard Henderson { 342951c6300SRichard Henderson if (TCG_TARGET_HAS_andc_i32) { 343951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2); 344951c6300SRichard Henderson } else { 345951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 346951c6300SRichard Henderson tcg_gen_not_i32(t0, arg2); 347951c6300SRichard Henderson tcg_gen_and_i32(ret, arg1, t0); 348951c6300SRichard Henderson tcg_temp_free_i32(t0); 349951c6300SRichard Henderson } 350951c6300SRichard Henderson } 351951c6300SRichard Henderson 352951c6300SRichard Henderson void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 353951c6300SRichard Henderson { 354951c6300SRichard Henderson if (TCG_TARGET_HAS_eqv_i32) { 355951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_eqv_i32, ret, arg1, arg2); 356951c6300SRichard Henderson } else { 357951c6300SRichard Henderson tcg_gen_xor_i32(ret, arg1, arg2); 358951c6300SRichard Henderson tcg_gen_not_i32(ret, ret); 359951c6300SRichard Henderson } 360951c6300SRichard Henderson } 361951c6300SRichard Henderson 362951c6300SRichard Henderson void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 363951c6300SRichard Henderson { 364951c6300SRichard Henderson if (TCG_TARGET_HAS_nand_i32) { 365951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_nand_i32, ret, arg1, arg2); 366951c6300SRichard Henderson } else { 367951c6300SRichard Henderson tcg_gen_and_i32(ret, arg1, arg2); 368951c6300SRichard Henderson tcg_gen_not_i32(ret, ret); 369951c6300SRichard Henderson } 370951c6300SRichard Henderson } 371951c6300SRichard Henderson 372951c6300SRichard Henderson void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 373951c6300SRichard Henderson { 374951c6300SRichard Henderson if (TCG_TARGET_HAS_nor_i32) { 375951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_nor_i32, ret, arg1, arg2); 376951c6300SRichard Henderson } else { 377951c6300SRichard Henderson tcg_gen_or_i32(ret, arg1, arg2); 378951c6300SRichard Henderson tcg_gen_not_i32(ret, ret); 379951c6300SRichard Henderson } 380951c6300SRichard Henderson } 381951c6300SRichard Henderson 382951c6300SRichard Henderson void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 383951c6300SRichard Henderson { 384951c6300SRichard Henderson if (TCG_TARGET_HAS_orc_i32) { 385951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2); 386951c6300SRichard Henderson } else { 387951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 388951c6300SRichard Henderson tcg_gen_not_i32(t0, arg2); 389951c6300SRichard Henderson tcg_gen_or_i32(ret, arg1, t0); 390951c6300SRichard Henderson tcg_temp_free_i32(t0); 391951c6300SRichard Henderson } 392951c6300SRichard Henderson } 393951c6300SRichard Henderson 3940e28d006SRichard Henderson void tcg_gen_clz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 3950e28d006SRichard Henderson { 3960e28d006SRichard Henderson if (TCG_TARGET_HAS_clz_i32) { 3970e28d006SRichard Henderson tcg_gen_op3_i32(INDEX_op_clz_i32, ret, arg1, arg2); 3980e28d006SRichard Henderson } else if (TCG_TARGET_HAS_clz_i64) { 3990e28d006SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 4000e28d006SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 4010e28d006SRichard Henderson tcg_gen_extu_i32_i64(t1, arg1); 4020e28d006SRichard Henderson tcg_gen_extu_i32_i64(t2, arg2); 4030e28d006SRichard Henderson tcg_gen_addi_i64(t2, t2, 32); 4040e28d006SRichard Henderson tcg_gen_clz_i64(t1, t1, t2); 4050e28d006SRichard Henderson tcg_gen_extrl_i64_i32(ret, t1); 4060e28d006SRichard Henderson tcg_temp_free_i64(t1); 4070e28d006SRichard Henderson tcg_temp_free_i64(t2); 4080e28d006SRichard Henderson tcg_gen_subi_i32(ret, ret, 32); 4090e28d006SRichard Henderson } else { 4100e28d006SRichard Henderson gen_helper_clz_i32(ret, arg1, arg2); 4110e28d006SRichard Henderson } 4120e28d006SRichard Henderson } 4130e28d006SRichard Henderson 4140e28d006SRichard Henderson void tcg_gen_clzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) 4150e28d006SRichard Henderson { 41611d11d61SRichard Henderson tcg_gen_clz_i32(ret, arg1, tcg_constant_i32(arg2)); 4170e28d006SRichard Henderson } 4180e28d006SRichard Henderson 4190e28d006SRichard Henderson void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 4200e28d006SRichard Henderson { 4210e28d006SRichard Henderson if (TCG_TARGET_HAS_ctz_i32) { 4220e28d006SRichard Henderson tcg_gen_op3_i32(INDEX_op_ctz_i32, ret, arg1, arg2); 4230e28d006SRichard Henderson } else if (TCG_TARGET_HAS_ctz_i64) { 4240e28d006SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 4250e28d006SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 4260e28d006SRichard Henderson tcg_gen_extu_i32_i64(t1, arg1); 4270e28d006SRichard Henderson tcg_gen_extu_i32_i64(t2, arg2); 4280e28d006SRichard Henderson tcg_gen_ctz_i64(t1, t1, t2); 4290e28d006SRichard Henderson tcg_gen_extrl_i64_i32(ret, t1); 4300e28d006SRichard Henderson tcg_temp_free_i64(t1); 4310e28d006SRichard Henderson tcg_temp_free_i64(t2); 43214e99210SRichard Henderson } else if (TCG_TARGET_HAS_ctpop_i32 43314e99210SRichard Henderson || TCG_TARGET_HAS_ctpop_i64 43414e99210SRichard Henderson || TCG_TARGET_HAS_clz_i32 43514e99210SRichard Henderson || TCG_TARGET_HAS_clz_i64) { 43614e99210SRichard Henderson TCGv_i32 z, t = tcg_temp_new_i32(); 43714e99210SRichard Henderson 43814e99210SRichard Henderson if (TCG_TARGET_HAS_ctpop_i32 || TCG_TARGET_HAS_ctpop_i64) { 43914e99210SRichard Henderson tcg_gen_subi_i32(t, arg1, 1); 44014e99210SRichard Henderson tcg_gen_andc_i32(t, t, arg1); 44114e99210SRichard Henderson tcg_gen_ctpop_i32(t, t); 44214e99210SRichard Henderson } else { 44314e99210SRichard Henderson /* Since all non-x86 hosts have clz(0) == 32, don't fight it. */ 44414e99210SRichard Henderson tcg_gen_neg_i32(t, arg1); 44514e99210SRichard Henderson tcg_gen_and_i32(t, t, arg1); 44614e99210SRichard Henderson tcg_gen_clzi_i32(t, t, 32); 44714e99210SRichard Henderson tcg_gen_xori_i32(t, t, 31); 44814e99210SRichard Henderson } 44911d11d61SRichard Henderson z = tcg_constant_i32(0); 45014e99210SRichard Henderson tcg_gen_movcond_i32(TCG_COND_EQ, ret, arg1, z, arg2, t); 45114e99210SRichard Henderson tcg_temp_free_i32(t); 4520e28d006SRichard Henderson } else { 4530e28d006SRichard Henderson gen_helper_ctz_i32(ret, arg1, arg2); 4540e28d006SRichard Henderson } 4550e28d006SRichard Henderson } 4560e28d006SRichard Henderson 4570e28d006SRichard Henderson void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) 4580e28d006SRichard Henderson { 45914e99210SRichard Henderson if (!TCG_TARGET_HAS_ctz_i32 && TCG_TARGET_HAS_ctpop_i32 && arg2 == 32) { 46014e99210SRichard Henderson /* This equivalence has the advantage of not requiring a fixup. */ 46114e99210SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 46214e99210SRichard Henderson tcg_gen_subi_i32(t, arg1, 1); 46314e99210SRichard Henderson tcg_gen_andc_i32(t, t, arg1); 46414e99210SRichard Henderson tcg_gen_ctpop_i32(ret, t); 46514e99210SRichard Henderson tcg_temp_free_i32(t); 46614e99210SRichard Henderson } else { 46711d11d61SRichard Henderson tcg_gen_ctz_i32(ret, arg1, tcg_constant_i32(arg2)); 4680e28d006SRichard Henderson } 46914e99210SRichard Henderson } 4700e28d006SRichard Henderson 471086920c2SRichard Henderson void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg) 472086920c2SRichard Henderson { 473086920c2SRichard Henderson if (TCG_TARGET_HAS_clz_i32) { 474086920c2SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 475086920c2SRichard Henderson tcg_gen_sari_i32(t, arg, 31); 476086920c2SRichard Henderson tcg_gen_xor_i32(t, t, arg); 477086920c2SRichard Henderson tcg_gen_clzi_i32(t, t, 32); 478086920c2SRichard Henderson tcg_gen_subi_i32(ret, t, 1); 479086920c2SRichard Henderson tcg_temp_free_i32(t); 480086920c2SRichard Henderson } else { 481086920c2SRichard Henderson gen_helper_clrsb_i32(ret, arg); 482086920c2SRichard Henderson } 483086920c2SRichard Henderson } 484086920c2SRichard Henderson 485a768e4e9SRichard Henderson void tcg_gen_ctpop_i32(TCGv_i32 ret, TCGv_i32 arg1) 486a768e4e9SRichard Henderson { 487a768e4e9SRichard Henderson if (TCG_TARGET_HAS_ctpop_i32) { 488a768e4e9SRichard Henderson tcg_gen_op2_i32(INDEX_op_ctpop_i32, ret, arg1); 489a768e4e9SRichard Henderson } else if (TCG_TARGET_HAS_ctpop_i64) { 490a768e4e9SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 491a768e4e9SRichard Henderson tcg_gen_extu_i32_i64(t, arg1); 492a768e4e9SRichard Henderson tcg_gen_ctpop_i64(t, t); 493a768e4e9SRichard Henderson tcg_gen_extrl_i64_i32(ret, t); 494a768e4e9SRichard Henderson tcg_temp_free_i64(t); 495a768e4e9SRichard Henderson } else { 496a768e4e9SRichard Henderson gen_helper_ctpop_i32(ret, arg1); 497a768e4e9SRichard Henderson } 498a768e4e9SRichard Henderson } 499a768e4e9SRichard Henderson 500951c6300SRichard Henderson void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 501951c6300SRichard Henderson { 502951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i32) { 503951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2); 504951c6300SRichard Henderson } else { 505951c6300SRichard Henderson TCGv_i32 t0, t1; 506951c6300SRichard Henderson 507951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 508951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 509951c6300SRichard Henderson tcg_gen_shl_i32(t0, arg1, arg2); 510951c6300SRichard Henderson tcg_gen_subfi_i32(t1, 32, arg2); 511951c6300SRichard Henderson tcg_gen_shr_i32(t1, arg1, t1); 512951c6300SRichard Henderson tcg_gen_or_i32(ret, t0, t1); 513951c6300SRichard Henderson tcg_temp_free_i32(t0); 514951c6300SRichard Henderson tcg_temp_free_i32(t1); 515951c6300SRichard Henderson } 516951c6300SRichard Henderson } 517951c6300SRichard Henderson 51807dada03SRichard Henderson void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 519951c6300SRichard Henderson { 52007dada03SRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 521951c6300SRichard Henderson /* some cases can be optimized here */ 522951c6300SRichard Henderson if (arg2 == 0) { 523951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 524951c6300SRichard Henderson } else if (TCG_TARGET_HAS_rot_i32) { 52511d11d61SRichard Henderson tcg_gen_rotl_i32(ret, arg1, tcg_constant_i32(arg2)); 526951c6300SRichard Henderson } else { 527951c6300SRichard Henderson TCGv_i32 t0, t1; 528951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 529951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 530951c6300SRichard Henderson tcg_gen_shli_i32(t0, arg1, arg2); 531951c6300SRichard Henderson tcg_gen_shri_i32(t1, arg1, 32 - arg2); 532951c6300SRichard Henderson tcg_gen_or_i32(ret, t0, t1); 533951c6300SRichard Henderson tcg_temp_free_i32(t0); 534951c6300SRichard Henderson tcg_temp_free_i32(t1); 535951c6300SRichard Henderson } 536951c6300SRichard Henderson } 537951c6300SRichard Henderson 538951c6300SRichard Henderson void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 539951c6300SRichard Henderson { 540951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i32) { 541951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2); 542951c6300SRichard Henderson } else { 543951c6300SRichard Henderson TCGv_i32 t0, t1; 544951c6300SRichard Henderson 545951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 546951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 547951c6300SRichard Henderson tcg_gen_shr_i32(t0, arg1, arg2); 548951c6300SRichard Henderson tcg_gen_subfi_i32(t1, 32, arg2); 549951c6300SRichard Henderson tcg_gen_shl_i32(t1, arg1, t1); 550951c6300SRichard Henderson tcg_gen_or_i32(ret, t0, t1); 551951c6300SRichard Henderson tcg_temp_free_i32(t0); 552951c6300SRichard Henderson tcg_temp_free_i32(t1); 553951c6300SRichard Henderson } 554951c6300SRichard Henderson } 555951c6300SRichard Henderson 55607dada03SRichard Henderson void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 557951c6300SRichard Henderson { 55807dada03SRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 559951c6300SRichard Henderson /* some cases can be optimized here */ 560951c6300SRichard Henderson if (arg2 == 0) { 561951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 562951c6300SRichard Henderson } else { 563951c6300SRichard Henderson tcg_gen_rotli_i32(ret, arg1, 32 - arg2); 564951c6300SRichard Henderson } 565951c6300SRichard Henderson } 566951c6300SRichard Henderson 567951c6300SRichard Henderson void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2, 568951c6300SRichard Henderson unsigned int ofs, unsigned int len) 569951c6300SRichard Henderson { 570951c6300SRichard Henderson uint32_t mask; 571951c6300SRichard Henderson TCGv_i32 t1; 572951c6300SRichard Henderson 573951c6300SRichard Henderson tcg_debug_assert(ofs < 32); 5740d0d309dSRichard Henderson tcg_debug_assert(len > 0); 575951c6300SRichard Henderson tcg_debug_assert(len <= 32); 576951c6300SRichard Henderson tcg_debug_assert(ofs + len <= 32); 577951c6300SRichard Henderson 5780d0d309dSRichard Henderson if (len == 32) { 579951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg2); 580951c6300SRichard Henderson return; 581951c6300SRichard Henderson } 582951c6300SRichard Henderson if (TCG_TARGET_HAS_deposit_i32 && TCG_TARGET_deposit_i32_valid(ofs, len)) { 583951c6300SRichard Henderson tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len); 584951c6300SRichard Henderson return; 585951c6300SRichard Henderson } 586951c6300SRichard Henderson 587951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 588951c6300SRichard Henderson 589b0a60567SRichard Henderson if (TCG_TARGET_HAS_extract2_i32) { 590b0a60567SRichard Henderson if (ofs + len == 32) { 591b0a60567SRichard Henderson tcg_gen_shli_i32(t1, arg1, len); 592b0a60567SRichard Henderson tcg_gen_extract2_i32(ret, t1, arg2, len); 593b0a60567SRichard Henderson goto done; 594b0a60567SRichard Henderson } 595b0a60567SRichard Henderson if (ofs == 0) { 596b0a60567SRichard Henderson tcg_gen_extract2_i32(ret, arg1, arg2, len); 597b0a60567SRichard Henderson tcg_gen_rotli_i32(ret, ret, len); 598b0a60567SRichard Henderson goto done; 599b0a60567SRichard Henderson } 600b0a60567SRichard Henderson } 601b0a60567SRichard Henderson 602b0a60567SRichard Henderson mask = (1u << len) - 1; 603951c6300SRichard Henderson if (ofs + len < 32) { 604951c6300SRichard Henderson tcg_gen_andi_i32(t1, arg2, mask); 605951c6300SRichard Henderson tcg_gen_shli_i32(t1, t1, ofs); 606951c6300SRichard Henderson } else { 607951c6300SRichard Henderson tcg_gen_shli_i32(t1, arg2, ofs); 608951c6300SRichard Henderson } 609951c6300SRichard Henderson tcg_gen_andi_i32(ret, arg1, ~(mask << ofs)); 610951c6300SRichard Henderson tcg_gen_or_i32(ret, ret, t1); 611b0a60567SRichard Henderson done: 612951c6300SRichard Henderson tcg_temp_free_i32(t1); 613951c6300SRichard Henderson } 614951c6300SRichard Henderson 61507cc68d5SRichard Henderson void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg, 61607cc68d5SRichard Henderson unsigned int ofs, unsigned int len) 61707cc68d5SRichard Henderson { 61807cc68d5SRichard Henderson tcg_debug_assert(ofs < 32); 61907cc68d5SRichard Henderson tcg_debug_assert(len > 0); 62007cc68d5SRichard Henderson tcg_debug_assert(len <= 32); 62107cc68d5SRichard Henderson tcg_debug_assert(ofs + len <= 32); 62207cc68d5SRichard Henderson 62307cc68d5SRichard Henderson if (ofs + len == 32) { 62407cc68d5SRichard Henderson tcg_gen_shli_i32(ret, arg, ofs); 62507cc68d5SRichard Henderson } else if (ofs == 0) { 62607cc68d5SRichard Henderson tcg_gen_andi_i32(ret, arg, (1u << len) - 1); 62707cc68d5SRichard Henderson } else if (TCG_TARGET_HAS_deposit_i32 62807cc68d5SRichard Henderson && TCG_TARGET_deposit_i32_valid(ofs, len)) { 62911d11d61SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0); 63007cc68d5SRichard Henderson tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, zero, arg, ofs, len); 63107cc68d5SRichard Henderson } else { 63207cc68d5SRichard Henderson /* To help two-operand hosts we prefer to zero-extend first, 63307cc68d5SRichard Henderson which allows ARG to stay live. */ 63407cc68d5SRichard Henderson switch (len) { 63507cc68d5SRichard Henderson case 16: 63607cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 63707cc68d5SRichard Henderson tcg_gen_ext16u_i32(ret, arg); 63807cc68d5SRichard Henderson tcg_gen_shli_i32(ret, ret, ofs); 63907cc68d5SRichard Henderson return; 64007cc68d5SRichard Henderson } 64107cc68d5SRichard Henderson break; 64207cc68d5SRichard Henderson case 8: 64307cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 64407cc68d5SRichard Henderson tcg_gen_ext8u_i32(ret, arg); 64507cc68d5SRichard Henderson tcg_gen_shli_i32(ret, ret, ofs); 64607cc68d5SRichard Henderson return; 64707cc68d5SRichard Henderson } 64807cc68d5SRichard Henderson break; 64907cc68d5SRichard Henderson } 65007cc68d5SRichard Henderson /* Otherwise prefer zero-extension over AND for code size. */ 65107cc68d5SRichard Henderson switch (ofs + len) { 65207cc68d5SRichard Henderson case 16: 65307cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 65407cc68d5SRichard Henderson tcg_gen_shli_i32(ret, arg, ofs); 65507cc68d5SRichard Henderson tcg_gen_ext16u_i32(ret, ret); 65607cc68d5SRichard Henderson return; 65707cc68d5SRichard Henderson } 65807cc68d5SRichard Henderson break; 65907cc68d5SRichard Henderson case 8: 66007cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 66107cc68d5SRichard Henderson tcg_gen_shli_i32(ret, arg, ofs); 66207cc68d5SRichard Henderson tcg_gen_ext8u_i32(ret, ret); 66307cc68d5SRichard Henderson return; 66407cc68d5SRichard Henderson } 66507cc68d5SRichard Henderson break; 66607cc68d5SRichard Henderson } 66707cc68d5SRichard Henderson tcg_gen_andi_i32(ret, arg, (1u << len) - 1); 66807cc68d5SRichard Henderson tcg_gen_shli_i32(ret, ret, ofs); 66907cc68d5SRichard Henderson } 67007cc68d5SRichard Henderson } 67107cc68d5SRichard Henderson 6727ec8bab3SRichard Henderson void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg, 6737ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 6747ec8bab3SRichard Henderson { 6757ec8bab3SRichard Henderson tcg_debug_assert(ofs < 32); 6767ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 6777ec8bab3SRichard Henderson tcg_debug_assert(len <= 32); 6787ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 32); 6797ec8bab3SRichard Henderson 6807ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if extract is supported. */ 6817ec8bab3SRichard Henderson if (ofs + len == 32) { 6827ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, 32 - len); 6837ec8bab3SRichard Henderson return; 6847ec8bab3SRichard Henderson } 6857ec8bab3SRichard Henderson if (ofs == 0) { 6867ec8bab3SRichard Henderson tcg_gen_andi_i32(ret, arg, (1u << len) - 1); 6877ec8bab3SRichard Henderson return; 6887ec8bab3SRichard Henderson } 6897ec8bab3SRichard Henderson 6907ec8bab3SRichard Henderson if (TCG_TARGET_HAS_extract_i32 6917ec8bab3SRichard Henderson && TCG_TARGET_extract_i32_valid(ofs, len)) { 6927ec8bab3SRichard Henderson tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, ofs, len); 6937ec8bab3SRichard Henderson return; 6947ec8bab3SRichard Henderson } 6957ec8bab3SRichard Henderson 6967ec8bab3SRichard Henderson /* Assume that zero-extension, if available, is cheaper than a shift. */ 6977ec8bab3SRichard Henderson switch (ofs + len) { 6987ec8bab3SRichard Henderson case 16: 6997ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 7007ec8bab3SRichard Henderson tcg_gen_ext16u_i32(ret, arg); 7017ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, ret, ofs); 7027ec8bab3SRichard Henderson return; 7037ec8bab3SRichard Henderson } 7047ec8bab3SRichard Henderson break; 7057ec8bab3SRichard Henderson case 8: 7067ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 7077ec8bab3SRichard Henderson tcg_gen_ext8u_i32(ret, arg); 7087ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, ret, ofs); 7097ec8bab3SRichard Henderson return; 7107ec8bab3SRichard Henderson } 7117ec8bab3SRichard Henderson break; 7127ec8bab3SRichard Henderson } 7137ec8bab3SRichard Henderson 7147ec8bab3SRichard Henderson /* ??? Ideally we'd know what values are available for immediate AND. 7157ec8bab3SRichard Henderson Assume that 8 bits are available, plus the special case of 16, 7167ec8bab3SRichard Henderson so that we get ext8u, ext16u. */ 7177ec8bab3SRichard Henderson switch (len) { 7187ec8bab3SRichard Henderson case 1 ... 8: case 16: 7197ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, ofs); 7207ec8bab3SRichard Henderson tcg_gen_andi_i32(ret, ret, (1u << len) - 1); 7217ec8bab3SRichard Henderson break; 7227ec8bab3SRichard Henderson default: 7237ec8bab3SRichard Henderson tcg_gen_shli_i32(ret, arg, 32 - len - ofs); 7247ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, ret, 32 - len); 7257ec8bab3SRichard Henderson break; 7267ec8bab3SRichard Henderson } 7277ec8bab3SRichard Henderson } 7287ec8bab3SRichard Henderson 7297ec8bab3SRichard Henderson void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg, 7307ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 7317ec8bab3SRichard Henderson { 7327ec8bab3SRichard Henderson tcg_debug_assert(ofs < 32); 7337ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 7347ec8bab3SRichard Henderson tcg_debug_assert(len <= 32); 7357ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 32); 7367ec8bab3SRichard Henderson 7377ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if extract is supported. */ 7387ec8bab3SRichard Henderson if (ofs + len == 32) { 7397ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, arg, 32 - len); 7407ec8bab3SRichard Henderson return; 7417ec8bab3SRichard Henderson } 7427ec8bab3SRichard Henderson if (ofs == 0) { 7437ec8bab3SRichard Henderson switch (len) { 7447ec8bab3SRichard Henderson case 16: 7457ec8bab3SRichard Henderson tcg_gen_ext16s_i32(ret, arg); 7467ec8bab3SRichard Henderson return; 7477ec8bab3SRichard Henderson case 8: 7487ec8bab3SRichard Henderson tcg_gen_ext8s_i32(ret, arg); 7497ec8bab3SRichard Henderson return; 7507ec8bab3SRichard Henderson } 7517ec8bab3SRichard Henderson } 7527ec8bab3SRichard Henderson 7537ec8bab3SRichard Henderson if (TCG_TARGET_HAS_sextract_i32 7547ec8bab3SRichard Henderson && TCG_TARGET_extract_i32_valid(ofs, len)) { 7557ec8bab3SRichard Henderson tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, ofs, len); 7567ec8bab3SRichard Henderson return; 7577ec8bab3SRichard Henderson } 7587ec8bab3SRichard Henderson 7597ec8bab3SRichard Henderson /* Assume that sign-extension, if available, is cheaper than a shift. */ 7607ec8bab3SRichard Henderson switch (ofs + len) { 7617ec8bab3SRichard Henderson case 16: 7627ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i32) { 7637ec8bab3SRichard Henderson tcg_gen_ext16s_i32(ret, arg); 7647ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, ret, ofs); 7657ec8bab3SRichard Henderson return; 7667ec8bab3SRichard Henderson } 7677ec8bab3SRichard Henderson break; 7687ec8bab3SRichard Henderson case 8: 7697ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i32) { 7707ec8bab3SRichard Henderson tcg_gen_ext8s_i32(ret, arg); 7717ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, ret, ofs); 7727ec8bab3SRichard Henderson return; 7737ec8bab3SRichard Henderson } 7747ec8bab3SRichard Henderson break; 7757ec8bab3SRichard Henderson } 7767ec8bab3SRichard Henderson switch (len) { 7777ec8bab3SRichard Henderson case 16: 7787ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i32) { 7797ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, ofs); 7807ec8bab3SRichard Henderson tcg_gen_ext16s_i32(ret, ret); 7817ec8bab3SRichard Henderson return; 7827ec8bab3SRichard Henderson } 7837ec8bab3SRichard Henderson break; 7847ec8bab3SRichard Henderson case 8: 7857ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i32) { 7867ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, ofs); 7877ec8bab3SRichard Henderson tcg_gen_ext8s_i32(ret, ret); 7887ec8bab3SRichard Henderson return; 7897ec8bab3SRichard Henderson } 7907ec8bab3SRichard Henderson break; 7917ec8bab3SRichard Henderson } 7927ec8bab3SRichard Henderson 7937ec8bab3SRichard Henderson tcg_gen_shli_i32(ret, arg, 32 - len - ofs); 7947ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, ret, 32 - len); 7957ec8bab3SRichard Henderson } 7967ec8bab3SRichard Henderson 7972089fcc9SDavid Hildenbrand /* 7982089fcc9SDavid Hildenbrand * Extract 32-bits from a 64-bit input, ah:al, starting from ofs. 7992089fcc9SDavid Hildenbrand * Unlike tcg_gen_extract_i32 above, len is fixed at 32. 8002089fcc9SDavid Hildenbrand */ 8012089fcc9SDavid Hildenbrand void tcg_gen_extract2_i32(TCGv_i32 ret, TCGv_i32 al, TCGv_i32 ah, 8022089fcc9SDavid Hildenbrand unsigned int ofs) 8032089fcc9SDavid Hildenbrand { 8042089fcc9SDavid Hildenbrand tcg_debug_assert(ofs <= 32); 8052089fcc9SDavid Hildenbrand if (ofs == 0) { 8062089fcc9SDavid Hildenbrand tcg_gen_mov_i32(ret, al); 8072089fcc9SDavid Hildenbrand } else if (ofs == 32) { 8082089fcc9SDavid Hildenbrand tcg_gen_mov_i32(ret, ah); 8092089fcc9SDavid Hildenbrand } else if (al == ah) { 8102089fcc9SDavid Hildenbrand tcg_gen_rotri_i32(ret, al, ofs); 811fce1296fSRichard Henderson } else if (TCG_TARGET_HAS_extract2_i32) { 812fce1296fSRichard Henderson tcg_gen_op4i_i32(INDEX_op_extract2_i32, ret, al, ah, ofs); 8132089fcc9SDavid Hildenbrand } else { 8142089fcc9SDavid Hildenbrand TCGv_i32 t0 = tcg_temp_new_i32(); 8152089fcc9SDavid Hildenbrand tcg_gen_shri_i32(t0, al, ofs); 8162089fcc9SDavid Hildenbrand tcg_gen_deposit_i32(ret, t0, ah, 32 - ofs, ofs); 8172089fcc9SDavid Hildenbrand tcg_temp_free_i32(t0); 8182089fcc9SDavid Hildenbrand } 8192089fcc9SDavid Hildenbrand } 8202089fcc9SDavid Hildenbrand 821951c6300SRichard Henderson void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1, 822951c6300SRichard Henderson TCGv_i32 c2, TCGv_i32 v1, TCGv_i32 v2) 823951c6300SRichard Henderson { 82437ed3bf1SRichard Henderson if (cond == TCG_COND_ALWAYS) { 82537ed3bf1SRichard Henderson tcg_gen_mov_i32(ret, v1); 82637ed3bf1SRichard Henderson } else if (cond == TCG_COND_NEVER) { 82737ed3bf1SRichard Henderson tcg_gen_mov_i32(ret, v2); 82837ed3bf1SRichard Henderson } else if (TCG_TARGET_HAS_movcond_i32) { 829951c6300SRichard Henderson tcg_gen_op6i_i32(INDEX_op_movcond_i32, ret, c1, c2, v1, v2, cond); 830951c6300SRichard Henderson } else { 831951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 832951c6300SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 833951c6300SRichard Henderson tcg_gen_setcond_i32(cond, t0, c1, c2); 834951c6300SRichard Henderson tcg_gen_neg_i32(t0, t0); 835951c6300SRichard Henderson tcg_gen_and_i32(t1, v1, t0); 836951c6300SRichard Henderson tcg_gen_andc_i32(ret, v2, t0); 837951c6300SRichard Henderson tcg_gen_or_i32(ret, ret, t1); 838951c6300SRichard Henderson tcg_temp_free_i32(t0); 839951c6300SRichard Henderson tcg_temp_free_i32(t1); 840951c6300SRichard Henderson } 841951c6300SRichard Henderson } 842951c6300SRichard Henderson 843951c6300SRichard Henderson void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, 844951c6300SRichard Henderson TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) 845951c6300SRichard Henderson { 846951c6300SRichard Henderson if (TCG_TARGET_HAS_add2_i32) { 847951c6300SRichard Henderson tcg_gen_op6_i32(INDEX_op_add2_i32, rl, rh, al, ah, bl, bh); 848951c6300SRichard Henderson } else { 849951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 850951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 851951c6300SRichard Henderson tcg_gen_concat_i32_i64(t0, al, ah); 852951c6300SRichard Henderson tcg_gen_concat_i32_i64(t1, bl, bh); 853951c6300SRichard Henderson tcg_gen_add_i64(t0, t0, t1); 854951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 855951c6300SRichard Henderson tcg_temp_free_i64(t0); 856951c6300SRichard Henderson tcg_temp_free_i64(t1); 857951c6300SRichard Henderson } 858951c6300SRichard Henderson } 859951c6300SRichard Henderson 860951c6300SRichard Henderson void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, 861951c6300SRichard Henderson TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) 862951c6300SRichard Henderson { 863951c6300SRichard Henderson if (TCG_TARGET_HAS_sub2_i32) { 864951c6300SRichard Henderson tcg_gen_op6_i32(INDEX_op_sub2_i32, rl, rh, al, ah, bl, bh); 865951c6300SRichard Henderson } else { 866951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 867951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 868951c6300SRichard Henderson tcg_gen_concat_i32_i64(t0, al, ah); 869951c6300SRichard Henderson tcg_gen_concat_i32_i64(t1, bl, bh); 870951c6300SRichard Henderson tcg_gen_sub_i64(t0, t0, t1); 871951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 872951c6300SRichard Henderson tcg_temp_free_i64(t0); 873951c6300SRichard Henderson tcg_temp_free_i64(t1); 874951c6300SRichard Henderson } 875951c6300SRichard Henderson } 876951c6300SRichard Henderson 877951c6300SRichard Henderson void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) 878951c6300SRichard Henderson { 879951c6300SRichard Henderson if (TCG_TARGET_HAS_mulu2_i32) { 880951c6300SRichard Henderson tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2); 881951c6300SRichard Henderson } else if (TCG_TARGET_HAS_muluh_i32) { 882951c6300SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 883951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2); 884951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_muluh_i32, rh, arg1, arg2); 885951c6300SRichard Henderson tcg_gen_mov_i32(rl, t); 886951c6300SRichard Henderson tcg_temp_free_i32(t); 887951c6300SRichard Henderson } else { 888951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 889951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 890951c6300SRichard Henderson tcg_gen_extu_i32_i64(t0, arg1); 891951c6300SRichard Henderson tcg_gen_extu_i32_i64(t1, arg2); 892951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, t1); 893951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 894951c6300SRichard Henderson tcg_temp_free_i64(t0); 895951c6300SRichard Henderson tcg_temp_free_i64(t1); 896951c6300SRichard Henderson } 897951c6300SRichard Henderson } 898951c6300SRichard Henderson 899951c6300SRichard Henderson void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) 900951c6300SRichard Henderson { 901951c6300SRichard Henderson if (TCG_TARGET_HAS_muls2_i32) { 902951c6300SRichard Henderson tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2); 903951c6300SRichard Henderson } else if (TCG_TARGET_HAS_mulsh_i32) { 904951c6300SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 905951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2); 906951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_mulsh_i32, rh, arg1, arg2); 907951c6300SRichard Henderson tcg_gen_mov_i32(rl, t); 908951c6300SRichard Henderson tcg_temp_free_i32(t); 909951c6300SRichard Henderson } else if (TCG_TARGET_REG_BITS == 32) { 910951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 911951c6300SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 912951c6300SRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 913951c6300SRichard Henderson TCGv_i32 t3 = tcg_temp_new_i32(); 914951c6300SRichard Henderson tcg_gen_mulu2_i32(t0, t1, arg1, arg2); 915951c6300SRichard Henderson /* Adjust for negative inputs. */ 916951c6300SRichard Henderson tcg_gen_sari_i32(t2, arg1, 31); 917951c6300SRichard Henderson tcg_gen_sari_i32(t3, arg2, 31); 918951c6300SRichard Henderson tcg_gen_and_i32(t2, t2, arg2); 919951c6300SRichard Henderson tcg_gen_and_i32(t3, t3, arg1); 920951c6300SRichard Henderson tcg_gen_sub_i32(rh, t1, t2); 921951c6300SRichard Henderson tcg_gen_sub_i32(rh, rh, t3); 922951c6300SRichard Henderson tcg_gen_mov_i32(rl, t0); 923951c6300SRichard Henderson tcg_temp_free_i32(t0); 924951c6300SRichard Henderson tcg_temp_free_i32(t1); 925951c6300SRichard Henderson tcg_temp_free_i32(t2); 926951c6300SRichard Henderson tcg_temp_free_i32(t3); 927951c6300SRichard Henderson } else { 928951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 929951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 930951c6300SRichard Henderson tcg_gen_ext_i32_i64(t0, arg1); 931951c6300SRichard Henderson tcg_gen_ext_i32_i64(t1, arg2); 932951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, t1); 933951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 934951c6300SRichard Henderson tcg_temp_free_i64(t0); 935951c6300SRichard Henderson tcg_temp_free_i64(t1); 936951c6300SRichard Henderson } 937951c6300SRichard Henderson } 938951c6300SRichard Henderson 9395087abfbSRichard Henderson void tcg_gen_mulsu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) 9405087abfbSRichard Henderson { 9415087abfbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 9425087abfbSRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 9435087abfbSRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 9445087abfbSRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 9455087abfbSRichard Henderson tcg_gen_mulu2_i32(t0, t1, arg1, arg2); 9465087abfbSRichard Henderson /* Adjust for negative input for the signed arg1. */ 9475087abfbSRichard Henderson tcg_gen_sari_i32(t2, arg1, 31); 9485087abfbSRichard Henderson tcg_gen_and_i32(t2, t2, arg2); 9495087abfbSRichard Henderson tcg_gen_sub_i32(rh, t1, t2); 9505087abfbSRichard Henderson tcg_gen_mov_i32(rl, t0); 9515087abfbSRichard Henderson tcg_temp_free_i32(t0); 9525087abfbSRichard Henderson tcg_temp_free_i32(t1); 9535087abfbSRichard Henderson tcg_temp_free_i32(t2); 9545087abfbSRichard Henderson } else { 9555087abfbSRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 9565087abfbSRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 9575087abfbSRichard Henderson tcg_gen_ext_i32_i64(t0, arg1); 9585087abfbSRichard Henderson tcg_gen_extu_i32_i64(t1, arg2); 9595087abfbSRichard Henderson tcg_gen_mul_i64(t0, t0, t1); 9605087abfbSRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 9615087abfbSRichard Henderson tcg_temp_free_i64(t0); 9625087abfbSRichard Henderson tcg_temp_free_i64(t1); 9635087abfbSRichard Henderson } 9645087abfbSRichard Henderson } 9655087abfbSRichard Henderson 966951c6300SRichard Henderson void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg) 967951c6300SRichard Henderson { 968951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8s_i32) { 969951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg); 970951c6300SRichard Henderson } else { 971951c6300SRichard Henderson tcg_gen_shli_i32(ret, arg, 24); 972951c6300SRichard Henderson tcg_gen_sari_i32(ret, ret, 24); 973951c6300SRichard Henderson } 974951c6300SRichard Henderson } 975951c6300SRichard Henderson 976951c6300SRichard Henderson void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg) 977951c6300SRichard Henderson { 978951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16s_i32) { 979951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg); 980951c6300SRichard Henderson } else { 981951c6300SRichard Henderson tcg_gen_shli_i32(ret, arg, 16); 982951c6300SRichard Henderson tcg_gen_sari_i32(ret, ret, 16); 983951c6300SRichard Henderson } 984951c6300SRichard Henderson } 985951c6300SRichard Henderson 986951c6300SRichard Henderson void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg) 987951c6300SRichard Henderson { 988951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 989951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg); 990951c6300SRichard Henderson } else { 991951c6300SRichard Henderson tcg_gen_andi_i32(ret, arg, 0xffu); 992951c6300SRichard Henderson } 993951c6300SRichard Henderson } 994951c6300SRichard Henderson 995951c6300SRichard Henderson void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg) 996951c6300SRichard Henderson { 997951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 998951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg); 999951c6300SRichard Henderson } else { 1000951c6300SRichard Henderson tcg_gen_andi_i32(ret, arg, 0xffffu); 1001951c6300SRichard Henderson } 1002951c6300SRichard Henderson } 1003951c6300SRichard Henderson 10042b836c2aSRichard Henderson void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags) 1005951c6300SRichard Henderson { 10062b836c2aSRichard Henderson /* Only one extension flag may be present. */ 10072b836c2aSRichard Henderson tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); 10082b836c2aSRichard Henderson 1009951c6300SRichard Henderson if (TCG_TARGET_HAS_bswap16_i32) { 10102b836c2aSRichard Henderson tcg_gen_op3i_i32(INDEX_op_bswap16_i32, ret, arg, flags); 1011951c6300SRichard Henderson } else { 1012951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 10132b836c2aSRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 1014951c6300SRichard Henderson 10152b836c2aSRichard Henderson tcg_gen_shri_i32(t0, arg, 8); 10162b836c2aSRichard Henderson if (!(flags & TCG_BSWAP_IZ)) { 10172b836c2aSRichard Henderson tcg_gen_ext8u_i32(t0, t0); 10182b836c2aSRichard Henderson } 10192b836c2aSRichard Henderson 10202b836c2aSRichard Henderson if (flags & TCG_BSWAP_OS) { 10212b836c2aSRichard Henderson tcg_gen_shli_i32(t1, arg, 24); 10222b836c2aSRichard Henderson tcg_gen_sari_i32(t1, t1, 16); 10232b836c2aSRichard Henderson } else if (flags & TCG_BSWAP_OZ) { 10242b836c2aSRichard Henderson tcg_gen_ext8u_i32(t1, arg); 10252b836c2aSRichard Henderson tcg_gen_shli_i32(t1, t1, 8); 10262b836c2aSRichard Henderson } else { 10272b836c2aSRichard Henderson tcg_gen_shli_i32(t1, arg, 8); 10282b836c2aSRichard Henderson } 10292b836c2aSRichard Henderson 10302b836c2aSRichard Henderson tcg_gen_or_i32(ret, t0, t1); 1031951c6300SRichard Henderson tcg_temp_free_i32(t0); 10322b836c2aSRichard Henderson tcg_temp_free_i32(t1); 1033951c6300SRichard Henderson } 1034951c6300SRichard Henderson } 1035951c6300SRichard Henderson 1036951c6300SRichard Henderson void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) 1037951c6300SRichard Henderson { 1038951c6300SRichard Henderson if (TCG_TARGET_HAS_bswap32_i32) { 1039587195bdSRichard Henderson tcg_gen_op3i_i32(INDEX_op_bswap32_i32, ret, arg, 0); 1040951c6300SRichard Henderson } else { 1041a686dc71SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 1042a686dc71SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 104311d11d61SRichard Henderson TCGv_i32 t2 = tcg_constant_i32(0x00ff00ff); 1044951c6300SRichard Henderson 1045a686dc71SRichard Henderson /* arg = abcd */ 1046a686dc71SRichard Henderson tcg_gen_shri_i32(t0, arg, 8); /* t0 = .abc */ 1047a686dc71SRichard Henderson tcg_gen_and_i32(t1, arg, t2); /* t1 = .b.d */ 1048a686dc71SRichard Henderson tcg_gen_and_i32(t0, t0, t2); /* t0 = .a.c */ 1049a686dc71SRichard Henderson tcg_gen_shli_i32(t1, t1, 8); /* t1 = b.d. */ 1050a686dc71SRichard Henderson tcg_gen_or_i32(ret, t0, t1); /* ret = badc */ 1051951c6300SRichard Henderson 1052a686dc71SRichard Henderson tcg_gen_shri_i32(t0, ret, 16); /* t0 = ..ba */ 1053a686dc71SRichard Henderson tcg_gen_shli_i32(t1, ret, 16); /* t1 = dc.. */ 1054a686dc71SRichard Henderson tcg_gen_or_i32(ret, t0, t1); /* ret = dcba */ 1055951c6300SRichard Henderson 1056951c6300SRichard Henderson tcg_temp_free_i32(t0); 1057951c6300SRichard Henderson tcg_temp_free_i32(t1); 1058951c6300SRichard Henderson } 1059951c6300SRichard Henderson } 1060951c6300SRichard Henderson 1061b87fb8cdSRichard Henderson void tcg_gen_smin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1062b87fb8cdSRichard Henderson { 1063b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, a, b); 1064b87fb8cdSRichard Henderson } 1065b87fb8cdSRichard Henderson 1066b87fb8cdSRichard Henderson void tcg_gen_umin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1067b87fb8cdSRichard Henderson { 1068b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, a, b); 1069b87fb8cdSRichard Henderson } 1070b87fb8cdSRichard Henderson 1071b87fb8cdSRichard Henderson void tcg_gen_smax_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1072b87fb8cdSRichard Henderson { 1073b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, b, a); 1074b87fb8cdSRichard Henderson } 1075b87fb8cdSRichard Henderson 1076b87fb8cdSRichard Henderson void tcg_gen_umax_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1077b87fb8cdSRichard Henderson { 1078b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, b, a); 1079b87fb8cdSRichard Henderson } 1080b87fb8cdSRichard Henderson 1081ff1f11f7SRichard Henderson void tcg_gen_abs_i32(TCGv_i32 ret, TCGv_i32 a) 1082ff1f11f7SRichard Henderson { 1083ff1f11f7SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 1084ff1f11f7SRichard Henderson 1085ff1f11f7SRichard Henderson tcg_gen_sari_i32(t, a, 31); 1086ff1f11f7SRichard Henderson tcg_gen_xor_i32(ret, a, t); 1087ff1f11f7SRichard Henderson tcg_gen_sub_i32(ret, ret, t); 1088ff1f11f7SRichard Henderson tcg_temp_free_i32(t); 1089ff1f11f7SRichard Henderson } 1090ff1f11f7SRichard Henderson 1091951c6300SRichard Henderson /* 64-bit ops */ 1092951c6300SRichard Henderson 1093951c6300SRichard Henderson #if TCG_TARGET_REG_BITS == 32 1094951c6300SRichard Henderson /* These are all inline for TCG_TARGET_REG_BITS == 64. */ 1095951c6300SRichard Henderson 1096951c6300SRichard Henderson void tcg_gen_discard_i64(TCGv_i64 arg) 1097951c6300SRichard Henderson { 1098951c6300SRichard Henderson tcg_gen_discard_i32(TCGV_LOW(arg)); 1099951c6300SRichard Henderson tcg_gen_discard_i32(TCGV_HIGH(arg)); 1100951c6300SRichard Henderson } 1101951c6300SRichard Henderson 1102951c6300SRichard Henderson void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg) 1103951c6300SRichard Henderson { 110411d11d61SRichard Henderson TCGTemp *ts = tcgv_i64_temp(arg); 110511d11d61SRichard Henderson 110611d11d61SRichard Henderson /* Canonicalize TCGv_i64 TEMP_CONST into TCGv_i32 TEMP_CONST. */ 110711d11d61SRichard Henderson if (ts->kind == TEMP_CONST) { 110811d11d61SRichard Henderson tcg_gen_movi_i64(ret, ts->val); 110911d11d61SRichard Henderson } else { 1110951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1111951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); 1112951c6300SRichard Henderson } 111311d11d61SRichard Henderson } 1114951c6300SRichard Henderson 1115951c6300SRichard Henderson void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg) 1116951c6300SRichard Henderson { 1117951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_LOW(ret), arg); 1118951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32); 1119951c6300SRichard Henderson } 1120951c6300SRichard Henderson 1121951c6300SRichard Henderson void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1122951c6300SRichard Henderson { 1123951c6300SRichard Henderson tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset); 1124951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1125951c6300SRichard Henderson } 1126951c6300SRichard Henderson 1127951c6300SRichard Henderson void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1128951c6300SRichard Henderson { 1129951c6300SRichard Henderson tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset); 11303ff91d7eSJoseph Myers tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 1131951c6300SRichard Henderson } 1132951c6300SRichard Henderson 1133951c6300SRichard Henderson void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1134951c6300SRichard Henderson { 1135951c6300SRichard Henderson tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset); 1136951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1137951c6300SRichard Henderson } 1138951c6300SRichard Henderson 1139951c6300SRichard Henderson void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1140951c6300SRichard Henderson { 1141951c6300SRichard Henderson tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset); 1142951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 1143951c6300SRichard Henderson } 1144951c6300SRichard Henderson 1145951c6300SRichard Henderson void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1146951c6300SRichard Henderson { 1147951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); 1148951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1149951c6300SRichard Henderson } 1150951c6300SRichard Henderson 1151951c6300SRichard Henderson void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1152951c6300SRichard Henderson { 1153951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); 1154951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 1155951c6300SRichard Henderson } 1156951c6300SRichard Henderson 1157951c6300SRichard Henderson void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1158951c6300SRichard Henderson { 1159951c6300SRichard Henderson /* Since arg2 and ret have different types, 1160951c6300SRichard Henderson they cannot be the same temporary */ 1161cf811fffSPeter Maydell #ifdef HOST_WORDS_BIGENDIAN 1162951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset); 1163951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4); 1164951c6300SRichard Henderson #else 1165951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); 1166951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4); 1167951c6300SRichard Henderson #endif 1168951c6300SRichard Henderson } 1169951c6300SRichard Henderson 1170951c6300SRichard Henderson void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) 1171951c6300SRichard Henderson { 1172cf811fffSPeter Maydell #ifdef HOST_WORDS_BIGENDIAN 1173951c6300SRichard Henderson tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset); 1174951c6300SRichard Henderson tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4); 1175951c6300SRichard Henderson #else 1176951c6300SRichard Henderson tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); 1177951c6300SRichard Henderson tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4); 1178951c6300SRichard Henderson #endif 1179951c6300SRichard Henderson } 1180951c6300SRichard Henderson 1181951c6300SRichard Henderson void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1182951c6300SRichard Henderson { 1183951c6300SRichard Henderson tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 1184951c6300SRichard Henderson tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 1185951c6300SRichard Henderson } 1186951c6300SRichard Henderson 1187951c6300SRichard Henderson void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1188951c6300SRichard Henderson { 1189951c6300SRichard Henderson tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 1190951c6300SRichard Henderson tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 1191951c6300SRichard Henderson } 1192951c6300SRichard Henderson 1193951c6300SRichard Henderson void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1194951c6300SRichard Henderson { 1195951c6300SRichard Henderson tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 1196951c6300SRichard Henderson tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 1197951c6300SRichard Henderson } 1198951c6300SRichard Henderson 1199951c6300SRichard Henderson void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1200951c6300SRichard Henderson { 1201951c6300SRichard Henderson gen_helper_shl_i64(ret, arg1, arg2); 1202951c6300SRichard Henderson } 1203951c6300SRichard Henderson 1204951c6300SRichard Henderson void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1205951c6300SRichard Henderson { 1206951c6300SRichard Henderson gen_helper_shr_i64(ret, arg1, arg2); 1207951c6300SRichard Henderson } 1208951c6300SRichard Henderson 1209951c6300SRichard Henderson void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1210951c6300SRichard Henderson { 1211951c6300SRichard Henderson gen_helper_sar_i64(ret, arg1, arg2); 1212951c6300SRichard Henderson } 1213951c6300SRichard Henderson 1214951c6300SRichard Henderson void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1215951c6300SRichard Henderson { 1216951c6300SRichard Henderson TCGv_i64 t0; 1217951c6300SRichard Henderson TCGv_i32 t1; 1218951c6300SRichard Henderson 1219951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 1220951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 1221951c6300SRichard Henderson 1222951c6300SRichard Henderson tcg_gen_mulu2_i32(TCGV_LOW(t0), TCGV_HIGH(t0), 1223951c6300SRichard Henderson TCGV_LOW(arg1), TCGV_LOW(arg2)); 1224951c6300SRichard Henderson 1225951c6300SRichard Henderson tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2)); 1226951c6300SRichard Henderson tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); 1227951c6300SRichard Henderson tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), TCGV_LOW(arg2)); 1228951c6300SRichard Henderson tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); 1229951c6300SRichard Henderson 1230951c6300SRichard Henderson tcg_gen_mov_i64(ret, t0); 1231951c6300SRichard Henderson tcg_temp_free_i64(t0); 1232951c6300SRichard Henderson tcg_temp_free_i32(t1); 1233951c6300SRichard Henderson } 123411d11d61SRichard Henderson 123511d11d61SRichard Henderson #else 123611d11d61SRichard Henderson 123711d11d61SRichard Henderson void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg) 123811d11d61SRichard Henderson { 123911d11d61SRichard Henderson tcg_gen_mov_i64(ret, tcg_constant_i64(arg)); 124011d11d61SRichard Henderson } 124111d11d61SRichard Henderson 1242951c6300SRichard Henderson #endif /* TCG_TARGET_REG_SIZE == 32 */ 1243951c6300SRichard Henderson 1244951c6300SRichard Henderson void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1245951c6300SRichard Henderson { 1246951c6300SRichard Henderson /* some cases can be optimized here */ 1247951c6300SRichard Henderson if (arg2 == 0) { 1248951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 124911d11d61SRichard Henderson } else if (TCG_TARGET_REG_BITS == 64) { 125011d11d61SRichard Henderson tcg_gen_add_i64(ret, arg1, tcg_constant_i64(arg2)); 1251951c6300SRichard Henderson } else { 125211d11d61SRichard Henderson tcg_gen_add2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), 125311d11d61SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 125411d11d61SRichard Henderson tcg_constant_i32(arg2), tcg_constant_i32(arg2 >> 32)); 1255951c6300SRichard Henderson } 1256951c6300SRichard Henderson } 1257951c6300SRichard Henderson 1258951c6300SRichard Henderson void tcg_gen_subfi_i64(TCGv_i64 ret, int64_t arg1, TCGv_i64 arg2) 1259951c6300SRichard Henderson { 1260951c6300SRichard Henderson if (arg1 == 0 && TCG_TARGET_HAS_neg_i64) { 1261951c6300SRichard Henderson /* Don't recurse with tcg_gen_neg_i64. */ 1262951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg2); 126311d11d61SRichard Henderson } else if (TCG_TARGET_REG_BITS == 64) { 126411d11d61SRichard Henderson tcg_gen_sub_i64(ret, tcg_constant_i64(arg1), arg2); 1265951c6300SRichard Henderson } else { 126611d11d61SRichard Henderson tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), 126711d11d61SRichard Henderson tcg_constant_i32(arg1), tcg_constant_i32(arg1 >> 32), 126811d11d61SRichard Henderson TCGV_LOW(arg2), TCGV_HIGH(arg2)); 1269951c6300SRichard Henderson } 1270951c6300SRichard Henderson } 1271951c6300SRichard Henderson 1272951c6300SRichard Henderson void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1273951c6300SRichard Henderson { 1274951c6300SRichard Henderson /* some cases can be optimized here */ 1275951c6300SRichard Henderson if (arg2 == 0) { 1276951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 127711d11d61SRichard Henderson } else if (TCG_TARGET_REG_BITS == 64) { 127811d11d61SRichard Henderson tcg_gen_sub_i64(ret, arg1, tcg_constant_i64(arg2)); 1279951c6300SRichard Henderson } else { 128011d11d61SRichard Henderson tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), 128111d11d61SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 128211d11d61SRichard Henderson tcg_constant_i32(arg2), tcg_constant_i32(arg2 >> 32)); 1283951c6300SRichard Henderson } 1284951c6300SRichard Henderson } 1285951c6300SRichard Henderson 1286474b2e8fSRichard Henderson void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1287951c6300SRichard Henderson { 12883a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1289951c6300SRichard Henderson tcg_gen_andi_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); 1290951c6300SRichard Henderson tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); 12913a13c3f3SRichard Henderson return; 12923a13c3f3SRichard Henderson } 12933a13c3f3SRichard Henderson 1294951c6300SRichard Henderson /* Some cases can be optimized here. */ 1295951c6300SRichard Henderson switch (arg2) { 1296951c6300SRichard Henderson case 0: 1297951c6300SRichard Henderson tcg_gen_movi_i64(ret, 0); 1298951c6300SRichard Henderson return; 1299474b2e8fSRichard Henderson case -1: 1300951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1301951c6300SRichard Henderson return; 1302474b2e8fSRichard Henderson case 0xff: 1303951c6300SRichard Henderson /* Don't recurse with tcg_gen_ext8u_i64. */ 1304951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 1305951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg1); 1306951c6300SRichard Henderson return; 1307951c6300SRichard Henderson } 1308951c6300SRichard Henderson break; 1309474b2e8fSRichard Henderson case 0xffff: 1310951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 1311951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg1); 1312951c6300SRichard Henderson return; 1313951c6300SRichard Henderson } 1314951c6300SRichard Henderson break; 1315474b2e8fSRichard Henderson case 0xffffffffu: 1316951c6300SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 1317951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg1); 1318951c6300SRichard Henderson return; 1319951c6300SRichard Henderson } 1320951c6300SRichard Henderson break; 1321951c6300SRichard Henderson } 132211d11d61SRichard Henderson 132311d11d61SRichard Henderson tcg_gen_and_i64(ret, arg1, tcg_constant_i64(arg2)); 1324951c6300SRichard Henderson } 1325951c6300SRichard Henderson 1326951c6300SRichard Henderson void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1327951c6300SRichard Henderson { 13283a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1329951c6300SRichard Henderson tcg_gen_ori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); 1330951c6300SRichard Henderson tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); 13313a13c3f3SRichard Henderson return; 13323a13c3f3SRichard Henderson } 1333951c6300SRichard Henderson /* Some cases can be optimized here. */ 1334951c6300SRichard Henderson if (arg2 == -1) { 1335951c6300SRichard Henderson tcg_gen_movi_i64(ret, -1); 1336951c6300SRichard Henderson } else if (arg2 == 0) { 1337951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1338951c6300SRichard Henderson } else { 133911d11d61SRichard Henderson tcg_gen_or_i64(ret, arg1, tcg_constant_i64(arg2)); 1340951c6300SRichard Henderson } 1341951c6300SRichard Henderson } 1342951c6300SRichard Henderson 1343951c6300SRichard Henderson void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1344951c6300SRichard Henderson { 13453a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1346951c6300SRichard Henderson tcg_gen_xori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); 1347951c6300SRichard Henderson tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); 13483a13c3f3SRichard Henderson return; 13493a13c3f3SRichard Henderson } 1350951c6300SRichard Henderson /* Some cases can be optimized here. */ 1351951c6300SRichard Henderson if (arg2 == 0) { 1352951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1353951c6300SRichard Henderson } else if (arg2 == -1 && TCG_TARGET_HAS_not_i64) { 1354951c6300SRichard Henderson /* Don't recurse with tcg_gen_not_i64. */ 1355951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg1); 1356951c6300SRichard Henderson } else { 135711d11d61SRichard Henderson tcg_gen_xor_i64(ret, arg1, tcg_constant_i64(arg2)); 1358951c6300SRichard Henderson } 1359951c6300SRichard Henderson } 1360951c6300SRichard Henderson 1361951c6300SRichard Henderson static inline void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, 1362951c6300SRichard Henderson unsigned c, bool right, bool arith) 1363951c6300SRichard Henderson { 1364951c6300SRichard Henderson tcg_debug_assert(c < 64); 1365951c6300SRichard Henderson if (c == 0) { 1366951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); 1367951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 1368951c6300SRichard Henderson } else if (c >= 32) { 1369951c6300SRichard Henderson c -= 32; 1370951c6300SRichard Henderson if (right) { 1371951c6300SRichard Henderson if (arith) { 1372951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); 1373951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); 1374951c6300SRichard Henderson } else { 1375951c6300SRichard Henderson tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); 1376951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1377951c6300SRichard Henderson } 1378951c6300SRichard Henderson } else { 1379951c6300SRichard Henderson tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c); 1380951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_LOW(ret), 0); 1381951c6300SRichard Henderson } 138202616badSRichard Henderson } else if (right) { 138302616badSRichard Henderson if (TCG_TARGET_HAS_extract2_i32) { 138402616badSRichard Henderson tcg_gen_extract2_i32(TCGV_LOW(ret), 138502616badSRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), c); 1386951c6300SRichard Henderson } else { 1387951c6300SRichard Henderson tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); 138802616badSRichard Henderson tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(ret), 138902616badSRichard Henderson TCGV_HIGH(arg1), 32 - c, c); 1390951c6300SRichard Henderson } 139102616badSRichard Henderson if (arith) { 139202616badSRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); 139302616badSRichard Henderson } else { 139402616badSRichard Henderson tcg_gen_shri_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); 139502616badSRichard Henderson } 139602616badSRichard Henderson } else { 139702616badSRichard Henderson if (TCG_TARGET_HAS_extract2_i32) { 139802616badSRichard Henderson tcg_gen_extract2_i32(TCGV_HIGH(ret), 139902616badSRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 32 - c); 140002616badSRichard Henderson } else { 140102616badSRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 140202616badSRichard Henderson tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c); 140302616badSRichard Henderson tcg_gen_deposit_i32(TCGV_HIGH(ret), t0, 140402616badSRichard Henderson TCGV_HIGH(arg1), c, 32 - c); 1405951c6300SRichard Henderson tcg_temp_free_i32(t0); 140602616badSRichard Henderson } 140702616badSRichard Henderson tcg_gen_shli_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); 1408951c6300SRichard Henderson } 1409951c6300SRichard Henderson } 1410951c6300SRichard Henderson 1411474b2e8fSRichard Henderson void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1412951c6300SRichard Henderson { 1413474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 14143a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 14153a13c3f3SRichard Henderson tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0); 14163a13c3f3SRichard Henderson } else if (arg2 == 0) { 1417951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1418951c6300SRichard Henderson } else { 141911d11d61SRichard Henderson tcg_gen_shl_i64(ret, arg1, tcg_constant_i64(arg2)); 1420951c6300SRichard Henderson } 1421951c6300SRichard Henderson } 1422951c6300SRichard Henderson 1423474b2e8fSRichard Henderson void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1424951c6300SRichard Henderson { 1425474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 14263a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 14273a13c3f3SRichard Henderson tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0); 14283a13c3f3SRichard Henderson } else if (arg2 == 0) { 1429951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1430951c6300SRichard Henderson } else { 143111d11d61SRichard Henderson tcg_gen_shr_i64(ret, arg1, tcg_constant_i64(arg2)); 1432951c6300SRichard Henderson } 1433951c6300SRichard Henderson } 1434951c6300SRichard Henderson 1435474b2e8fSRichard Henderson void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1436951c6300SRichard Henderson { 1437474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 14383a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 14393a13c3f3SRichard Henderson tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1); 14403a13c3f3SRichard Henderson } else if (arg2 == 0) { 1441951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1442951c6300SRichard Henderson } else { 144311d11d61SRichard Henderson tcg_gen_sar_i64(ret, arg1, tcg_constant_i64(arg2)); 1444951c6300SRichard Henderson } 1445951c6300SRichard Henderson } 1446951c6300SRichard Henderson 144742a268c2SRichard Henderson void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, TCGLabel *l) 1448951c6300SRichard Henderson { 1449951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 145042a268c2SRichard Henderson tcg_gen_br(l); 1451951c6300SRichard Henderson } else if (cond != TCG_COND_NEVER) { 1452d88a117eSRichard Henderson l->refs++; 14533a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1454951c6300SRichard Henderson tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, TCGV_LOW(arg1), 1455951c6300SRichard Henderson TCGV_HIGH(arg1), TCGV_LOW(arg2), 145642a268c2SRichard Henderson TCGV_HIGH(arg2), cond, label_arg(l)); 14573a13c3f3SRichard Henderson } else { 145842a268c2SRichard Henderson tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, 145942a268c2SRichard Henderson label_arg(l)); 14603a13c3f3SRichard Henderson } 1461951c6300SRichard Henderson } 1462951c6300SRichard Henderson } 1463951c6300SRichard Henderson 146442a268c2SRichard Henderson void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1, int64_t arg2, TCGLabel *l) 1465951c6300SRichard Henderson { 146611d11d61SRichard Henderson if (TCG_TARGET_REG_BITS == 64) { 146711d11d61SRichard Henderson tcg_gen_brcond_i64(cond, arg1, tcg_constant_i64(arg2), l); 146811d11d61SRichard Henderson } else if (cond == TCG_COND_ALWAYS) { 146942a268c2SRichard Henderson tcg_gen_br(l); 1470951c6300SRichard Henderson } else if (cond != TCG_COND_NEVER) { 147111d11d61SRichard Henderson l->refs++; 147211d11d61SRichard Henderson tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, 147311d11d61SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 147411d11d61SRichard Henderson tcg_constant_i32(arg2), 147511d11d61SRichard Henderson tcg_constant_i32(arg2 >> 32), 147611d11d61SRichard Henderson cond, label_arg(l)); 1477951c6300SRichard Henderson } 1478951c6300SRichard Henderson } 1479951c6300SRichard Henderson 1480951c6300SRichard Henderson void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret, 1481951c6300SRichard Henderson TCGv_i64 arg1, TCGv_i64 arg2) 1482951c6300SRichard Henderson { 1483951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 1484951c6300SRichard Henderson tcg_gen_movi_i64(ret, 1); 1485951c6300SRichard Henderson } else if (cond == TCG_COND_NEVER) { 1486951c6300SRichard Henderson tcg_gen_movi_i64(ret, 0); 1487951c6300SRichard Henderson } else { 14883a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1489951c6300SRichard Henderson tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), 1490951c6300SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 1491951c6300SRichard Henderson TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); 1492951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 14933a13c3f3SRichard Henderson } else { 1494951c6300SRichard Henderson tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond); 14953a13c3f3SRichard Henderson } 1496951c6300SRichard Henderson } 1497951c6300SRichard Henderson } 1498951c6300SRichard Henderson 1499951c6300SRichard Henderson void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret, 1500951c6300SRichard Henderson TCGv_i64 arg1, int64_t arg2) 1501951c6300SRichard Henderson { 150211d11d61SRichard Henderson if (TCG_TARGET_REG_BITS == 64) { 150311d11d61SRichard Henderson tcg_gen_setcond_i64(cond, ret, arg1, tcg_constant_i64(arg2)); 150411d11d61SRichard Henderson } else if (cond == TCG_COND_ALWAYS) { 150511d11d61SRichard Henderson tcg_gen_movi_i64(ret, 1); 150611d11d61SRichard Henderson } else if (cond == TCG_COND_NEVER) { 150711d11d61SRichard Henderson tcg_gen_movi_i64(ret, 0); 150811d11d61SRichard Henderson } else { 150911d11d61SRichard Henderson tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), 151011d11d61SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 151111d11d61SRichard Henderson tcg_constant_i32(arg2), 151211d11d61SRichard Henderson tcg_constant_i32(arg2 >> 32), cond); 151311d11d61SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 151411d11d61SRichard Henderson } 1515951c6300SRichard Henderson } 1516951c6300SRichard Henderson 1517951c6300SRichard Henderson void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1518951c6300SRichard Henderson { 1519b2e3ae94SRichard Henderson if (arg2 == 0) { 1520b2e3ae94SRichard Henderson tcg_gen_movi_i64(ret, 0); 1521b2e3ae94SRichard Henderson } else if (is_power_of_2(arg2)) { 1522b2e3ae94SRichard Henderson tcg_gen_shli_i64(ret, arg1, ctz64(arg2)); 1523b2e3ae94SRichard Henderson } else { 1524951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1525951c6300SRichard Henderson tcg_gen_mul_i64(ret, arg1, t0); 1526951c6300SRichard Henderson tcg_temp_free_i64(t0); 1527951c6300SRichard Henderson } 1528b2e3ae94SRichard Henderson } 1529951c6300SRichard Henderson 1530951c6300SRichard Henderson void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1531951c6300SRichard Henderson { 1532951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i64) { 1533951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2); 1534951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1535951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1536951c6300SRichard Henderson tcg_gen_sari_i64(t0, arg1, 63); 1537951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2); 1538951c6300SRichard Henderson tcg_temp_free_i64(t0); 1539951c6300SRichard Henderson } else { 1540951c6300SRichard Henderson gen_helper_div_i64(ret, arg1, arg2); 1541951c6300SRichard Henderson } 1542951c6300SRichard Henderson } 1543951c6300SRichard Henderson 1544951c6300SRichard Henderson void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1545951c6300SRichard Henderson { 1546951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i64) { 1547951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2); 1548951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i64) { 1549951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1550951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_div_i64, t0, arg1, arg2); 1551951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, arg2); 1552951c6300SRichard Henderson tcg_gen_sub_i64(ret, arg1, t0); 1553951c6300SRichard Henderson tcg_temp_free_i64(t0); 1554951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1555951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1556951c6300SRichard Henderson tcg_gen_sari_i64(t0, arg1, 63); 1557951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2); 1558951c6300SRichard Henderson tcg_temp_free_i64(t0); 1559951c6300SRichard Henderson } else { 1560951c6300SRichard Henderson gen_helper_rem_i64(ret, arg1, arg2); 1561951c6300SRichard Henderson } 1562951c6300SRichard Henderson } 1563951c6300SRichard Henderson 1564951c6300SRichard Henderson void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1565951c6300SRichard Henderson { 1566951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i64) { 1567951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2); 1568951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1569951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1570951c6300SRichard Henderson tcg_gen_movi_i64(t0, 0); 1571951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2); 1572951c6300SRichard Henderson tcg_temp_free_i64(t0); 1573951c6300SRichard Henderson } else { 1574951c6300SRichard Henderson gen_helper_divu_i64(ret, arg1, arg2); 1575951c6300SRichard Henderson } 1576951c6300SRichard Henderson } 1577951c6300SRichard Henderson 1578951c6300SRichard Henderson void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1579951c6300SRichard Henderson { 1580951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i64) { 1581951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2); 1582951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i64) { 1583951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1584951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_divu_i64, t0, arg1, arg2); 1585951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, arg2); 1586951c6300SRichard Henderson tcg_gen_sub_i64(ret, arg1, t0); 1587951c6300SRichard Henderson tcg_temp_free_i64(t0); 1588951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1589951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1590951c6300SRichard Henderson tcg_gen_movi_i64(t0, 0); 1591951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2); 1592951c6300SRichard Henderson tcg_temp_free_i64(t0); 1593951c6300SRichard Henderson } else { 1594951c6300SRichard Henderson gen_helper_remu_i64(ret, arg1, arg2); 1595951c6300SRichard Henderson } 1596951c6300SRichard Henderson } 1597951c6300SRichard Henderson 1598951c6300SRichard Henderson void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg) 1599951c6300SRichard Henderson { 16003a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1601951c6300SRichard Henderson tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1602951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 16033a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext8s_i64) { 1604951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg); 1605951c6300SRichard Henderson } else { 1606951c6300SRichard Henderson tcg_gen_shli_i64(ret, arg, 56); 1607951c6300SRichard Henderson tcg_gen_sari_i64(ret, ret, 56); 1608951c6300SRichard Henderson } 1609951c6300SRichard Henderson } 1610951c6300SRichard Henderson 1611951c6300SRichard Henderson void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg) 1612951c6300SRichard Henderson { 16133a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1614951c6300SRichard Henderson tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1615951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 16163a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext16s_i64) { 1617951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg); 1618951c6300SRichard Henderson } else { 1619951c6300SRichard Henderson tcg_gen_shli_i64(ret, arg, 48); 1620951c6300SRichard Henderson tcg_gen_sari_i64(ret, ret, 48); 1621951c6300SRichard Henderson } 1622951c6300SRichard Henderson } 1623951c6300SRichard Henderson 1624951c6300SRichard Henderson void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg) 1625951c6300SRichard Henderson { 16263a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1627951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1628951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 16293a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext32s_i64) { 1630951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg); 1631951c6300SRichard Henderson } else { 1632951c6300SRichard Henderson tcg_gen_shli_i64(ret, arg, 32); 1633951c6300SRichard Henderson tcg_gen_sari_i64(ret, ret, 32); 1634951c6300SRichard Henderson } 1635951c6300SRichard Henderson } 1636951c6300SRichard Henderson 1637951c6300SRichard Henderson void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg) 1638951c6300SRichard Henderson { 16393a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1640951c6300SRichard Henderson tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1641951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16423a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext8u_i64) { 1643951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg); 1644951c6300SRichard Henderson } else { 1645951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg, 0xffu); 1646951c6300SRichard Henderson } 1647951c6300SRichard Henderson } 1648951c6300SRichard Henderson 1649951c6300SRichard Henderson void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg) 1650951c6300SRichard Henderson { 16513a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1652951c6300SRichard Henderson tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1653951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16543a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext16u_i64) { 1655951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg); 1656951c6300SRichard Henderson } else { 1657951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg, 0xffffu); 1658951c6300SRichard Henderson } 1659951c6300SRichard Henderson } 1660951c6300SRichard Henderson 1661951c6300SRichard Henderson void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg) 1662951c6300SRichard Henderson { 16633a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1664951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1665951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16663a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext32u_i64) { 1667951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg); 1668951c6300SRichard Henderson } else { 1669951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg, 0xffffffffu); 1670951c6300SRichard Henderson } 1671951c6300SRichard Henderson } 1672951c6300SRichard Henderson 16732b836c2aSRichard Henderson void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) 1674951c6300SRichard Henderson { 16752b836c2aSRichard Henderson /* Only one extension flag may be present. */ 16762b836c2aSRichard Henderson tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); 16772b836c2aSRichard Henderson 16783a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 16792b836c2aSRichard Henderson tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg), flags); 16802b836c2aSRichard Henderson if (flags & TCG_BSWAP_OS) { 16812b836c2aSRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 16822b836c2aSRichard Henderson } else { 1683951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16842b836c2aSRichard Henderson } 16853a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_bswap16_i64) { 16862b836c2aSRichard Henderson tcg_gen_op3i_i64(INDEX_op_bswap16_i64, ret, arg, flags); 1687951c6300SRichard Henderson } else { 1688951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 16892b836c2aSRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 1690951c6300SRichard Henderson 16912b836c2aSRichard Henderson tcg_gen_shri_i64(t0, arg, 8); 16922b836c2aSRichard Henderson if (!(flags & TCG_BSWAP_IZ)) { 16932b836c2aSRichard Henderson tcg_gen_ext8u_i64(t0, t0); 16942b836c2aSRichard Henderson } 16952b836c2aSRichard Henderson 16962b836c2aSRichard Henderson if (flags & TCG_BSWAP_OS) { 16972b836c2aSRichard Henderson tcg_gen_shli_i64(t1, arg, 56); 16982b836c2aSRichard Henderson tcg_gen_sari_i64(t1, t1, 48); 16992b836c2aSRichard Henderson } else if (flags & TCG_BSWAP_OZ) { 17002b836c2aSRichard Henderson tcg_gen_ext8u_i64(t1, arg); 17012b836c2aSRichard Henderson tcg_gen_shli_i64(t1, t1, 8); 17022b836c2aSRichard Henderson } else { 17032b836c2aSRichard Henderson tcg_gen_shli_i64(t1, arg, 8); 17042b836c2aSRichard Henderson } 17052b836c2aSRichard Henderson 17062b836c2aSRichard Henderson tcg_gen_or_i64(ret, t0, t1); 1707951c6300SRichard Henderson tcg_temp_free_i64(t0); 17082b836c2aSRichard Henderson tcg_temp_free_i64(t1); 1709951c6300SRichard Henderson } 1710951c6300SRichard Henderson } 1711951c6300SRichard Henderson 17122b836c2aSRichard Henderson void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) 1713951c6300SRichard Henderson { 17142b836c2aSRichard Henderson /* Only one extension flag may be present. */ 17152b836c2aSRichard Henderson tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); 17162b836c2aSRichard Henderson 17173a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1718951c6300SRichard Henderson tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 17192b836c2aSRichard Henderson if (flags & TCG_BSWAP_OS) { 17202b836c2aSRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 17212b836c2aSRichard Henderson } else { 1722951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 17232b836c2aSRichard Henderson } 17243a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_bswap32_i64) { 17252b836c2aSRichard Henderson tcg_gen_op3i_i64(INDEX_op_bswap32_i64, ret, arg, flags); 1726951c6300SRichard Henderson } else { 1727a686dc71SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1728a686dc71SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 172911d11d61SRichard Henderson TCGv_i64 t2 = tcg_constant_i64(0x00ff00ff); 1730951c6300SRichard Henderson 17312b836c2aSRichard Henderson /* arg = xxxxabcd */ 17322b836c2aSRichard Henderson tcg_gen_shri_i64(t0, arg, 8); /* t0 = .xxxxabc */ 1733a686dc71SRichard Henderson tcg_gen_and_i64(t1, arg, t2); /* t1 = .....b.d */ 1734a686dc71SRichard Henderson tcg_gen_and_i64(t0, t0, t2); /* t0 = .....a.c */ 1735a686dc71SRichard Henderson tcg_gen_shli_i64(t1, t1, 8); /* t1 = ....b.d. */ 1736a686dc71SRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = ....badc */ 1737951c6300SRichard Henderson 1738a686dc71SRichard Henderson tcg_gen_shli_i64(t1, ret, 48); /* t1 = dc...... */ 1739a686dc71SRichard Henderson tcg_gen_shri_i64(t0, ret, 16); /* t0 = ......ba */ 17402b836c2aSRichard Henderson if (flags & TCG_BSWAP_OS) { 17412b836c2aSRichard Henderson tcg_gen_sari_i64(t1, t1, 32); /* t1 = ssssdc.. */ 17422b836c2aSRichard Henderson } else { 1743a686dc71SRichard Henderson tcg_gen_shri_i64(t1, t1, 32); /* t1 = ....dc.. */ 17442b836c2aSRichard Henderson } 17452b836c2aSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = ssssdcba */ 1746951c6300SRichard Henderson 1747951c6300SRichard Henderson tcg_temp_free_i64(t0); 1748951c6300SRichard Henderson tcg_temp_free_i64(t1); 1749951c6300SRichard Henderson } 1750951c6300SRichard Henderson } 1751951c6300SRichard Henderson 1752951c6300SRichard Henderson void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) 1753951c6300SRichard Henderson { 17543a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1755951c6300SRichard Henderson TCGv_i32 t0, t1; 1756951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 1757951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 1758951c6300SRichard Henderson 1759951c6300SRichard Henderson tcg_gen_bswap32_i32(t0, TCGV_LOW(arg)); 1760951c6300SRichard Henderson tcg_gen_bswap32_i32(t1, TCGV_HIGH(arg)); 1761951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), t1); 1762951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), t0); 1763951c6300SRichard Henderson tcg_temp_free_i32(t0); 1764951c6300SRichard Henderson tcg_temp_free_i32(t1); 17653a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_bswap64_i64) { 1766587195bdSRichard Henderson tcg_gen_op3i_i64(INDEX_op_bswap64_i64, ret, arg, 0); 1767951c6300SRichard Henderson } else { 1768951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1769951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 17709e821eabSRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 1771951c6300SRichard Henderson 17729e821eabSRichard Henderson /* arg = abcdefgh */ 17739e821eabSRichard Henderson tcg_gen_movi_i64(t2, 0x00ff00ff00ff00ffull); 17749e821eabSRichard Henderson tcg_gen_shri_i64(t0, arg, 8); /* t0 = .abcdefg */ 17759e821eabSRichard Henderson tcg_gen_and_i64(t1, arg, t2); /* t1 = .b.d.f.h */ 17769e821eabSRichard Henderson tcg_gen_and_i64(t0, t0, t2); /* t0 = .a.c.e.g */ 17779e821eabSRichard Henderson tcg_gen_shli_i64(t1, t1, 8); /* t1 = b.d.f.h. */ 17789e821eabSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = badcfehg */ 1779951c6300SRichard Henderson 17809e821eabSRichard Henderson tcg_gen_movi_i64(t2, 0x0000ffff0000ffffull); 17819e821eabSRichard Henderson tcg_gen_shri_i64(t0, ret, 16); /* t0 = ..badcfe */ 17829e821eabSRichard Henderson tcg_gen_and_i64(t1, ret, t2); /* t1 = ..dc..hg */ 17839e821eabSRichard Henderson tcg_gen_and_i64(t0, t0, t2); /* t0 = ..ba..fe */ 17849e821eabSRichard Henderson tcg_gen_shli_i64(t1, t1, 16); /* t1 = dc..hg.. */ 17859e821eabSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = dcbahgfe */ 1786951c6300SRichard Henderson 17879e821eabSRichard Henderson tcg_gen_shri_i64(t0, ret, 32); /* t0 = ....dcba */ 17889e821eabSRichard Henderson tcg_gen_shli_i64(t1, ret, 32); /* t1 = hgfe.... */ 17899e821eabSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = hgfedcba */ 1790951c6300SRichard Henderson 1791951c6300SRichard Henderson tcg_temp_free_i64(t0); 1792951c6300SRichard Henderson tcg_temp_free_i64(t1); 17939e821eabSRichard Henderson tcg_temp_free_i64(t2); 1794951c6300SRichard Henderson } 1795951c6300SRichard Henderson } 1796951c6300SRichard Henderson 1797951c6300SRichard Henderson void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) 1798951c6300SRichard Henderson { 17993a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18003a13c3f3SRichard Henderson tcg_gen_not_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 18013a13c3f3SRichard Henderson tcg_gen_not_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); 18023a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_not_i64) { 1803951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg); 1804951c6300SRichard Henderson } else { 1805951c6300SRichard Henderson tcg_gen_xori_i64(ret, arg, -1); 1806951c6300SRichard Henderson } 1807951c6300SRichard Henderson } 1808951c6300SRichard Henderson 1809951c6300SRichard Henderson void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1810951c6300SRichard Henderson { 18113a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18123a13c3f3SRichard Henderson tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18133a13c3f3SRichard Henderson tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18143a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_andc_i64) { 1815951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2); 1816951c6300SRichard Henderson } else { 1817951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1818951c6300SRichard Henderson tcg_gen_not_i64(t0, arg2); 1819951c6300SRichard Henderson tcg_gen_and_i64(ret, arg1, t0); 1820951c6300SRichard Henderson tcg_temp_free_i64(t0); 1821951c6300SRichard Henderson } 1822951c6300SRichard Henderson } 1823951c6300SRichard Henderson 1824951c6300SRichard Henderson void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1825951c6300SRichard Henderson { 18263a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18273a13c3f3SRichard Henderson tcg_gen_eqv_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18283a13c3f3SRichard Henderson tcg_gen_eqv_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18293a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_eqv_i64) { 1830951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2); 1831951c6300SRichard Henderson } else { 1832951c6300SRichard Henderson tcg_gen_xor_i64(ret, arg1, arg2); 1833951c6300SRichard Henderson tcg_gen_not_i64(ret, ret); 1834951c6300SRichard Henderson } 1835951c6300SRichard Henderson } 1836951c6300SRichard Henderson 1837951c6300SRichard Henderson void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1838951c6300SRichard Henderson { 18393a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18403a13c3f3SRichard Henderson tcg_gen_nand_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18413a13c3f3SRichard Henderson tcg_gen_nand_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18423a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_nand_i64) { 1843951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2); 1844951c6300SRichard Henderson } else { 1845951c6300SRichard Henderson tcg_gen_and_i64(ret, arg1, arg2); 1846951c6300SRichard Henderson tcg_gen_not_i64(ret, ret); 1847951c6300SRichard Henderson } 1848951c6300SRichard Henderson } 1849951c6300SRichard Henderson 1850951c6300SRichard Henderson void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1851951c6300SRichard Henderson { 18523a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18533a13c3f3SRichard Henderson tcg_gen_nor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18543a13c3f3SRichard Henderson tcg_gen_nor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18553a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_nor_i64) { 1856951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2); 1857951c6300SRichard Henderson } else { 1858951c6300SRichard Henderson tcg_gen_or_i64(ret, arg1, arg2); 1859951c6300SRichard Henderson tcg_gen_not_i64(ret, ret); 1860951c6300SRichard Henderson } 1861951c6300SRichard Henderson } 1862951c6300SRichard Henderson 1863951c6300SRichard Henderson void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1864951c6300SRichard Henderson { 18653a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18663a13c3f3SRichard Henderson tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18673a13c3f3SRichard Henderson tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18683a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_orc_i64) { 1869951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2); 1870951c6300SRichard Henderson } else { 1871951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1872951c6300SRichard Henderson tcg_gen_not_i64(t0, arg2); 1873951c6300SRichard Henderson tcg_gen_or_i64(ret, arg1, t0); 1874951c6300SRichard Henderson tcg_temp_free_i64(t0); 1875951c6300SRichard Henderson } 1876951c6300SRichard Henderson } 1877951c6300SRichard Henderson 18780e28d006SRichard Henderson void tcg_gen_clz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 18790e28d006SRichard Henderson { 18800e28d006SRichard Henderson if (TCG_TARGET_HAS_clz_i64) { 18810e28d006SRichard Henderson tcg_gen_op3_i64(INDEX_op_clz_i64, ret, arg1, arg2); 18820e28d006SRichard Henderson } else { 18830e28d006SRichard Henderson gen_helper_clz_i64(ret, arg1, arg2); 18840e28d006SRichard Henderson } 18850e28d006SRichard Henderson } 18860e28d006SRichard Henderson 18870e28d006SRichard Henderson void tcg_gen_clzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) 18880e28d006SRichard Henderson { 18890e28d006SRichard Henderson if (TCG_TARGET_REG_BITS == 32 18900e28d006SRichard Henderson && TCG_TARGET_HAS_clz_i32 18910e28d006SRichard Henderson && arg2 <= 0xffffffffu) { 189211d11d61SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 189311d11d61SRichard Henderson tcg_gen_clzi_i32(t, TCGV_LOW(arg1), arg2 - 32); 18940e28d006SRichard Henderson tcg_gen_addi_i32(t, t, 32); 18950e28d006SRichard Henderson tcg_gen_clz_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), t); 18960e28d006SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 18970e28d006SRichard Henderson tcg_temp_free_i32(t); 18980e28d006SRichard Henderson } else { 189911d11d61SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 190011d11d61SRichard Henderson tcg_gen_clz_i64(ret, arg1, t0); 190111d11d61SRichard Henderson tcg_temp_free_i64(t0); 19020e28d006SRichard Henderson } 19030e28d006SRichard Henderson } 19040e28d006SRichard Henderson 19050e28d006SRichard Henderson void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 19060e28d006SRichard Henderson { 19070e28d006SRichard Henderson if (TCG_TARGET_HAS_ctz_i64) { 19080e28d006SRichard Henderson tcg_gen_op3_i64(INDEX_op_ctz_i64, ret, arg1, arg2); 190914e99210SRichard Henderson } else if (TCG_TARGET_HAS_ctpop_i64 || TCG_TARGET_HAS_clz_i64) { 191014e99210SRichard Henderson TCGv_i64 z, t = tcg_temp_new_i64(); 191114e99210SRichard Henderson 191214e99210SRichard Henderson if (TCG_TARGET_HAS_ctpop_i64) { 191314e99210SRichard Henderson tcg_gen_subi_i64(t, arg1, 1); 191414e99210SRichard Henderson tcg_gen_andc_i64(t, t, arg1); 191514e99210SRichard Henderson tcg_gen_ctpop_i64(t, t); 191614e99210SRichard Henderson } else { 191714e99210SRichard Henderson /* Since all non-x86 hosts have clz(0) == 64, don't fight it. */ 191814e99210SRichard Henderson tcg_gen_neg_i64(t, arg1); 191914e99210SRichard Henderson tcg_gen_and_i64(t, t, arg1); 192014e99210SRichard Henderson tcg_gen_clzi_i64(t, t, 64); 192114e99210SRichard Henderson tcg_gen_xori_i64(t, t, 63); 192214e99210SRichard Henderson } 192311d11d61SRichard Henderson z = tcg_constant_i64(0); 192414e99210SRichard Henderson tcg_gen_movcond_i64(TCG_COND_EQ, ret, arg1, z, arg2, t); 192514e99210SRichard Henderson tcg_temp_free_i64(t); 192614e99210SRichard Henderson tcg_temp_free_i64(z); 19270e28d006SRichard Henderson } else { 19280e28d006SRichard Henderson gen_helper_ctz_i64(ret, arg1, arg2); 19290e28d006SRichard Henderson } 19300e28d006SRichard Henderson } 19310e28d006SRichard Henderson 19320e28d006SRichard Henderson void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) 19330e28d006SRichard Henderson { 19340e28d006SRichard Henderson if (TCG_TARGET_REG_BITS == 32 19350e28d006SRichard Henderson && TCG_TARGET_HAS_ctz_i32 19360e28d006SRichard Henderson && arg2 <= 0xffffffffu) { 193711d11d61SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 193811d11d61SRichard Henderson tcg_gen_ctzi_i32(t32, TCGV_HIGH(arg1), arg2 - 32); 19390e28d006SRichard Henderson tcg_gen_addi_i32(t32, t32, 32); 19400e28d006SRichard Henderson tcg_gen_ctz_i32(TCGV_LOW(ret), TCGV_LOW(arg1), t32); 19410e28d006SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 19420e28d006SRichard Henderson tcg_temp_free_i32(t32); 194314e99210SRichard Henderson } else if (!TCG_TARGET_HAS_ctz_i64 194414e99210SRichard Henderson && TCG_TARGET_HAS_ctpop_i64 194514e99210SRichard Henderson && arg2 == 64) { 194614e99210SRichard Henderson /* This equivalence has the advantage of not requiring a fixup. */ 194714e99210SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 194814e99210SRichard Henderson tcg_gen_subi_i64(t, arg1, 1); 194914e99210SRichard Henderson tcg_gen_andc_i64(t, t, arg1); 195014e99210SRichard Henderson tcg_gen_ctpop_i64(ret, t); 195114e99210SRichard Henderson tcg_temp_free_i64(t); 19520e28d006SRichard Henderson } else { 195311d11d61SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 195411d11d61SRichard Henderson tcg_gen_ctz_i64(ret, arg1, t0); 195511d11d61SRichard Henderson tcg_temp_free_i64(t0); 19560e28d006SRichard Henderson } 19570e28d006SRichard Henderson } 19580e28d006SRichard Henderson 1959086920c2SRichard Henderson void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg) 1960086920c2SRichard Henderson { 1961086920c2SRichard Henderson if (TCG_TARGET_HAS_clz_i64 || TCG_TARGET_HAS_clz_i32) { 1962086920c2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 1963086920c2SRichard Henderson tcg_gen_sari_i64(t, arg, 63); 1964086920c2SRichard Henderson tcg_gen_xor_i64(t, t, arg); 1965086920c2SRichard Henderson tcg_gen_clzi_i64(t, t, 64); 1966086920c2SRichard Henderson tcg_gen_subi_i64(ret, t, 1); 1967086920c2SRichard Henderson tcg_temp_free_i64(t); 1968086920c2SRichard Henderson } else { 1969086920c2SRichard Henderson gen_helper_clrsb_i64(ret, arg); 1970086920c2SRichard Henderson } 1971086920c2SRichard Henderson } 1972086920c2SRichard Henderson 1973a768e4e9SRichard Henderson void tcg_gen_ctpop_i64(TCGv_i64 ret, TCGv_i64 arg1) 1974a768e4e9SRichard Henderson { 1975a768e4e9SRichard Henderson if (TCG_TARGET_HAS_ctpop_i64) { 1976a768e4e9SRichard Henderson tcg_gen_op2_i64(INDEX_op_ctpop_i64, ret, arg1); 1977a768e4e9SRichard Henderson } else if (TCG_TARGET_REG_BITS == 32 && TCG_TARGET_HAS_ctpop_i32) { 1978a768e4e9SRichard Henderson tcg_gen_ctpop_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 1979a768e4e9SRichard Henderson tcg_gen_ctpop_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); 1980a768e4e9SRichard Henderson tcg_gen_add_i32(TCGV_LOW(ret), TCGV_LOW(ret), TCGV_HIGH(ret)); 1981a768e4e9SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1982a768e4e9SRichard Henderson } else { 1983a768e4e9SRichard Henderson gen_helper_ctpop_i64(ret, arg1); 1984a768e4e9SRichard Henderson } 1985a768e4e9SRichard Henderson } 1986a768e4e9SRichard Henderson 1987951c6300SRichard Henderson void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1988951c6300SRichard Henderson { 1989951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i64) { 1990951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2); 1991951c6300SRichard Henderson } else { 1992951c6300SRichard Henderson TCGv_i64 t0, t1; 1993951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 1994951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 1995951c6300SRichard Henderson tcg_gen_shl_i64(t0, arg1, arg2); 1996951c6300SRichard Henderson tcg_gen_subfi_i64(t1, 64, arg2); 1997951c6300SRichard Henderson tcg_gen_shr_i64(t1, arg1, t1); 1998951c6300SRichard Henderson tcg_gen_or_i64(ret, t0, t1); 1999951c6300SRichard Henderson tcg_temp_free_i64(t0); 2000951c6300SRichard Henderson tcg_temp_free_i64(t1); 2001951c6300SRichard Henderson } 2002951c6300SRichard Henderson } 2003951c6300SRichard Henderson 200407dada03SRichard Henderson void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 2005951c6300SRichard Henderson { 200607dada03SRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 2007951c6300SRichard Henderson /* some cases can be optimized here */ 2008951c6300SRichard Henderson if (arg2 == 0) { 2009951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 2010951c6300SRichard Henderson } else if (TCG_TARGET_HAS_rot_i64) { 201111d11d61SRichard Henderson tcg_gen_rotl_i64(ret, arg1, tcg_constant_i64(arg2)); 2012951c6300SRichard Henderson } else { 2013951c6300SRichard Henderson TCGv_i64 t0, t1; 2014951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 2015951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 2016951c6300SRichard Henderson tcg_gen_shli_i64(t0, arg1, arg2); 2017951c6300SRichard Henderson tcg_gen_shri_i64(t1, arg1, 64 - arg2); 2018951c6300SRichard Henderson tcg_gen_or_i64(ret, t0, t1); 2019951c6300SRichard Henderson tcg_temp_free_i64(t0); 2020951c6300SRichard Henderson tcg_temp_free_i64(t1); 2021951c6300SRichard Henderson } 2022951c6300SRichard Henderson } 2023951c6300SRichard Henderson 2024951c6300SRichard Henderson void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 2025951c6300SRichard Henderson { 2026951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i64) { 2027951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2); 2028951c6300SRichard Henderson } else { 2029951c6300SRichard Henderson TCGv_i64 t0, t1; 2030951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 2031951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 2032951c6300SRichard Henderson tcg_gen_shr_i64(t0, arg1, arg2); 2033951c6300SRichard Henderson tcg_gen_subfi_i64(t1, 64, arg2); 2034951c6300SRichard Henderson tcg_gen_shl_i64(t1, arg1, t1); 2035951c6300SRichard Henderson tcg_gen_or_i64(ret, t0, t1); 2036951c6300SRichard Henderson tcg_temp_free_i64(t0); 2037951c6300SRichard Henderson tcg_temp_free_i64(t1); 2038951c6300SRichard Henderson } 2039951c6300SRichard Henderson } 2040951c6300SRichard Henderson 204107dada03SRichard Henderson void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 2042951c6300SRichard Henderson { 204307dada03SRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 2044951c6300SRichard Henderson /* some cases can be optimized here */ 2045951c6300SRichard Henderson if (arg2 == 0) { 2046951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 2047951c6300SRichard Henderson } else { 2048951c6300SRichard Henderson tcg_gen_rotli_i64(ret, arg1, 64 - arg2); 2049951c6300SRichard Henderson } 2050951c6300SRichard Henderson } 2051951c6300SRichard Henderson 2052951c6300SRichard Henderson void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2, 2053951c6300SRichard Henderson unsigned int ofs, unsigned int len) 2054951c6300SRichard Henderson { 2055951c6300SRichard Henderson uint64_t mask; 2056951c6300SRichard Henderson TCGv_i64 t1; 2057951c6300SRichard Henderson 2058951c6300SRichard Henderson tcg_debug_assert(ofs < 64); 20590d0d309dSRichard Henderson tcg_debug_assert(len > 0); 2060951c6300SRichard Henderson tcg_debug_assert(len <= 64); 2061951c6300SRichard Henderson tcg_debug_assert(ofs + len <= 64); 2062951c6300SRichard Henderson 20630d0d309dSRichard Henderson if (len == 64) { 2064951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg2); 2065951c6300SRichard Henderson return; 2066951c6300SRichard Henderson } 2067951c6300SRichard Henderson if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(ofs, len)) { 2068951c6300SRichard Henderson tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len); 2069951c6300SRichard Henderson return; 2070951c6300SRichard Henderson } 2071951c6300SRichard Henderson 20723a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2073951c6300SRichard Henderson if (ofs >= 32) { 2074951c6300SRichard Henderson tcg_gen_deposit_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 2075951c6300SRichard Henderson TCGV_LOW(arg2), ofs - 32, len); 2076951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); 2077951c6300SRichard Henderson return; 2078951c6300SRichard Henderson } 2079951c6300SRichard Henderson if (ofs + len <= 32) { 2080951c6300SRichard Henderson tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(arg1), 2081951c6300SRichard Henderson TCGV_LOW(arg2), ofs, len); 2082951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 2083951c6300SRichard Henderson return; 2084951c6300SRichard Henderson } 20853a13c3f3SRichard Henderson } 2086951c6300SRichard Henderson 2087951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 2088951c6300SRichard Henderson 2089b0a60567SRichard Henderson if (TCG_TARGET_HAS_extract2_i64) { 2090b0a60567SRichard Henderson if (ofs + len == 64) { 2091b0a60567SRichard Henderson tcg_gen_shli_i64(t1, arg1, len); 2092b0a60567SRichard Henderson tcg_gen_extract2_i64(ret, t1, arg2, len); 2093b0a60567SRichard Henderson goto done; 2094b0a60567SRichard Henderson } 2095b0a60567SRichard Henderson if (ofs == 0) { 2096b0a60567SRichard Henderson tcg_gen_extract2_i64(ret, arg1, arg2, len); 2097b0a60567SRichard Henderson tcg_gen_rotli_i64(ret, ret, len); 2098b0a60567SRichard Henderson goto done; 2099b0a60567SRichard Henderson } 2100b0a60567SRichard Henderson } 2101b0a60567SRichard Henderson 2102b0a60567SRichard Henderson mask = (1ull << len) - 1; 2103951c6300SRichard Henderson if (ofs + len < 64) { 2104951c6300SRichard Henderson tcg_gen_andi_i64(t1, arg2, mask); 2105951c6300SRichard Henderson tcg_gen_shli_i64(t1, t1, ofs); 2106951c6300SRichard Henderson } else { 2107951c6300SRichard Henderson tcg_gen_shli_i64(t1, arg2, ofs); 2108951c6300SRichard Henderson } 2109951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg1, ~(mask << ofs)); 2110951c6300SRichard Henderson tcg_gen_or_i64(ret, ret, t1); 2111b0a60567SRichard Henderson done: 2112951c6300SRichard Henderson tcg_temp_free_i64(t1); 2113951c6300SRichard Henderson } 2114951c6300SRichard Henderson 211507cc68d5SRichard Henderson void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg, 211607cc68d5SRichard Henderson unsigned int ofs, unsigned int len) 211707cc68d5SRichard Henderson { 211807cc68d5SRichard Henderson tcg_debug_assert(ofs < 64); 211907cc68d5SRichard Henderson tcg_debug_assert(len > 0); 212007cc68d5SRichard Henderson tcg_debug_assert(len <= 64); 212107cc68d5SRichard Henderson tcg_debug_assert(ofs + len <= 64); 212207cc68d5SRichard Henderson 212307cc68d5SRichard Henderson if (ofs + len == 64) { 212407cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 212507cc68d5SRichard Henderson } else if (ofs == 0) { 212607cc68d5SRichard Henderson tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); 212707cc68d5SRichard Henderson } else if (TCG_TARGET_HAS_deposit_i64 212807cc68d5SRichard Henderson && TCG_TARGET_deposit_i64_valid(ofs, len)) { 212911d11d61SRichard Henderson TCGv_i64 zero = tcg_constant_i64(0); 213007cc68d5SRichard Henderson tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, zero, arg, ofs, len); 213107cc68d5SRichard Henderson } else { 213207cc68d5SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 213307cc68d5SRichard Henderson if (ofs >= 32) { 213407cc68d5SRichard Henderson tcg_gen_deposit_z_i32(TCGV_HIGH(ret), TCGV_LOW(arg), 213507cc68d5SRichard Henderson ofs - 32, len); 213607cc68d5SRichard Henderson tcg_gen_movi_i32(TCGV_LOW(ret), 0); 213707cc68d5SRichard Henderson return; 213807cc68d5SRichard Henderson } 213907cc68d5SRichard Henderson if (ofs + len <= 32) { 214007cc68d5SRichard Henderson tcg_gen_deposit_z_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len); 214107cc68d5SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 214207cc68d5SRichard Henderson return; 214307cc68d5SRichard Henderson } 214407cc68d5SRichard Henderson } 214507cc68d5SRichard Henderson /* To help two-operand hosts we prefer to zero-extend first, 214607cc68d5SRichard Henderson which allows ARG to stay live. */ 214707cc68d5SRichard Henderson switch (len) { 214807cc68d5SRichard Henderson case 32: 214907cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 215007cc68d5SRichard Henderson tcg_gen_ext32u_i64(ret, arg); 215107cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 215207cc68d5SRichard Henderson return; 215307cc68d5SRichard Henderson } 215407cc68d5SRichard Henderson break; 215507cc68d5SRichard Henderson case 16: 215607cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 215707cc68d5SRichard Henderson tcg_gen_ext16u_i64(ret, arg); 215807cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 215907cc68d5SRichard Henderson return; 216007cc68d5SRichard Henderson } 216107cc68d5SRichard Henderson break; 216207cc68d5SRichard Henderson case 8: 216307cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 216407cc68d5SRichard Henderson tcg_gen_ext8u_i64(ret, arg); 216507cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 216607cc68d5SRichard Henderson return; 216707cc68d5SRichard Henderson } 216807cc68d5SRichard Henderson break; 216907cc68d5SRichard Henderson } 217007cc68d5SRichard Henderson /* Otherwise prefer zero-extension over AND for code size. */ 217107cc68d5SRichard Henderson switch (ofs + len) { 217207cc68d5SRichard Henderson case 32: 217307cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 217407cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 217507cc68d5SRichard Henderson tcg_gen_ext32u_i64(ret, ret); 217607cc68d5SRichard Henderson return; 217707cc68d5SRichard Henderson } 217807cc68d5SRichard Henderson break; 217907cc68d5SRichard Henderson case 16: 218007cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 218107cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 218207cc68d5SRichard Henderson tcg_gen_ext16u_i64(ret, ret); 218307cc68d5SRichard Henderson return; 218407cc68d5SRichard Henderson } 218507cc68d5SRichard Henderson break; 218607cc68d5SRichard Henderson case 8: 218707cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 218807cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 218907cc68d5SRichard Henderson tcg_gen_ext8u_i64(ret, ret); 219007cc68d5SRichard Henderson return; 219107cc68d5SRichard Henderson } 219207cc68d5SRichard Henderson break; 219307cc68d5SRichard Henderson } 219407cc68d5SRichard Henderson tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); 219507cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 219607cc68d5SRichard Henderson } 219707cc68d5SRichard Henderson } 219807cc68d5SRichard Henderson 21997ec8bab3SRichard Henderson void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg, 22007ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 22017ec8bab3SRichard Henderson { 22027ec8bab3SRichard Henderson tcg_debug_assert(ofs < 64); 22037ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 22047ec8bab3SRichard Henderson tcg_debug_assert(len <= 64); 22057ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 64); 22067ec8bab3SRichard Henderson 22077ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if extract is supported. */ 22087ec8bab3SRichard Henderson if (ofs + len == 64) { 22097ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, 64 - len); 22107ec8bab3SRichard Henderson return; 22117ec8bab3SRichard Henderson } 22127ec8bab3SRichard Henderson if (ofs == 0) { 22137ec8bab3SRichard Henderson tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); 22147ec8bab3SRichard Henderson return; 22157ec8bab3SRichard Henderson } 22167ec8bab3SRichard Henderson 22177ec8bab3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 22187ec8bab3SRichard Henderson /* Look for a 32-bit extract within one of the two words. */ 22197ec8bab3SRichard Henderson if (ofs >= 32) { 22207ec8bab3SRichard Henderson tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len); 22217ec8bab3SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 22227ec8bab3SRichard Henderson return; 22237ec8bab3SRichard Henderson } 22247ec8bab3SRichard Henderson if (ofs + len <= 32) { 22257ec8bab3SRichard Henderson tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len); 22267ec8bab3SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 22277ec8bab3SRichard Henderson return; 22287ec8bab3SRichard Henderson } 22297ec8bab3SRichard Henderson /* The field is split across two words. One double-word 22307ec8bab3SRichard Henderson shift is better than two double-word shifts. */ 22317ec8bab3SRichard Henderson goto do_shift_and; 22327ec8bab3SRichard Henderson } 22337ec8bab3SRichard Henderson 22347ec8bab3SRichard Henderson if (TCG_TARGET_HAS_extract_i64 22357ec8bab3SRichard Henderson && TCG_TARGET_extract_i64_valid(ofs, len)) { 22367ec8bab3SRichard Henderson tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, ofs, len); 22377ec8bab3SRichard Henderson return; 22387ec8bab3SRichard Henderson } 22397ec8bab3SRichard Henderson 22407ec8bab3SRichard Henderson /* Assume that zero-extension, if available, is cheaper than a shift. */ 22417ec8bab3SRichard Henderson switch (ofs + len) { 22427ec8bab3SRichard Henderson case 32: 22437ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 22447ec8bab3SRichard Henderson tcg_gen_ext32u_i64(ret, arg); 22457ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, ofs); 22467ec8bab3SRichard Henderson return; 22477ec8bab3SRichard Henderson } 22487ec8bab3SRichard Henderson break; 22497ec8bab3SRichard Henderson case 16: 22507ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 22517ec8bab3SRichard Henderson tcg_gen_ext16u_i64(ret, arg); 22527ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, ofs); 22537ec8bab3SRichard Henderson return; 22547ec8bab3SRichard Henderson } 22557ec8bab3SRichard Henderson break; 22567ec8bab3SRichard Henderson case 8: 22577ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 22587ec8bab3SRichard Henderson tcg_gen_ext8u_i64(ret, arg); 22597ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, ofs); 22607ec8bab3SRichard Henderson return; 22617ec8bab3SRichard Henderson } 22627ec8bab3SRichard Henderson break; 22637ec8bab3SRichard Henderson } 22647ec8bab3SRichard Henderson 22657ec8bab3SRichard Henderson /* ??? Ideally we'd know what values are available for immediate AND. 22667ec8bab3SRichard Henderson Assume that 8 bits are available, plus the special cases of 16 and 32, 22677ec8bab3SRichard Henderson so that we get ext8u, ext16u, and ext32u. */ 22687ec8bab3SRichard Henderson switch (len) { 22697ec8bab3SRichard Henderson case 1 ... 8: case 16: case 32: 22707ec8bab3SRichard Henderson do_shift_and: 22717ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 22727ec8bab3SRichard Henderson tcg_gen_andi_i64(ret, ret, (1ull << len) - 1); 22737ec8bab3SRichard Henderson break; 22747ec8bab3SRichard Henderson default: 22757ec8bab3SRichard Henderson tcg_gen_shli_i64(ret, arg, 64 - len - ofs); 22767ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, 64 - len); 22777ec8bab3SRichard Henderson break; 22787ec8bab3SRichard Henderson } 22797ec8bab3SRichard Henderson } 22807ec8bab3SRichard Henderson 22817ec8bab3SRichard Henderson void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg, 22827ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 22837ec8bab3SRichard Henderson { 22847ec8bab3SRichard Henderson tcg_debug_assert(ofs < 64); 22857ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 22867ec8bab3SRichard Henderson tcg_debug_assert(len <= 64); 22877ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 64); 22887ec8bab3SRichard Henderson 22897ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if sextract is supported. */ 22907ec8bab3SRichard Henderson if (ofs + len == 64) { 22917ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, arg, 64 - len); 22927ec8bab3SRichard Henderson return; 22937ec8bab3SRichard Henderson } 22947ec8bab3SRichard Henderson if (ofs == 0) { 22957ec8bab3SRichard Henderson switch (len) { 22967ec8bab3SRichard Henderson case 32: 22977ec8bab3SRichard Henderson tcg_gen_ext32s_i64(ret, arg); 22987ec8bab3SRichard Henderson return; 22997ec8bab3SRichard Henderson case 16: 23007ec8bab3SRichard Henderson tcg_gen_ext16s_i64(ret, arg); 23017ec8bab3SRichard Henderson return; 23027ec8bab3SRichard Henderson case 8: 23037ec8bab3SRichard Henderson tcg_gen_ext8s_i64(ret, arg); 23047ec8bab3SRichard Henderson return; 23057ec8bab3SRichard Henderson } 23067ec8bab3SRichard Henderson } 23077ec8bab3SRichard Henderson 23087ec8bab3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 23097ec8bab3SRichard Henderson /* Look for a 32-bit extract within one of the two words. */ 23107ec8bab3SRichard Henderson if (ofs >= 32) { 23117ec8bab3SRichard Henderson tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len); 23127ec8bab3SRichard Henderson } else if (ofs + len <= 32) { 23137ec8bab3SRichard Henderson tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len); 23147ec8bab3SRichard Henderson } else if (ofs == 0) { 23157ec8bab3SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 23167ec8bab3SRichard Henderson tcg_gen_sextract_i32(TCGV_HIGH(ret), TCGV_HIGH(arg), 0, len - 32); 23177ec8bab3SRichard Henderson return; 23187ec8bab3SRichard Henderson } else if (len > 32) { 23197ec8bab3SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 23207ec8bab3SRichard Henderson /* Extract the bits for the high word normally. */ 23217ec8bab3SRichard Henderson tcg_gen_sextract_i32(t, TCGV_HIGH(arg), ofs + 32, len - 32); 23227ec8bab3SRichard Henderson /* Shift the field down for the low part. */ 23237ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 23247ec8bab3SRichard Henderson /* Overwrite the shift into the high part. */ 23257ec8bab3SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), t); 23267ec8bab3SRichard Henderson tcg_temp_free_i32(t); 23277ec8bab3SRichard Henderson return; 23287ec8bab3SRichard Henderson } else { 23297ec8bab3SRichard Henderson /* Shift the field down for the low part, such that the 23307ec8bab3SRichard Henderson field sits at the MSB. */ 23317ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs + len - 32); 23327ec8bab3SRichard Henderson /* Shift the field down from the MSB, sign extending. */ 23337ec8bab3SRichard Henderson tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_LOW(ret), 32 - len); 23347ec8bab3SRichard Henderson } 23357ec8bab3SRichard Henderson /* Sign-extend the field from 32 bits. */ 23367ec8bab3SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 23377ec8bab3SRichard Henderson return; 23387ec8bab3SRichard Henderson } 23397ec8bab3SRichard Henderson 23407ec8bab3SRichard Henderson if (TCG_TARGET_HAS_sextract_i64 23417ec8bab3SRichard Henderson && TCG_TARGET_extract_i64_valid(ofs, len)) { 23427ec8bab3SRichard Henderson tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, ofs, len); 23437ec8bab3SRichard Henderson return; 23447ec8bab3SRichard Henderson } 23457ec8bab3SRichard Henderson 23467ec8bab3SRichard Henderson /* Assume that sign-extension, if available, is cheaper than a shift. */ 23477ec8bab3SRichard Henderson switch (ofs + len) { 23487ec8bab3SRichard Henderson case 32: 23497ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext32s_i64) { 23507ec8bab3SRichard Henderson tcg_gen_ext32s_i64(ret, arg); 23517ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, ofs); 23527ec8bab3SRichard Henderson return; 23537ec8bab3SRichard Henderson } 23547ec8bab3SRichard Henderson break; 23557ec8bab3SRichard Henderson case 16: 23567ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i64) { 23577ec8bab3SRichard Henderson tcg_gen_ext16s_i64(ret, arg); 23587ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, ofs); 23597ec8bab3SRichard Henderson return; 23607ec8bab3SRichard Henderson } 23617ec8bab3SRichard Henderson break; 23627ec8bab3SRichard Henderson case 8: 23637ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i64) { 23647ec8bab3SRichard Henderson tcg_gen_ext8s_i64(ret, arg); 23657ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, ofs); 23667ec8bab3SRichard Henderson return; 23677ec8bab3SRichard Henderson } 23687ec8bab3SRichard Henderson break; 23697ec8bab3SRichard Henderson } 23707ec8bab3SRichard Henderson switch (len) { 23717ec8bab3SRichard Henderson case 32: 23727ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext32s_i64) { 23737ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 23747ec8bab3SRichard Henderson tcg_gen_ext32s_i64(ret, ret); 23757ec8bab3SRichard Henderson return; 23767ec8bab3SRichard Henderson } 23777ec8bab3SRichard Henderson break; 23787ec8bab3SRichard Henderson case 16: 23797ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i64) { 23807ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 23817ec8bab3SRichard Henderson tcg_gen_ext16s_i64(ret, ret); 23827ec8bab3SRichard Henderson return; 23837ec8bab3SRichard Henderson } 23847ec8bab3SRichard Henderson break; 23857ec8bab3SRichard Henderson case 8: 23867ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i64) { 23877ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 23887ec8bab3SRichard Henderson tcg_gen_ext8s_i64(ret, ret); 23897ec8bab3SRichard Henderson return; 23907ec8bab3SRichard Henderson } 23917ec8bab3SRichard Henderson break; 23927ec8bab3SRichard Henderson } 23937ec8bab3SRichard Henderson tcg_gen_shli_i64(ret, arg, 64 - len - ofs); 23947ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, 64 - len); 23957ec8bab3SRichard Henderson } 23967ec8bab3SRichard Henderson 23972089fcc9SDavid Hildenbrand /* 23982089fcc9SDavid Hildenbrand * Extract 64 bits from a 128-bit input, ah:al, starting from ofs. 23992089fcc9SDavid Hildenbrand * Unlike tcg_gen_extract_i64 above, len is fixed at 64. 24002089fcc9SDavid Hildenbrand */ 24012089fcc9SDavid Hildenbrand void tcg_gen_extract2_i64(TCGv_i64 ret, TCGv_i64 al, TCGv_i64 ah, 24022089fcc9SDavid Hildenbrand unsigned int ofs) 24032089fcc9SDavid Hildenbrand { 24042089fcc9SDavid Hildenbrand tcg_debug_assert(ofs <= 64); 24052089fcc9SDavid Hildenbrand if (ofs == 0) { 24062089fcc9SDavid Hildenbrand tcg_gen_mov_i64(ret, al); 24072089fcc9SDavid Hildenbrand } else if (ofs == 64) { 24082089fcc9SDavid Hildenbrand tcg_gen_mov_i64(ret, ah); 24092089fcc9SDavid Hildenbrand } else if (al == ah) { 24102089fcc9SDavid Hildenbrand tcg_gen_rotri_i64(ret, al, ofs); 2411fce1296fSRichard Henderson } else if (TCG_TARGET_HAS_extract2_i64) { 2412fce1296fSRichard Henderson tcg_gen_op4i_i64(INDEX_op_extract2_i64, ret, al, ah, ofs); 24132089fcc9SDavid Hildenbrand } else { 24142089fcc9SDavid Hildenbrand TCGv_i64 t0 = tcg_temp_new_i64(); 24152089fcc9SDavid Hildenbrand tcg_gen_shri_i64(t0, al, ofs); 24162089fcc9SDavid Hildenbrand tcg_gen_deposit_i64(ret, t0, ah, 64 - ofs, ofs); 24172089fcc9SDavid Hildenbrand tcg_temp_free_i64(t0); 24182089fcc9SDavid Hildenbrand } 24192089fcc9SDavid Hildenbrand } 24202089fcc9SDavid Hildenbrand 2421951c6300SRichard Henderson void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1, 2422951c6300SRichard Henderson TCGv_i64 c2, TCGv_i64 v1, TCGv_i64 v2) 2423951c6300SRichard Henderson { 242437ed3bf1SRichard Henderson if (cond == TCG_COND_ALWAYS) { 242537ed3bf1SRichard Henderson tcg_gen_mov_i64(ret, v1); 242637ed3bf1SRichard Henderson } else if (cond == TCG_COND_NEVER) { 242737ed3bf1SRichard Henderson tcg_gen_mov_i64(ret, v2); 242837ed3bf1SRichard Henderson } else if (TCG_TARGET_REG_BITS == 32) { 2429951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 2430951c6300SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 2431951c6300SRichard Henderson tcg_gen_op6i_i32(INDEX_op_setcond2_i32, t0, 2432951c6300SRichard Henderson TCGV_LOW(c1), TCGV_HIGH(c1), 2433951c6300SRichard Henderson TCGV_LOW(c2), TCGV_HIGH(c2), cond); 2434951c6300SRichard Henderson 2435951c6300SRichard Henderson if (TCG_TARGET_HAS_movcond_i32) { 2436951c6300SRichard Henderson tcg_gen_movi_i32(t1, 0); 2437951c6300SRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, TCGV_LOW(ret), t0, t1, 2438951c6300SRichard Henderson TCGV_LOW(v1), TCGV_LOW(v2)); 2439951c6300SRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, TCGV_HIGH(ret), t0, t1, 2440951c6300SRichard Henderson TCGV_HIGH(v1), TCGV_HIGH(v2)); 2441951c6300SRichard Henderson } else { 2442951c6300SRichard Henderson tcg_gen_neg_i32(t0, t0); 2443951c6300SRichard Henderson 2444951c6300SRichard Henderson tcg_gen_and_i32(t1, TCGV_LOW(v1), t0); 2445951c6300SRichard Henderson tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(v2), t0); 2446951c6300SRichard Henderson tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t1); 2447951c6300SRichard Henderson 2448951c6300SRichard Henderson tcg_gen_and_i32(t1, TCGV_HIGH(v1), t0); 2449951c6300SRichard Henderson tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(v2), t0); 2450951c6300SRichard Henderson tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t1); 2451951c6300SRichard Henderson } 2452951c6300SRichard Henderson tcg_temp_free_i32(t0); 2453951c6300SRichard Henderson tcg_temp_free_i32(t1); 24543a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_movcond_i64) { 2455951c6300SRichard Henderson tcg_gen_op6i_i64(INDEX_op_movcond_i64, ret, c1, c2, v1, v2, cond); 2456951c6300SRichard Henderson } else { 2457951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2458951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2459951c6300SRichard Henderson tcg_gen_setcond_i64(cond, t0, c1, c2); 2460951c6300SRichard Henderson tcg_gen_neg_i64(t0, t0); 2461951c6300SRichard Henderson tcg_gen_and_i64(t1, v1, t0); 2462951c6300SRichard Henderson tcg_gen_andc_i64(ret, v2, t0); 2463951c6300SRichard Henderson tcg_gen_or_i64(ret, ret, t1); 2464951c6300SRichard Henderson tcg_temp_free_i64(t0); 2465951c6300SRichard Henderson tcg_temp_free_i64(t1); 2466951c6300SRichard Henderson } 2467951c6300SRichard Henderson } 2468951c6300SRichard Henderson 2469951c6300SRichard Henderson void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, 2470951c6300SRichard Henderson TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) 2471951c6300SRichard Henderson { 2472951c6300SRichard Henderson if (TCG_TARGET_HAS_add2_i64) { 2473951c6300SRichard Henderson tcg_gen_op6_i64(INDEX_op_add2_i64, rl, rh, al, ah, bl, bh); 2474951c6300SRichard Henderson } else { 2475951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2476951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2477951c6300SRichard Henderson tcg_gen_add_i64(t0, al, bl); 2478951c6300SRichard Henderson tcg_gen_setcond_i64(TCG_COND_LTU, t1, t0, al); 2479951c6300SRichard Henderson tcg_gen_add_i64(rh, ah, bh); 2480951c6300SRichard Henderson tcg_gen_add_i64(rh, rh, t1); 2481951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2482951c6300SRichard Henderson tcg_temp_free_i64(t0); 2483951c6300SRichard Henderson tcg_temp_free_i64(t1); 2484951c6300SRichard Henderson } 2485951c6300SRichard Henderson } 2486951c6300SRichard Henderson 2487951c6300SRichard Henderson void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, 2488951c6300SRichard Henderson TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) 2489951c6300SRichard Henderson { 2490951c6300SRichard Henderson if (TCG_TARGET_HAS_sub2_i64) { 2491951c6300SRichard Henderson tcg_gen_op6_i64(INDEX_op_sub2_i64, rl, rh, al, ah, bl, bh); 2492951c6300SRichard Henderson } else { 2493951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2494951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2495951c6300SRichard Henderson tcg_gen_sub_i64(t0, al, bl); 2496951c6300SRichard Henderson tcg_gen_setcond_i64(TCG_COND_LTU, t1, al, bl); 2497951c6300SRichard Henderson tcg_gen_sub_i64(rh, ah, bh); 2498951c6300SRichard Henderson tcg_gen_sub_i64(rh, rh, t1); 2499951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2500951c6300SRichard Henderson tcg_temp_free_i64(t0); 2501951c6300SRichard Henderson tcg_temp_free_i64(t1); 2502951c6300SRichard Henderson } 2503951c6300SRichard Henderson } 2504951c6300SRichard Henderson 2505951c6300SRichard Henderson void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) 2506951c6300SRichard Henderson { 2507951c6300SRichard Henderson if (TCG_TARGET_HAS_mulu2_i64) { 2508951c6300SRichard Henderson tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2); 2509951c6300SRichard Henderson } else if (TCG_TARGET_HAS_muluh_i64) { 2510951c6300SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2511951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2); 2512951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_muluh_i64, rh, arg1, arg2); 2513951c6300SRichard Henderson tcg_gen_mov_i64(rl, t); 2514951c6300SRichard Henderson tcg_temp_free_i64(t); 2515951c6300SRichard Henderson } else { 2516951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2517951c6300SRichard Henderson tcg_gen_mul_i64(t0, arg1, arg2); 2518951c6300SRichard Henderson gen_helper_muluh_i64(rh, arg1, arg2); 2519951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2520951c6300SRichard Henderson tcg_temp_free_i64(t0); 2521951c6300SRichard Henderson } 2522951c6300SRichard Henderson } 2523951c6300SRichard Henderson 2524951c6300SRichard Henderson void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) 2525951c6300SRichard Henderson { 2526951c6300SRichard Henderson if (TCG_TARGET_HAS_muls2_i64) { 2527951c6300SRichard Henderson tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2); 2528951c6300SRichard Henderson } else if (TCG_TARGET_HAS_mulsh_i64) { 2529951c6300SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2530951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2); 2531951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_mulsh_i64, rh, arg1, arg2); 2532951c6300SRichard Henderson tcg_gen_mov_i64(rl, t); 2533951c6300SRichard Henderson tcg_temp_free_i64(t); 2534951c6300SRichard Henderson } else if (TCG_TARGET_HAS_mulu2_i64 || TCG_TARGET_HAS_muluh_i64) { 2535951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2536951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2537951c6300SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 2538951c6300SRichard Henderson TCGv_i64 t3 = tcg_temp_new_i64(); 2539951c6300SRichard Henderson tcg_gen_mulu2_i64(t0, t1, arg1, arg2); 2540951c6300SRichard Henderson /* Adjust for negative inputs. */ 2541951c6300SRichard Henderson tcg_gen_sari_i64(t2, arg1, 63); 2542951c6300SRichard Henderson tcg_gen_sari_i64(t3, arg2, 63); 2543951c6300SRichard Henderson tcg_gen_and_i64(t2, t2, arg2); 2544951c6300SRichard Henderson tcg_gen_and_i64(t3, t3, arg1); 2545951c6300SRichard Henderson tcg_gen_sub_i64(rh, t1, t2); 2546951c6300SRichard Henderson tcg_gen_sub_i64(rh, rh, t3); 2547951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2548951c6300SRichard Henderson tcg_temp_free_i64(t0); 2549951c6300SRichard Henderson tcg_temp_free_i64(t1); 2550951c6300SRichard Henderson tcg_temp_free_i64(t2); 2551951c6300SRichard Henderson tcg_temp_free_i64(t3); 2552951c6300SRichard Henderson } else { 2553951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2554951c6300SRichard Henderson tcg_gen_mul_i64(t0, arg1, arg2); 2555951c6300SRichard Henderson gen_helper_mulsh_i64(rh, arg1, arg2); 2556951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2557951c6300SRichard Henderson tcg_temp_free_i64(t0); 2558951c6300SRichard Henderson } 2559951c6300SRichard Henderson } 2560951c6300SRichard Henderson 25615087abfbSRichard Henderson void tcg_gen_mulsu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) 25625087abfbSRichard Henderson { 25635087abfbSRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 25645087abfbSRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 25655087abfbSRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 25665087abfbSRichard Henderson tcg_gen_mulu2_i64(t0, t1, arg1, arg2); 25675087abfbSRichard Henderson /* Adjust for negative input for the signed arg1. */ 25685087abfbSRichard Henderson tcg_gen_sari_i64(t2, arg1, 63); 25695087abfbSRichard Henderson tcg_gen_and_i64(t2, t2, arg2); 25705087abfbSRichard Henderson tcg_gen_sub_i64(rh, t1, t2); 25715087abfbSRichard Henderson tcg_gen_mov_i64(rl, t0); 25725087abfbSRichard Henderson tcg_temp_free_i64(t0); 25735087abfbSRichard Henderson tcg_temp_free_i64(t1); 25745087abfbSRichard Henderson tcg_temp_free_i64(t2); 25755087abfbSRichard Henderson } 25765087abfbSRichard Henderson 2577b87fb8cdSRichard Henderson void tcg_gen_smin_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2578b87fb8cdSRichard Henderson { 2579b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LT, ret, a, b, a, b); 2580b87fb8cdSRichard Henderson } 2581b87fb8cdSRichard Henderson 2582b87fb8cdSRichard Henderson void tcg_gen_umin_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2583b87fb8cdSRichard Henderson { 2584b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, a, b); 2585b87fb8cdSRichard Henderson } 2586b87fb8cdSRichard Henderson 2587b87fb8cdSRichard Henderson void tcg_gen_smax_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2588b87fb8cdSRichard Henderson { 2589b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LT, ret, a, b, b, a); 2590b87fb8cdSRichard Henderson } 2591b87fb8cdSRichard Henderson 2592b87fb8cdSRichard Henderson void tcg_gen_umax_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2593b87fb8cdSRichard Henderson { 2594b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, b, a); 2595b87fb8cdSRichard Henderson } 2596b87fb8cdSRichard Henderson 2597ff1f11f7SRichard Henderson void tcg_gen_abs_i64(TCGv_i64 ret, TCGv_i64 a) 2598ff1f11f7SRichard Henderson { 2599ff1f11f7SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2600ff1f11f7SRichard Henderson 2601ff1f11f7SRichard Henderson tcg_gen_sari_i64(t, a, 63); 2602ff1f11f7SRichard Henderson tcg_gen_xor_i64(ret, a, t); 2603ff1f11f7SRichard Henderson tcg_gen_sub_i64(ret, ret, t); 2604ff1f11f7SRichard Henderson tcg_temp_free_i64(t); 2605ff1f11f7SRichard Henderson } 2606ff1f11f7SRichard Henderson 2607951c6300SRichard Henderson /* Size changing operations. */ 2608951c6300SRichard Henderson 2609609ad705SRichard Henderson void tcg_gen_extrl_i64_i32(TCGv_i32 ret, TCGv_i64 arg) 2610951c6300SRichard Henderson { 26113a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2612951c6300SRichard Henderson tcg_gen_mov_i32(ret, TCGV_LOW(arg)); 2613609ad705SRichard Henderson } else if (TCG_TARGET_HAS_extrl_i64_i32) { 2614b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_extrl_i64_i32, 2615ae8b75dcSRichard Henderson tcgv_i32_arg(ret), tcgv_i64_arg(arg)); 2616951c6300SRichard Henderson } else { 2617dc41aa7dSRichard Henderson tcg_gen_mov_i32(ret, (TCGv_i32)arg); 2618609ad705SRichard Henderson } 2619609ad705SRichard Henderson } 2620609ad705SRichard Henderson 2621609ad705SRichard Henderson void tcg_gen_extrh_i64_i32(TCGv_i32 ret, TCGv_i64 arg) 2622609ad705SRichard Henderson { 2623609ad705SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2624609ad705SRichard Henderson tcg_gen_mov_i32(ret, TCGV_HIGH(arg)); 2625609ad705SRichard Henderson } else if (TCG_TARGET_HAS_extrh_i64_i32) { 2626b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_extrh_i64_i32, 2627ae8b75dcSRichard Henderson tcgv_i32_arg(ret), tcgv_i64_arg(arg)); 2628951c6300SRichard Henderson } else { 2629951c6300SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2630609ad705SRichard Henderson tcg_gen_shri_i64(t, arg, 32); 2631dc41aa7dSRichard Henderson tcg_gen_mov_i32(ret, (TCGv_i32)t); 2632951c6300SRichard Henderson tcg_temp_free_i64(t); 2633951c6300SRichard Henderson } 2634951c6300SRichard Henderson } 2635951c6300SRichard Henderson 2636951c6300SRichard Henderson void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg) 2637951c6300SRichard Henderson { 26383a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2639951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), arg); 2640951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 26413a13c3f3SRichard Henderson } else { 2642b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_extu_i32_i64, 2643ae8b75dcSRichard Henderson tcgv_i64_arg(ret), tcgv_i32_arg(arg)); 26443a13c3f3SRichard Henderson } 2645951c6300SRichard Henderson } 2646951c6300SRichard Henderson 2647951c6300SRichard Henderson void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg) 2648951c6300SRichard Henderson { 26493a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2650951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), arg); 2651951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 26523a13c3f3SRichard Henderson } else { 2653b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_ext_i32_i64, 2654ae8b75dcSRichard Henderson tcgv_i64_arg(ret), tcgv_i32_arg(arg)); 26553a13c3f3SRichard Henderson } 2656951c6300SRichard Henderson } 2657951c6300SRichard Henderson 2658951c6300SRichard Henderson void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high) 2659951c6300SRichard Henderson { 26603a13c3f3SRichard Henderson TCGv_i64 tmp; 26613a13c3f3SRichard Henderson 26623a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2663951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(dest), low); 2664951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(dest), high); 26653a13c3f3SRichard Henderson return; 26663a13c3f3SRichard Henderson } 26673a13c3f3SRichard Henderson 26683a13c3f3SRichard Henderson tmp = tcg_temp_new_i64(); 2669951c6300SRichard Henderson /* These extensions are only needed for type correctness. 2670951c6300SRichard Henderson We may be able to do better given target specific information. */ 2671951c6300SRichard Henderson tcg_gen_extu_i32_i64(tmp, high); 2672951c6300SRichard Henderson tcg_gen_extu_i32_i64(dest, low); 2673951c6300SRichard Henderson /* If deposit is available, use it. Otherwise use the extra 2674951c6300SRichard Henderson knowledge that we have of the zero-extensions above. */ 2675951c6300SRichard Henderson if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(32, 32)) { 2676951c6300SRichard Henderson tcg_gen_deposit_i64(dest, dest, tmp, 32, 32); 2677951c6300SRichard Henderson } else { 2678951c6300SRichard Henderson tcg_gen_shli_i64(tmp, tmp, 32); 2679951c6300SRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 2680951c6300SRichard Henderson } 2681951c6300SRichard Henderson tcg_temp_free_i64(tmp); 2682951c6300SRichard Henderson } 2683951c6300SRichard Henderson 2684951c6300SRichard Henderson void tcg_gen_extr_i64_i32(TCGv_i32 lo, TCGv_i32 hi, TCGv_i64 arg) 2685951c6300SRichard Henderson { 26863a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2687951c6300SRichard Henderson tcg_gen_mov_i32(lo, TCGV_LOW(arg)); 2688951c6300SRichard Henderson tcg_gen_mov_i32(hi, TCGV_HIGH(arg)); 26893a13c3f3SRichard Henderson } else { 2690609ad705SRichard Henderson tcg_gen_extrl_i64_i32(lo, arg); 2691609ad705SRichard Henderson tcg_gen_extrh_i64_i32(hi, arg); 26923a13c3f3SRichard Henderson } 2693951c6300SRichard Henderson } 2694951c6300SRichard Henderson 2695951c6300SRichard Henderson void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg) 2696951c6300SRichard Henderson { 2697951c6300SRichard Henderson tcg_gen_ext32u_i64(lo, arg); 2698951c6300SRichard Henderson tcg_gen_shri_i64(hi, arg, 32); 2699951c6300SRichard Henderson } 2700951c6300SRichard Henderson 2701951c6300SRichard Henderson /* QEMU specific operations. */ 2702951c6300SRichard Henderson 2703d9971435SRichard Henderson void tcg_gen_exit_tb(const TranslationBlock *tb, unsigned idx) 270407ea28b4SRichard Henderson { 2705eba40358SRichard Henderson /* 2706eba40358SRichard Henderson * Let the jit code return the read-only version of the 2707eba40358SRichard Henderson * TranslationBlock, so that we minimize the pc-relative 2708eba40358SRichard Henderson * distance of the address of the exit_tb code to TB. 2709eba40358SRichard Henderson * This will improve utilization of pc-relative address loads. 2710eba40358SRichard Henderson * 2711eba40358SRichard Henderson * TODO: Move this to translator_loop, so that all const 2712eba40358SRichard Henderson * TranslationBlock pointers refer to read-only memory. 2713eba40358SRichard Henderson * This requires coordination with targets that do not use 2714eba40358SRichard Henderson * the translator_loop. 2715eba40358SRichard Henderson */ 2716eba40358SRichard Henderson uintptr_t val = (uintptr_t)tcg_splitwx_to_rx((void *)tb) + idx; 271707ea28b4SRichard Henderson 271807ea28b4SRichard Henderson if (tb == NULL) { 271907ea28b4SRichard Henderson tcg_debug_assert(idx == 0); 272007ea28b4SRichard Henderson } else if (idx <= TB_EXIT_IDXMAX) { 272107ea28b4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 272207ea28b4SRichard Henderson /* This is an exit following a goto_tb. Verify that we have 272307ea28b4SRichard Henderson seen this numbered exit before, via tcg_gen_goto_tb. */ 272407ea28b4SRichard Henderson tcg_debug_assert(tcg_ctx->goto_tb_issue_mask & (1 << idx)); 272507ea28b4SRichard Henderson #endif 272607ea28b4SRichard Henderson } else { 272707ea28b4SRichard Henderson /* This is an exit via the exitreq label. */ 272807ea28b4SRichard Henderson tcg_debug_assert(idx == TB_EXIT_REQUESTED); 272907ea28b4SRichard Henderson } 273007ea28b4SRichard Henderson 2731e6d86bedSEmilio G. Cota plugin_gen_disable_mem_helpers(); 273207ea28b4SRichard Henderson tcg_gen_op1i(INDEX_op_exit_tb, val); 273307ea28b4SRichard Henderson } 273407ea28b4SRichard Henderson 2735951c6300SRichard Henderson void tcg_gen_goto_tb(unsigned idx) 2736951c6300SRichard Henderson { 273784f15616SRichard Henderson /* We tested CF_NO_GOTO_TB in translator_use_goto_tb. */ 273884f15616SRichard Henderson tcg_debug_assert(!(tcg_ctx->tb_cflags & CF_NO_GOTO_TB)); 2739951c6300SRichard Henderson /* We only support two chained exits. */ 274007ea28b4SRichard Henderson tcg_debug_assert(idx <= TB_EXIT_IDXMAX); 2741951c6300SRichard Henderson #ifdef CONFIG_DEBUG_TCG 2742a4761232SPhilippe Mathieu-Daudé /* Verify that we haven't seen this numbered exit before. */ 2743b1311c4aSEmilio G. Cota tcg_debug_assert((tcg_ctx->goto_tb_issue_mask & (1 << idx)) == 0); 2744b1311c4aSEmilio G. Cota tcg_ctx->goto_tb_issue_mask |= 1 << idx; 2745951c6300SRichard Henderson #endif 2746e6d86bedSEmilio G. Cota plugin_gen_disable_mem_helpers(); 2747951c6300SRichard Henderson tcg_gen_op1i(INDEX_op_goto_tb, idx); 2748951c6300SRichard Henderson } 2749951c6300SRichard Henderson 27507f11636dSEmilio G. Cota void tcg_gen_lookup_and_goto_ptr(void) 2751cedbcb01SEmilio G. Cota { 2752e6d86bedSEmilio G. Cota TCGv_ptr ptr; 2753e6d86bedSEmilio G. Cota 275484f15616SRichard Henderson if (tcg_ctx->tb_cflags & CF_NO_GOTO_PTR) { 275584f15616SRichard Henderson tcg_gen_exit_tb(NULL, 0); 275684f15616SRichard Henderson return; 275784f15616SRichard Henderson } 275884f15616SRichard Henderson 2759e6d86bedSEmilio G. Cota plugin_gen_disable_mem_helpers(); 2760e6d86bedSEmilio G. Cota ptr = tcg_temp_new_ptr(); 27611c2adb95SRichard Henderson gen_helper_lookup_tb_ptr(ptr, cpu_env); 2762ae8b75dcSRichard Henderson tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr)); 2763cedbcb01SEmilio G. Cota tcg_temp_free_ptr(ptr); 2764cedbcb01SEmilio G. Cota } 2765cedbcb01SEmilio G. Cota 276614776ab5STony Nguyen static inline MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st) 2767951c6300SRichard Henderson { 27681f00b27fSSergey Sorokin /* Trigger the asserts within as early as possible. */ 27691f00b27fSSergey Sorokin (void)get_alignment_bits(op); 27701f00b27fSSergey Sorokin 2771951c6300SRichard Henderson switch (op & MO_SIZE) { 2772951c6300SRichard Henderson case MO_8: 2773951c6300SRichard Henderson op &= ~MO_BSWAP; 2774951c6300SRichard Henderson break; 2775951c6300SRichard Henderson case MO_16: 2776951c6300SRichard Henderson break; 2777951c6300SRichard Henderson case MO_32: 2778951c6300SRichard Henderson if (!is64) { 2779951c6300SRichard Henderson op &= ~MO_SIGN; 2780951c6300SRichard Henderson } 2781951c6300SRichard Henderson break; 2782951c6300SRichard Henderson case MO_64: 27834b473e0cSRichard Henderson if (is64) { 27844b473e0cSRichard Henderson op &= ~MO_SIGN; 2785951c6300SRichard Henderson break; 2786951c6300SRichard Henderson } 27874b473e0cSRichard Henderson /* fall through */ 27884b473e0cSRichard Henderson default: 27894b473e0cSRichard Henderson g_assert_not_reached(); 27904b473e0cSRichard Henderson } 2791951c6300SRichard Henderson if (st) { 2792951c6300SRichard Henderson op &= ~MO_SIGN; 2793951c6300SRichard Henderson } 2794951c6300SRichard Henderson return op; 2795951c6300SRichard Henderson } 2796951c6300SRichard Henderson 2797c45cb8bbSRichard Henderson static void gen_ldst_i32(TCGOpcode opc, TCGv_i32 val, TCGv addr, 279814776ab5STony Nguyen MemOp memop, TCGArg idx) 2799951c6300SRichard Henderson { 28009002ffcbSRichard Henderson MemOpIdx oi = make_memop_idx(memop, idx); 2801951c6300SRichard Henderson #if TARGET_LONG_BITS == 32 280259227d5dSRichard Henderson tcg_gen_op3i_i32(opc, val, addr, oi); 2803951c6300SRichard Henderson #else 2804c45cb8bbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 280559227d5dSRichard Henderson tcg_gen_op4i_i32(opc, val, TCGV_LOW(addr), TCGV_HIGH(addr), oi); 2806c45cb8bbSRichard Henderson } else { 2807ae8b75dcSRichard Henderson tcg_gen_op3(opc, tcgv_i32_arg(val), tcgv_i64_arg(addr), oi); 2808c45cb8bbSRichard Henderson } 2809951c6300SRichard Henderson #endif 2810c45cb8bbSRichard Henderson } 2811c45cb8bbSRichard Henderson 2812c45cb8bbSRichard Henderson static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 val, TCGv addr, 281314776ab5STony Nguyen MemOp memop, TCGArg idx) 2814c45cb8bbSRichard Henderson { 28159002ffcbSRichard Henderson MemOpIdx oi = make_memop_idx(memop, idx); 2816c45cb8bbSRichard Henderson #if TARGET_LONG_BITS == 32 2817c45cb8bbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 281859227d5dSRichard Henderson tcg_gen_op4i_i32(opc, TCGV_LOW(val), TCGV_HIGH(val), addr, oi); 2819c45cb8bbSRichard Henderson } else { 2820ae8b75dcSRichard Henderson tcg_gen_op3(opc, tcgv_i64_arg(val), tcgv_i32_arg(addr), oi); 2821c45cb8bbSRichard Henderson } 2822c45cb8bbSRichard Henderson #else 2823c45cb8bbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 282459227d5dSRichard Henderson tcg_gen_op5i_i32(opc, TCGV_LOW(val), TCGV_HIGH(val), 282559227d5dSRichard Henderson TCGV_LOW(addr), TCGV_HIGH(addr), oi); 2826c45cb8bbSRichard Henderson } else { 282759227d5dSRichard Henderson tcg_gen_op3i_i64(opc, val, addr, oi); 2828c45cb8bbSRichard Henderson } 2829c45cb8bbSRichard Henderson #endif 2830c45cb8bbSRichard Henderson } 2831951c6300SRichard Henderson 2832b32dc337SPranith Kumar static void tcg_gen_req_mo(TCGBar type) 2833b32dc337SPranith Kumar { 2834b32dc337SPranith Kumar #ifdef TCG_GUEST_DEFAULT_MO 2835b32dc337SPranith Kumar type &= TCG_GUEST_DEFAULT_MO; 2836b32dc337SPranith Kumar #endif 2837b32dc337SPranith Kumar type &= ~TCG_TARGET_DEFAULT_MO; 2838b32dc337SPranith Kumar if (type) { 2839b32dc337SPranith Kumar tcg_gen_mb(type | TCG_BAR_SC); 2840b32dc337SPranith Kumar } 2841b32dc337SPranith Kumar } 2842b32dc337SPranith Kumar 2843fcc54ab5SAlex Bennée static inline TCGv plugin_prep_mem_callbacks(TCGv vaddr) 2844fcc54ab5SAlex Bennée { 2845fcc54ab5SAlex Bennée #ifdef CONFIG_PLUGIN 2846fcc54ab5SAlex Bennée if (tcg_ctx->plugin_insn != NULL) { 2847fcc54ab5SAlex Bennée /* Save a copy of the vaddr for use after a load. */ 2848fcc54ab5SAlex Bennée TCGv temp = tcg_temp_new(); 2849fcc54ab5SAlex Bennée tcg_gen_mov_tl(temp, vaddr); 2850fcc54ab5SAlex Bennée return temp; 2851fcc54ab5SAlex Bennée } 2852fcc54ab5SAlex Bennée #endif 2853fcc54ab5SAlex Bennée return vaddr; 2854fcc54ab5SAlex Bennée } 2855fcc54ab5SAlex Bennée 2856*37aff087SRichard Henderson static void plugin_gen_mem_callbacks(TCGv vaddr, MemOpIdx oi, 2857*37aff087SRichard Henderson enum qemu_plugin_mem_rw rw) 2858e6d86bedSEmilio G. Cota { 2859e6d86bedSEmilio G. Cota #ifdef CONFIG_PLUGIN 2860fcc54ab5SAlex Bennée if (tcg_ctx->plugin_insn != NULL) { 2861*37aff087SRichard Henderson qemu_plugin_meminfo_t info = make_plugin_meminfo(oi, rw); 2862e6d86bedSEmilio G. Cota plugin_gen_empty_mem_callback(vaddr, info); 2863fcc54ab5SAlex Bennée tcg_temp_free(vaddr); 2864fcc54ab5SAlex Bennée } 2865e6d86bedSEmilio G. Cota #endif 2866e6d86bedSEmilio G. Cota } 2867e6d86bedSEmilio G. Cota 286814776ab5STony Nguyen void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) 2869951c6300SRichard Henderson { 287014776ab5STony Nguyen MemOp orig_memop; 2871*37aff087SRichard Henderson MemOpIdx oi; 2872*37aff087SRichard Henderson uint16_t info; 2873e1dcf352SRichard Henderson 2874b32dc337SPranith Kumar tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 2875951c6300SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 2876*37aff087SRichard Henderson oi = make_memop_idx(memop, idx); 2877*37aff087SRichard Henderson info = trace_mem_get_info(oi, 0); 2878e6d86bedSEmilio G. Cota trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, addr, info); 2879e1dcf352SRichard Henderson 2880e1dcf352SRichard Henderson orig_memop = memop; 2881e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 2882e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 2883359feba5SRichard Henderson /* The bswap primitive benefits from zero-extended input. */ 2884e1dcf352SRichard Henderson if ((memop & MO_SSIZE) == MO_SW) { 2885e1dcf352SRichard Henderson memop &= ~MO_SIGN; 2886e1dcf352SRichard Henderson } 2887e1dcf352SRichard Henderson } 2888e1dcf352SRichard Henderson 2889fcc54ab5SAlex Bennée addr = plugin_prep_mem_callbacks(addr); 2890c45cb8bbSRichard Henderson gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx); 2891*37aff087SRichard Henderson plugin_gen_mem_callbacks(addr, oi, QEMU_PLUGIN_MEM_R); 2892e1dcf352SRichard Henderson 2893e1dcf352SRichard Henderson if ((orig_memop ^ memop) & MO_BSWAP) { 2894e1dcf352SRichard Henderson switch (orig_memop & MO_SIZE) { 2895e1dcf352SRichard Henderson case MO_16: 2896359feba5SRichard Henderson tcg_gen_bswap16_i32(val, val, (orig_memop & MO_SIGN 2897359feba5SRichard Henderson ? TCG_BSWAP_IZ | TCG_BSWAP_OS 2898359feba5SRichard Henderson : TCG_BSWAP_IZ | TCG_BSWAP_OZ)); 2899e1dcf352SRichard Henderson break; 2900e1dcf352SRichard Henderson case MO_32: 2901e1dcf352SRichard Henderson tcg_gen_bswap32_i32(val, val); 2902e1dcf352SRichard Henderson break; 2903e1dcf352SRichard Henderson default: 2904e1dcf352SRichard Henderson g_assert_not_reached(); 2905e1dcf352SRichard Henderson } 2906e1dcf352SRichard Henderson } 2907951c6300SRichard Henderson } 2908951c6300SRichard Henderson 290914776ab5STony Nguyen void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) 2910951c6300SRichard Henderson { 2911e1dcf352SRichard Henderson TCGv_i32 swap = NULL; 2912*37aff087SRichard Henderson MemOpIdx oi; 2913*37aff087SRichard Henderson uint16_t info; 2914e1dcf352SRichard Henderson 2915b32dc337SPranith Kumar tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 2916951c6300SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 1); 2917*37aff087SRichard Henderson oi = make_memop_idx(memop, idx); 2918*37aff087SRichard Henderson info = trace_mem_get_info(oi, 1); 2919e6d86bedSEmilio G. Cota trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, addr, info); 2920e1dcf352SRichard Henderson 2921e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 2922e1dcf352SRichard Henderson swap = tcg_temp_new_i32(); 2923e1dcf352SRichard Henderson switch (memop & MO_SIZE) { 2924e1dcf352SRichard Henderson case MO_16: 2925b53357acSRichard Henderson tcg_gen_bswap16_i32(swap, val, 0); 2926e1dcf352SRichard Henderson break; 2927e1dcf352SRichard Henderson case MO_32: 2928e1dcf352SRichard Henderson tcg_gen_bswap32_i32(swap, val); 2929e1dcf352SRichard Henderson break; 2930e1dcf352SRichard Henderson default: 2931e1dcf352SRichard Henderson g_assert_not_reached(); 2932e1dcf352SRichard Henderson } 2933e1dcf352SRichard Henderson val = swap; 2934e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 2935e1dcf352SRichard Henderson } 2936e1dcf352SRichard Henderson 2937fcc54ab5SAlex Bennée addr = plugin_prep_mem_callbacks(addr); 293807ce0b05SRichard Henderson if (TCG_TARGET_HAS_qemu_st8_i32 && (memop & MO_SIZE) == MO_8) { 293907ce0b05SRichard Henderson gen_ldst_i32(INDEX_op_qemu_st8_i32, val, addr, memop, idx); 294007ce0b05SRichard Henderson } else { 2941c45cb8bbSRichard Henderson gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx); 294207ce0b05SRichard Henderson } 2943*37aff087SRichard Henderson plugin_gen_mem_callbacks(addr, oi, QEMU_PLUGIN_MEM_W); 2944e1dcf352SRichard Henderson 2945e1dcf352SRichard Henderson if (swap) { 2946e1dcf352SRichard Henderson tcg_temp_free_i32(swap); 2947e1dcf352SRichard Henderson } 2948951c6300SRichard Henderson } 2949951c6300SRichard Henderson 295014776ab5STony Nguyen void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) 2951951c6300SRichard Henderson { 295214776ab5STony Nguyen MemOp orig_memop; 2953*37aff087SRichard Henderson MemOpIdx oi; 2954e6d86bedSEmilio G. Cota uint16_t info; 2955e1dcf352SRichard Henderson 29563a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) { 2957951c6300SRichard Henderson tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop); 2958951c6300SRichard Henderson if (memop & MO_SIGN) { 2959951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(val), TCGV_LOW(val), 31); 2960951c6300SRichard Henderson } else { 2961951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(val), 0); 2962951c6300SRichard Henderson } 2963951c6300SRichard Henderson return; 2964951c6300SRichard Henderson } 2965951c6300SRichard Henderson 2966e1dcf352SRichard Henderson tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 2967c45cb8bbSRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 2968*37aff087SRichard Henderson oi = make_memop_idx(memop, idx); 2969*37aff087SRichard Henderson info = trace_mem_get_info(oi, 0); 2970e6d86bedSEmilio G. Cota trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, addr, info); 2971e1dcf352SRichard Henderson 2972e1dcf352SRichard Henderson orig_memop = memop; 2973e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 2974e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 2975359feba5SRichard Henderson /* The bswap primitive benefits from zero-extended input. */ 2976e1dcf352SRichard Henderson if ((memop & MO_SIGN) && (memop & MO_SIZE) < MO_64) { 2977e1dcf352SRichard Henderson memop &= ~MO_SIGN; 2978e1dcf352SRichard Henderson } 2979e1dcf352SRichard Henderson } 2980e1dcf352SRichard Henderson 2981fcc54ab5SAlex Bennée addr = plugin_prep_mem_callbacks(addr); 2982c45cb8bbSRichard Henderson gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx); 2983*37aff087SRichard Henderson plugin_gen_mem_callbacks(addr, oi, QEMU_PLUGIN_MEM_R); 2984e1dcf352SRichard Henderson 2985e1dcf352SRichard Henderson if ((orig_memop ^ memop) & MO_BSWAP) { 2986359feba5SRichard Henderson int flags = (orig_memop & MO_SIGN 2987359feba5SRichard Henderson ? TCG_BSWAP_IZ | TCG_BSWAP_OS 2988359feba5SRichard Henderson : TCG_BSWAP_IZ | TCG_BSWAP_OZ); 2989e1dcf352SRichard Henderson switch (orig_memop & MO_SIZE) { 2990e1dcf352SRichard Henderson case MO_16: 2991359feba5SRichard Henderson tcg_gen_bswap16_i64(val, val, flags); 2992e1dcf352SRichard Henderson break; 2993e1dcf352SRichard Henderson case MO_32: 2994359feba5SRichard Henderson tcg_gen_bswap32_i64(val, val, flags); 2995e1dcf352SRichard Henderson break; 2996e1dcf352SRichard Henderson case MO_64: 2997e1dcf352SRichard Henderson tcg_gen_bswap64_i64(val, val); 2998e1dcf352SRichard Henderson break; 2999e1dcf352SRichard Henderson default: 3000e1dcf352SRichard Henderson g_assert_not_reached(); 3001e1dcf352SRichard Henderson } 3002e1dcf352SRichard Henderson } 3003951c6300SRichard Henderson } 3004951c6300SRichard Henderson 300514776ab5STony Nguyen void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) 3006951c6300SRichard Henderson { 3007e1dcf352SRichard Henderson TCGv_i64 swap = NULL; 3008*37aff087SRichard Henderson MemOpIdx oi; 3009e6d86bedSEmilio G. Cota uint16_t info; 3010e1dcf352SRichard Henderson 30113a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) { 3012951c6300SRichard Henderson tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop); 3013951c6300SRichard Henderson return; 3014951c6300SRichard Henderson } 3015951c6300SRichard Henderson 3016e1dcf352SRichard Henderson tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 3017c45cb8bbSRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 1); 3018*37aff087SRichard Henderson oi = make_memop_idx(memop, idx); 3019*37aff087SRichard Henderson info = trace_mem_get_info(oi, 1); 3020e6d86bedSEmilio G. Cota trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, addr, info); 3021e1dcf352SRichard Henderson 3022e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 3023e1dcf352SRichard Henderson swap = tcg_temp_new_i64(); 3024e1dcf352SRichard Henderson switch (memop & MO_SIZE) { 3025e1dcf352SRichard Henderson case MO_16: 3026b53357acSRichard Henderson tcg_gen_bswap16_i64(swap, val, 0); 3027e1dcf352SRichard Henderson break; 3028e1dcf352SRichard Henderson case MO_32: 3029b53357acSRichard Henderson tcg_gen_bswap32_i64(swap, val, 0); 3030e1dcf352SRichard Henderson break; 3031e1dcf352SRichard Henderson case MO_64: 3032e1dcf352SRichard Henderson tcg_gen_bswap64_i64(swap, val); 3033e1dcf352SRichard Henderson break; 3034e1dcf352SRichard Henderson default: 3035e1dcf352SRichard Henderson g_assert_not_reached(); 3036e1dcf352SRichard Henderson } 3037e1dcf352SRichard Henderson val = swap; 3038e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 3039e1dcf352SRichard Henderson } 3040e1dcf352SRichard Henderson 3041fcc54ab5SAlex Bennée addr = plugin_prep_mem_callbacks(addr); 3042c45cb8bbSRichard Henderson gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx); 3043*37aff087SRichard Henderson plugin_gen_mem_callbacks(addr, oi, QEMU_PLUGIN_MEM_W); 3044e1dcf352SRichard Henderson 3045e1dcf352SRichard Henderson if (swap) { 3046e1dcf352SRichard Henderson tcg_temp_free_i64(swap); 3047e1dcf352SRichard Henderson } 3048951c6300SRichard Henderson } 3049c482cb11SRichard Henderson 305014776ab5STony Nguyen static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc) 3051c482cb11SRichard Henderson { 3052c482cb11SRichard Henderson switch (opc & MO_SSIZE) { 3053c482cb11SRichard Henderson case MO_SB: 3054c482cb11SRichard Henderson tcg_gen_ext8s_i32(ret, val); 3055c482cb11SRichard Henderson break; 3056c482cb11SRichard Henderson case MO_UB: 3057c482cb11SRichard Henderson tcg_gen_ext8u_i32(ret, val); 3058c482cb11SRichard Henderson break; 3059c482cb11SRichard Henderson case MO_SW: 3060c482cb11SRichard Henderson tcg_gen_ext16s_i32(ret, val); 3061c482cb11SRichard Henderson break; 3062c482cb11SRichard Henderson case MO_UW: 3063c482cb11SRichard Henderson tcg_gen_ext16u_i32(ret, val); 3064c482cb11SRichard Henderson break; 3065c482cb11SRichard Henderson default: 3066c482cb11SRichard Henderson tcg_gen_mov_i32(ret, val); 3067c482cb11SRichard Henderson break; 3068c482cb11SRichard Henderson } 3069c482cb11SRichard Henderson } 3070c482cb11SRichard Henderson 307114776ab5STony Nguyen static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc) 3072c482cb11SRichard Henderson { 3073c482cb11SRichard Henderson switch (opc & MO_SSIZE) { 3074c482cb11SRichard Henderson case MO_SB: 3075c482cb11SRichard Henderson tcg_gen_ext8s_i64(ret, val); 3076c482cb11SRichard Henderson break; 3077c482cb11SRichard Henderson case MO_UB: 3078c482cb11SRichard Henderson tcg_gen_ext8u_i64(ret, val); 3079c482cb11SRichard Henderson break; 3080c482cb11SRichard Henderson case MO_SW: 3081c482cb11SRichard Henderson tcg_gen_ext16s_i64(ret, val); 3082c482cb11SRichard Henderson break; 3083c482cb11SRichard Henderson case MO_UW: 3084c482cb11SRichard Henderson tcg_gen_ext16u_i64(ret, val); 3085c482cb11SRichard Henderson break; 3086c482cb11SRichard Henderson case MO_SL: 3087c482cb11SRichard Henderson tcg_gen_ext32s_i64(ret, val); 3088c482cb11SRichard Henderson break; 3089c482cb11SRichard Henderson case MO_UL: 3090c482cb11SRichard Henderson tcg_gen_ext32u_i64(ret, val); 3091c482cb11SRichard Henderson break; 3092c482cb11SRichard Henderson default: 3093c482cb11SRichard Henderson tcg_gen_mov_i64(ret, val); 3094c482cb11SRichard Henderson break; 3095c482cb11SRichard Henderson } 3096c482cb11SRichard Henderson } 3097c482cb11SRichard Henderson 3098c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv, 3099c482cb11SRichard Henderson TCGv_i32, TCGv_i32, TCGv_i32); 3100c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv, 3101c482cb11SRichard Henderson TCGv_i64, TCGv_i64, TCGv_i32); 3102c482cb11SRichard Henderson typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv, 3103c482cb11SRichard Henderson TCGv_i32, TCGv_i32); 3104c482cb11SRichard Henderson typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv, 3105c482cb11SRichard Henderson TCGv_i64, TCGv_i32); 3106c482cb11SRichard Henderson 3107df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64 3108df79b996SRichard Henderson # define WITH_ATOMIC64(X) X, 3109df79b996SRichard Henderson #else 3110df79b996SRichard Henderson # define WITH_ATOMIC64(X) 3111df79b996SRichard Henderson #endif 3112df79b996SRichard Henderson 31134b473e0cSRichard Henderson static void * const table_cmpxchg[(MO_SIZE | MO_BSWAP) + 1] = { 3114c482cb11SRichard Henderson [MO_8] = gen_helper_atomic_cmpxchgb, 3115c482cb11SRichard Henderson [MO_16 | MO_LE] = gen_helper_atomic_cmpxchgw_le, 3116c482cb11SRichard Henderson [MO_16 | MO_BE] = gen_helper_atomic_cmpxchgw_be, 3117c482cb11SRichard Henderson [MO_32 | MO_LE] = gen_helper_atomic_cmpxchgl_le, 3118c482cb11SRichard Henderson [MO_32 | MO_BE] = gen_helper_atomic_cmpxchgl_be, 3119df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_cmpxchgq_le) 3120df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_cmpxchgq_be) 3121c482cb11SRichard Henderson }; 3122c482cb11SRichard Henderson 3123c482cb11SRichard Henderson void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv, 312414776ab5STony Nguyen TCGv_i32 newv, TCGArg idx, MemOp memop) 3125c482cb11SRichard Henderson { 3126c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 3127c482cb11SRichard Henderson 3128b1311c4aSEmilio G. Cota if (!(tcg_ctx->tb_cflags & CF_PARALLEL)) { 3129c482cb11SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 3130c482cb11SRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 3131c482cb11SRichard Henderson 3132c482cb11SRichard Henderson tcg_gen_ext_i32(t2, cmpv, memop & MO_SIZE); 3133c482cb11SRichard Henderson 3134c482cb11SRichard Henderson tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN); 3135c482cb11SRichard Henderson tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, t2, newv, t1); 3136c482cb11SRichard Henderson tcg_gen_qemu_st_i32(t2, addr, idx, memop); 3137c482cb11SRichard Henderson tcg_temp_free_i32(t2); 3138c482cb11SRichard Henderson 3139c482cb11SRichard Henderson if (memop & MO_SIGN) { 3140c482cb11SRichard Henderson tcg_gen_ext_i32(retv, t1, memop); 3141c482cb11SRichard Henderson } else { 3142c482cb11SRichard Henderson tcg_gen_mov_i32(retv, t1); 3143c482cb11SRichard Henderson } 3144c482cb11SRichard Henderson tcg_temp_free_i32(t1); 3145c482cb11SRichard Henderson } else { 3146c482cb11SRichard Henderson gen_atomic_cx_i32 gen; 31479002ffcbSRichard Henderson MemOpIdx oi; 3148c482cb11SRichard Henderson 3149c482cb11SRichard Henderson gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; 3150c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3151c482cb11SRichard Henderson 3152e28a8664SRichard Henderson oi = make_memop_idx(memop & ~MO_SIGN, idx); 315311d11d61SRichard Henderson gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); 3154c482cb11SRichard Henderson 3155c482cb11SRichard Henderson if (memop & MO_SIGN) { 3156c482cb11SRichard Henderson tcg_gen_ext_i32(retv, retv, memop); 3157c482cb11SRichard Henderson } 3158c482cb11SRichard Henderson } 3159c482cb11SRichard Henderson } 3160c482cb11SRichard Henderson 3161c482cb11SRichard Henderson void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv, 316214776ab5STony Nguyen TCGv_i64 newv, TCGArg idx, MemOp memop) 3163c482cb11SRichard Henderson { 3164c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 3165c482cb11SRichard Henderson 3166b1311c4aSEmilio G. Cota if (!(tcg_ctx->tb_cflags & CF_PARALLEL)) { 3167c482cb11SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 3168c482cb11SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 3169c482cb11SRichard Henderson 3170c482cb11SRichard Henderson tcg_gen_ext_i64(t2, cmpv, memop & MO_SIZE); 3171c482cb11SRichard Henderson 3172c482cb11SRichard Henderson tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN); 3173c482cb11SRichard Henderson tcg_gen_movcond_i64(TCG_COND_EQ, t2, t1, t2, newv, t1); 3174c482cb11SRichard Henderson tcg_gen_qemu_st_i64(t2, addr, idx, memop); 3175c482cb11SRichard Henderson tcg_temp_free_i64(t2); 3176c482cb11SRichard Henderson 3177c482cb11SRichard Henderson if (memop & MO_SIGN) { 3178c482cb11SRichard Henderson tcg_gen_ext_i64(retv, t1, memop); 3179c482cb11SRichard Henderson } else { 3180c482cb11SRichard Henderson tcg_gen_mov_i64(retv, t1); 3181c482cb11SRichard Henderson } 3182c482cb11SRichard Henderson tcg_temp_free_i64(t1); 3183c482cb11SRichard Henderson } else if ((memop & MO_SIZE) == MO_64) { 3184df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64 3185c482cb11SRichard Henderson gen_atomic_cx_i64 gen; 31869002ffcbSRichard Henderson MemOpIdx oi; 3187c482cb11SRichard Henderson 3188c482cb11SRichard Henderson gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; 3189c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3190c482cb11SRichard Henderson 3191e28a8664SRichard Henderson oi = make_memop_idx(memop, idx); 319211d11d61SRichard Henderson gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); 3193df79b996SRichard Henderson #else 31941c2adb95SRichard Henderson gen_helper_exit_atomic(cpu_env); 319579b1af90SRichard Henderson /* Produce a result, so that we have a well-formed opcode stream 319679b1af90SRichard Henderson with respect to uses of the result in the (dead) code following. */ 319779b1af90SRichard Henderson tcg_gen_movi_i64(retv, 0); 3198df79b996SRichard Henderson #endif /* CONFIG_ATOMIC64 */ 3199c482cb11SRichard Henderson } else { 3200c482cb11SRichard Henderson TCGv_i32 c32 = tcg_temp_new_i32(); 3201c482cb11SRichard Henderson TCGv_i32 n32 = tcg_temp_new_i32(); 3202c482cb11SRichard Henderson TCGv_i32 r32 = tcg_temp_new_i32(); 3203c482cb11SRichard Henderson 3204c482cb11SRichard Henderson tcg_gen_extrl_i64_i32(c32, cmpv); 3205c482cb11SRichard Henderson tcg_gen_extrl_i64_i32(n32, newv); 3206c482cb11SRichard Henderson tcg_gen_atomic_cmpxchg_i32(r32, addr, c32, n32, idx, memop & ~MO_SIGN); 3207c482cb11SRichard Henderson tcg_temp_free_i32(c32); 3208c482cb11SRichard Henderson tcg_temp_free_i32(n32); 3209c482cb11SRichard Henderson 3210c482cb11SRichard Henderson tcg_gen_extu_i32_i64(retv, r32); 3211c482cb11SRichard Henderson tcg_temp_free_i32(r32); 3212c482cb11SRichard Henderson 3213c482cb11SRichard Henderson if (memop & MO_SIGN) { 3214c482cb11SRichard Henderson tcg_gen_ext_i64(retv, retv, memop); 3215c482cb11SRichard Henderson } 3216c482cb11SRichard Henderson } 3217c482cb11SRichard Henderson } 3218c482cb11SRichard Henderson 3219c482cb11SRichard Henderson static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, 322014776ab5STony Nguyen TCGArg idx, MemOp memop, bool new_val, 3221c482cb11SRichard Henderson void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32)) 3222c482cb11SRichard Henderson { 3223c482cb11SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 3224c482cb11SRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 3225c482cb11SRichard Henderson 3226c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 3227c482cb11SRichard Henderson 3228852f933eSRichard Henderson tcg_gen_qemu_ld_i32(t1, addr, idx, memop); 3229852f933eSRichard Henderson tcg_gen_ext_i32(t2, val, memop); 3230852f933eSRichard Henderson gen(t2, t1, t2); 3231c482cb11SRichard Henderson tcg_gen_qemu_st_i32(t2, addr, idx, memop); 3232c482cb11SRichard Henderson 3233c482cb11SRichard Henderson tcg_gen_ext_i32(ret, (new_val ? t2 : t1), memop); 3234c482cb11SRichard Henderson tcg_temp_free_i32(t1); 3235c482cb11SRichard Henderson tcg_temp_free_i32(t2); 3236c482cb11SRichard Henderson } 3237c482cb11SRichard Henderson 3238c482cb11SRichard Henderson static void do_atomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, 323914776ab5STony Nguyen TCGArg idx, MemOp memop, void * const table[]) 3240c482cb11SRichard Henderson { 3241c482cb11SRichard Henderson gen_atomic_op_i32 gen; 32429002ffcbSRichard Henderson MemOpIdx oi; 3243c482cb11SRichard Henderson 3244c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 3245c482cb11SRichard Henderson 3246c482cb11SRichard Henderson gen = table[memop & (MO_SIZE | MO_BSWAP)]; 3247c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3248c482cb11SRichard Henderson 3249e28a8664SRichard Henderson oi = make_memop_idx(memop & ~MO_SIGN, idx); 325011d11d61SRichard Henderson gen(ret, cpu_env, addr, val, tcg_constant_i32(oi)); 3251c482cb11SRichard Henderson 3252c482cb11SRichard Henderson if (memop & MO_SIGN) { 3253c482cb11SRichard Henderson tcg_gen_ext_i32(ret, ret, memop); 3254c482cb11SRichard Henderson } 3255c482cb11SRichard Henderson } 3256c482cb11SRichard Henderson 3257c482cb11SRichard Henderson static void do_nonatomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, 325814776ab5STony Nguyen TCGArg idx, MemOp memop, bool new_val, 3259c482cb11SRichard Henderson void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64)) 3260c482cb11SRichard Henderson { 3261c482cb11SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 3262c482cb11SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 3263c482cb11SRichard Henderson 3264c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 3265c482cb11SRichard Henderson 3266852f933eSRichard Henderson tcg_gen_qemu_ld_i64(t1, addr, idx, memop); 3267852f933eSRichard Henderson tcg_gen_ext_i64(t2, val, memop); 3268852f933eSRichard Henderson gen(t2, t1, t2); 3269c482cb11SRichard Henderson tcg_gen_qemu_st_i64(t2, addr, idx, memop); 3270c482cb11SRichard Henderson 3271c482cb11SRichard Henderson tcg_gen_ext_i64(ret, (new_val ? t2 : t1), memop); 3272c482cb11SRichard Henderson tcg_temp_free_i64(t1); 3273c482cb11SRichard Henderson tcg_temp_free_i64(t2); 3274c482cb11SRichard Henderson } 3275c482cb11SRichard Henderson 3276c482cb11SRichard Henderson static void do_atomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, 327714776ab5STony Nguyen TCGArg idx, MemOp memop, void * const table[]) 3278c482cb11SRichard Henderson { 3279c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 3280c482cb11SRichard Henderson 3281c482cb11SRichard Henderson if ((memop & MO_SIZE) == MO_64) { 3282df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64 3283c482cb11SRichard Henderson gen_atomic_op_i64 gen; 32849002ffcbSRichard Henderson MemOpIdx oi; 3285c482cb11SRichard Henderson 3286c482cb11SRichard Henderson gen = table[memop & (MO_SIZE | MO_BSWAP)]; 3287c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3288c482cb11SRichard Henderson 3289e28a8664SRichard Henderson oi = make_memop_idx(memop & ~MO_SIGN, idx); 329011d11d61SRichard Henderson gen(ret, cpu_env, addr, val, tcg_constant_i32(oi)); 3291df79b996SRichard Henderson #else 32921c2adb95SRichard Henderson gen_helper_exit_atomic(cpu_env); 329379b1af90SRichard Henderson /* Produce a result, so that we have a well-formed opcode stream 329479b1af90SRichard Henderson with respect to uses of the result in the (dead) code following. */ 329579b1af90SRichard Henderson tcg_gen_movi_i64(ret, 0); 3296df79b996SRichard Henderson #endif /* CONFIG_ATOMIC64 */ 3297c482cb11SRichard Henderson } else { 3298c482cb11SRichard Henderson TCGv_i32 v32 = tcg_temp_new_i32(); 3299c482cb11SRichard Henderson TCGv_i32 r32 = tcg_temp_new_i32(); 3300c482cb11SRichard Henderson 3301c482cb11SRichard Henderson tcg_gen_extrl_i64_i32(v32, val); 3302c482cb11SRichard Henderson do_atomic_op_i32(r32, addr, v32, idx, memop & ~MO_SIGN, table); 3303c482cb11SRichard Henderson tcg_temp_free_i32(v32); 3304c482cb11SRichard Henderson 3305c482cb11SRichard Henderson tcg_gen_extu_i32_i64(ret, r32); 3306c482cb11SRichard Henderson tcg_temp_free_i32(r32); 3307c482cb11SRichard Henderson 3308c482cb11SRichard Henderson if (memop & MO_SIGN) { 3309c482cb11SRichard Henderson tcg_gen_ext_i64(ret, ret, memop); 3310c482cb11SRichard Henderson } 3311c482cb11SRichard Henderson } 3312c482cb11SRichard Henderson } 3313c482cb11SRichard Henderson 3314c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(NAME, OP, NEW) \ 33154b473e0cSRichard Henderson static void * const table_##NAME[(MO_SIZE | MO_BSWAP) + 1] = { \ 3316c482cb11SRichard Henderson [MO_8] = gen_helper_atomic_##NAME##b, \ 3317c482cb11SRichard Henderson [MO_16 | MO_LE] = gen_helper_atomic_##NAME##w_le, \ 3318c482cb11SRichard Henderson [MO_16 | MO_BE] = gen_helper_atomic_##NAME##w_be, \ 3319c482cb11SRichard Henderson [MO_32 | MO_LE] = gen_helper_atomic_##NAME##l_le, \ 3320c482cb11SRichard Henderson [MO_32 | MO_BE] = gen_helper_atomic_##NAME##l_be, \ 3321df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_##NAME##q_le) \ 3322df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_##NAME##q_be) \ 3323c482cb11SRichard Henderson }; \ 3324c482cb11SRichard Henderson void tcg_gen_atomic_##NAME##_i32 \ 332514776ab5STony Nguyen (TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, MemOp memop) \ 3326c482cb11SRichard Henderson { \ 3327b1311c4aSEmilio G. Cota if (tcg_ctx->tb_cflags & CF_PARALLEL) { \ 3328c482cb11SRichard Henderson do_atomic_op_i32(ret, addr, val, idx, memop, table_##NAME); \ 3329c482cb11SRichard Henderson } else { \ 3330c482cb11SRichard Henderson do_nonatomic_op_i32(ret, addr, val, idx, memop, NEW, \ 3331c482cb11SRichard Henderson tcg_gen_##OP##_i32); \ 3332c482cb11SRichard Henderson } \ 3333c482cb11SRichard Henderson } \ 3334c482cb11SRichard Henderson void tcg_gen_atomic_##NAME##_i64 \ 333514776ab5STony Nguyen (TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, MemOp memop) \ 3336c482cb11SRichard Henderson { \ 3337b1311c4aSEmilio G. Cota if (tcg_ctx->tb_cflags & CF_PARALLEL) { \ 3338c482cb11SRichard Henderson do_atomic_op_i64(ret, addr, val, idx, memop, table_##NAME); \ 3339c482cb11SRichard Henderson } else { \ 3340c482cb11SRichard Henderson do_nonatomic_op_i64(ret, addr, val, idx, memop, NEW, \ 3341c482cb11SRichard Henderson tcg_gen_##OP##_i64); \ 3342c482cb11SRichard Henderson } \ 3343c482cb11SRichard Henderson } 3344c482cb11SRichard Henderson 3345c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add, add, 0) 3346c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and, and, 0) 3347c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or, or, 0) 3348c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor, xor, 0) 33495507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_smin, smin, 0) 33505507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_umin, umin, 0) 33515507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_smax, smax, 0) 33525507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_umax, umax, 0) 3353c482cb11SRichard Henderson 3354c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch, add, 1) 3355c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch, and, 1) 3356c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch, or, 1) 3357c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch, xor, 1) 33585507c2bfSRichard Henderson GEN_ATOMIC_HELPER(smin_fetch, smin, 1) 33595507c2bfSRichard Henderson GEN_ATOMIC_HELPER(umin_fetch, umin, 1) 33605507c2bfSRichard Henderson GEN_ATOMIC_HELPER(smax_fetch, smax, 1) 33615507c2bfSRichard Henderson GEN_ATOMIC_HELPER(umax_fetch, umax, 1) 3362c482cb11SRichard Henderson 3363c482cb11SRichard Henderson static void tcg_gen_mov2_i32(TCGv_i32 r, TCGv_i32 a, TCGv_i32 b) 3364c482cb11SRichard Henderson { 3365c482cb11SRichard Henderson tcg_gen_mov_i32(r, b); 3366c482cb11SRichard Henderson } 3367c482cb11SRichard Henderson 3368c482cb11SRichard Henderson static void tcg_gen_mov2_i64(TCGv_i64 r, TCGv_i64 a, TCGv_i64 b) 3369c482cb11SRichard Henderson { 3370c482cb11SRichard Henderson tcg_gen_mov_i64(r, b); 3371c482cb11SRichard Henderson } 3372c482cb11SRichard Henderson 3373c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xchg, mov2, 0) 3374c482cb11SRichard Henderson 3375c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 3376