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" 30e6d86bedSEmilio G. Cota #include "exec/plugin-gen.h" 31d56fea79SRichard Henderson #include "tcg-internal.h" 32951c6300SRichard Henderson 33951c6300SRichard Henderson 34b7e8b17aSRichard Henderson void tcg_gen_op1(TCGOpcode opc, TCGArg a1) 35951c6300SRichard Henderson { 36d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_emit_op(opc, 1); 3775e8b9b7SRichard Henderson op->args[0] = a1; 38951c6300SRichard Henderson } 39951c6300SRichard Henderson 40b7e8b17aSRichard Henderson void tcg_gen_op2(TCGOpcode opc, TCGArg a1, TCGArg a2) 41951c6300SRichard Henderson { 42d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_emit_op(opc, 2); 4375e8b9b7SRichard Henderson op->args[0] = a1; 4475e8b9b7SRichard Henderson op->args[1] = a2; 45951c6300SRichard Henderson } 46951c6300SRichard Henderson 47b7e8b17aSRichard Henderson void tcg_gen_op3(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3) 48951c6300SRichard Henderson { 49d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_emit_op(opc, 3); 5075e8b9b7SRichard Henderson op->args[0] = a1; 5175e8b9b7SRichard Henderson op->args[1] = a2; 5275e8b9b7SRichard Henderson op->args[2] = a3; 53951c6300SRichard Henderson } 54951c6300SRichard Henderson 55b7e8b17aSRichard Henderson void tcg_gen_op4(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, TCGArg a4) 56951c6300SRichard Henderson { 57d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_emit_op(opc, 4); 5875e8b9b7SRichard Henderson op->args[0] = a1; 5975e8b9b7SRichard Henderson op->args[1] = a2; 6075e8b9b7SRichard Henderson op->args[2] = a3; 6175e8b9b7SRichard Henderson op->args[3] = a4; 62951c6300SRichard Henderson } 63951c6300SRichard Henderson 64b7e8b17aSRichard Henderson void tcg_gen_op5(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, 65b7e8b17aSRichard Henderson TCGArg a4, TCGArg a5) 66951c6300SRichard Henderson { 67d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_emit_op(opc, 5); 6875e8b9b7SRichard Henderson op->args[0] = a1; 6975e8b9b7SRichard Henderson op->args[1] = a2; 7075e8b9b7SRichard Henderson op->args[2] = a3; 7175e8b9b7SRichard Henderson op->args[3] = a4; 7275e8b9b7SRichard Henderson op->args[4] = a5; 73951c6300SRichard Henderson } 74951c6300SRichard Henderson 75b7e8b17aSRichard Henderson void tcg_gen_op6(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, 76b7e8b17aSRichard Henderson TCGArg a4, TCGArg a5, TCGArg a6) 77951c6300SRichard Henderson { 78d4478943SPhilippe Mathieu-Daudé TCGOp *op = tcg_emit_op(opc, 6); 7975e8b9b7SRichard Henderson op->args[0] = a1; 8075e8b9b7SRichard Henderson op->args[1] = a2; 8175e8b9b7SRichard Henderson op->args[2] = a3; 8275e8b9b7SRichard Henderson op->args[3] = a4; 8375e8b9b7SRichard Henderson op->args[4] = a5; 8475e8b9b7SRichard Henderson op->args[5] = a6; 85951c6300SRichard Henderson } 86951c6300SRichard Henderson 87f65e19bcSPranith Kumar void tcg_gen_mb(TCGBar mb_type) 88f65e19bcSPranith Kumar { 89b7e4afbdSRichard Henderson if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) { 90b7e8b17aSRichard Henderson tcg_gen_op1(INDEX_op_mb, mb_type); 91f65e19bcSPranith Kumar } 92f65e19bcSPranith Kumar } 93f65e19bcSPranith Kumar 94951c6300SRichard Henderson /* 32 bit ops */ 95951c6300SRichard Henderson 9611d11d61SRichard Henderson void tcg_gen_movi_i32(TCGv_i32 ret, int32_t arg) 9711d11d61SRichard Henderson { 9811d11d61SRichard Henderson tcg_gen_mov_i32(ret, tcg_constant_i32(arg)); 9911d11d61SRichard Henderson } 10011d11d61SRichard Henderson 101951c6300SRichard Henderson void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 102951c6300SRichard Henderson { 103951c6300SRichard Henderson /* some cases can be optimized here */ 104951c6300SRichard Henderson if (arg2 == 0) { 105951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 106951c6300SRichard Henderson } else { 10711d11d61SRichard Henderson tcg_gen_add_i32(ret, arg1, tcg_constant_i32(arg2)); 108951c6300SRichard Henderson } 109951c6300SRichard Henderson } 110951c6300SRichard Henderson 111951c6300SRichard Henderson void tcg_gen_subfi_i32(TCGv_i32 ret, int32_t arg1, TCGv_i32 arg2) 112951c6300SRichard Henderson { 113951c6300SRichard Henderson if (arg1 == 0 && TCG_TARGET_HAS_neg_i32) { 114951c6300SRichard Henderson /* Don't recurse with tcg_gen_neg_i32. */ 115951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg2); 116951c6300SRichard Henderson } else { 11711d11d61SRichard Henderson tcg_gen_sub_i32(ret, tcg_constant_i32(arg1), arg2); 118951c6300SRichard Henderson } 119951c6300SRichard Henderson } 120951c6300SRichard Henderson 121951c6300SRichard Henderson void tcg_gen_subi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 122951c6300SRichard Henderson { 123951c6300SRichard Henderson /* some cases can be optimized here */ 124951c6300SRichard Henderson if (arg2 == 0) { 125951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 126951c6300SRichard Henderson } else { 12711d11d61SRichard Henderson tcg_gen_sub_i32(ret, arg1, tcg_constant_i32(arg2)); 128951c6300SRichard Henderson } 129951c6300SRichard Henderson } 130951c6300SRichard Henderson 131474b2e8fSRichard Henderson void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 132951c6300SRichard Henderson { 133951c6300SRichard Henderson /* Some cases can be optimized here. */ 134951c6300SRichard Henderson switch (arg2) { 135951c6300SRichard Henderson case 0: 136951c6300SRichard Henderson tcg_gen_movi_i32(ret, 0); 137951c6300SRichard Henderson return; 138474b2e8fSRichard Henderson case -1: 139951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 140951c6300SRichard Henderson return; 141474b2e8fSRichard Henderson case 0xff: 142951c6300SRichard Henderson /* Don't recurse with tcg_gen_ext8u_i32. */ 143951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 144951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg1); 145951c6300SRichard Henderson return; 146951c6300SRichard Henderson } 147951c6300SRichard Henderson break; 148474b2e8fSRichard Henderson case 0xffff: 149951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 150951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg1); 151951c6300SRichard Henderson return; 152951c6300SRichard Henderson } 153951c6300SRichard Henderson break; 154951c6300SRichard Henderson } 15511d11d61SRichard Henderson 15611d11d61SRichard Henderson tcg_gen_and_i32(ret, arg1, tcg_constant_i32(arg2)); 157951c6300SRichard Henderson } 158951c6300SRichard Henderson 159951c6300SRichard Henderson void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 160951c6300SRichard Henderson { 161951c6300SRichard Henderson /* Some cases can be optimized here. */ 162951c6300SRichard Henderson if (arg2 == -1) { 163951c6300SRichard Henderson tcg_gen_movi_i32(ret, -1); 164951c6300SRichard Henderson } else if (arg2 == 0) { 165951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 166951c6300SRichard Henderson } else { 16711d11d61SRichard Henderson tcg_gen_or_i32(ret, arg1, tcg_constant_i32(arg2)); 168951c6300SRichard Henderson } 169951c6300SRichard Henderson } 170951c6300SRichard Henderson 171951c6300SRichard Henderson void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 172951c6300SRichard Henderson { 173951c6300SRichard Henderson /* Some cases can be optimized here. */ 174951c6300SRichard Henderson if (arg2 == 0) { 175951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 176951c6300SRichard Henderson } else if (arg2 == -1 && TCG_TARGET_HAS_not_i32) { 177951c6300SRichard Henderson /* Don't recurse with tcg_gen_not_i32. */ 178951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg1); 179951c6300SRichard Henderson } else { 18011d11d61SRichard Henderson tcg_gen_xor_i32(ret, arg1, tcg_constant_i32(arg2)); 181951c6300SRichard Henderson } 182951c6300SRichard Henderson } 183951c6300SRichard Henderson 184474b2e8fSRichard Henderson void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 185951c6300SRichard Henderson { 186474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 187951c6300SRichard Henderson if (arg2 == 0) { 188951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 189951c6300SRichard Henderson } else { 19011d11d61SRichard Henderson tcg_gen_shl_i32(ret, arg1, tcg_constant_i32(arg2)); 191951c6300SRichard Henderson } 192951c6300SRichard Henderson } 193951c6300SRichard Henderson 194474b2e8fSRichard Henderson void tcg_gen_shri_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_shr_i32(ret, arg1, tcg_constant_i32(arg2)); 201951c6300SRichard Henderson } 202951c6300SRichard Henderson } 203951c6300SRichard Henderson 204474b2e8fSRichard Henderson void tcg_gen_sari_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_sar_i32(ret, arg1, tcg_constant_i32(arg2)); 211951c6300SRichard Henderson } 212951c6300SRichard Henderson } 213951c6300SRichard Henderson 21442a268c2SRichard Henderson void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1, TCGv_i32 arg2, TCGLabel *l) 215951c6300SRichard Henderson { 216951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 21742a268c2SRichard Henderson tcg_gen_br(l); 218951c6300SRichard Henderson } else if (cond != TCG_COND_NEVER) { 219d88a117eSRichard Henderson l->refs++; 22042a268c2SRichard Henderson tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_arg(l)); 221951c6300SRichard Henderson } 222951c6300SRichard Henderson } 223951c6300SRichard Henderson 22442a268c2SRichard Henderson void tcg_gen_brcondi_i32(TCGCond cond, TCGv_i32 arg1, int32_t arg2, TCGLabel *l) 225951c6300SRichard Henderson { 22637ed3bf1SRichard Henderson if (cond == TCG_COND_ALWAYS) { 22737ed3bf1SRichard Henderson tcg_gen_br(l); 22837ed3bf1SRichard Henderson } else if (cond != TCG_COND_NEVER) { 22911d11d61SRichard Henderson tcg_gen_brcond_i32(cond, arg1, tcg_constant_i32(arg2), l); 230951c6300SRichard Henderson } 23137ed3bf1SRichard Henderson } 232951c6300SRichard Henderson 233951c6300SRichard Henderson void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret, 234951c6300SRichard Henderson TCGv_i32 arg1, TCGv_i32 arg2) 235951c6300SRichard Henderson { 236951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 237951c6300SRichard Henderson tcg_gen_movi_i32(ret, 1); 238951c6300SRichard Henderson } else if (cond == TCG_COND_NEVER) { 239951c6300SRichard Henderson tcg_gen_movi_i32(ret, 0); 240951c6300SRichard Henderson } else { 241951c6300SRichard Henderson tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond); 242951c6300SRichard Henderson } 243951c6300SRichard Henderson } 244951c6300SRichard Henderson 245951c6300SRichard Henderson void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret, 246951c6300SRichard Henderson TCGv_i32 arg1, int32_t arg2) 247951c6300SRichard Henderson { 24811d11d61SRichard Henderson tcg_gen_setcond_i32(cond, ret, arg1, tcg_constant_i32(arg2)); 249951c6300SRichard Henderson } 250951c6300SRichard Henderson 251951c6300SRichard Henderson void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 252951c6300SRichard Henderson { 253b2e3ae94SRichard Henderson if (arg2 == 0) { 254b2e3ae94SRichard Henderson tcg_gen_movi_i32(ret, 0); 255b2e3ae94SRichard Henderson } else if (is_power_of_2(arg2)) { 256b2e3ae94SRichard Henderson tcg_gen_shli_i32(ret, arg1, ctz32(arg2)); 257b2e3ae94SRichard Henderson } else { 25811d11d61SRichard Henderson tcg_gen_mul_i32(ret, arg1, tcg_constant_i32(arg2)); 259951c6300SRichard Henderson } 260b2e3ae94SRichard Henderson } 261951c6300SRichard Henderson 262951c6300SRichard Henderson void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 263951c6300SRichard Henderson { 264951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i32) { 265951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2); 266951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 267951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 268951c6300SRichard Henderson tcg_gen_sari_i32(t0, arg1, 31); 269951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2); 270951c6300SRichard Henderson tcg_temp_free_i32(t0); 271951c6300SRichard Henderson } else { 272951c6300SRichard Henderson gen_helper_div_i32(ret, arg1, arg2); 273951c6300SRichard Henderson } 274951c6300SRichard Henderson } 275951c6300SRichard Henderson 276951c6300SRichard Henderson void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 277951c6300SRichard Henderson { 278951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i32) { 279951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2); 280951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i32) { 281951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 282951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_div_i32, t0, arg1, arg2); 283951c6300SRichard Henderson tcg_gen_mul_i32(t0, t0, arg2); 284951c6300SRichard Henderson tcg_gen_sub_i32(ret, arg1, t0); 285951c6300SRichard Henderson tcg_temp_free_i32(t0); 286951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 287951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 288951c6300SRichard Henderson tcg_gen_sari_i32(t0, arg1, 31); 289951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2); 290951c6300SRichard Henderson tcg_temp_free_i32(t0); 291951c6300SRichard Henderson } else { 292951c6300SRichard Henderson gen_helper_rem_i32(ret, arg1, arg2); 293951c6300SRichard Henderson } 294951c6300SRichard Henderson } 295951c6300SRichard Henderson 296951c6300SRichard Henderson void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 297951c6300SRichard Henderson { 298951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i32) { 299951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2); 300951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 301951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 302951c6300SRichard Henderson tcg_gen_movi_i32(t0, 0); 303951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2); 304951c6300SRichard Henderson tcg_temp_free_i32(t0); 305951c6300SRichard Henderson } else { 306951c6300SRichard Henderson gen_helper_divu_i32(ret, arg1, arg2); 307951c6300SRichard Henderson } 308951c6300SRichard Henderson } 309951c6300SRichard Henderson 310951c6300SRichard Henderson void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 311951c6300SRichard Henderson { 312951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i32) { 313951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2); 314951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i32) { 315951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 316951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_divu_i32, t0, arg1, arg2); 317951c6300SRichard Henderson tcg_gen_mul_i32(t0, t0, arg2); 318951c6300SRichard Henderson tcg_gen_sub_i32(ret, arg1, t0); 319951c6300SRichard Henderson tcg_temp_free_i32(t0); 320951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 321951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 322951c6300SRichard Henderson tcg_gen_movi_i32(t0, 0); 323951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2); 324951c6300SRichard Henderson tcg_temp_free_i32(t0); 325951c6300SRichard Henderson } else { 326951c6300SRichard Henderson gen_helper_remu_i32(ret, arg1, arg2); 327951c6300SRichard Henderson } 328951c6300SRichard Henderson } 329951c6300SRichard Henderson 330951c6300SRichard Henderson void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 331951c6300SRichard Henderson { 332951c6300SRichard Henderson if (TCG_TARGET_HAS_andc_i32) { 333951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2); 334951c6300SRichard Henderson } else { 335951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 336951c6300SRichard Henderson tcg_gen_not_i32(t0, arg2); 337951c6300SRichard Henderson tcg_gen_and_i32(ret, arg1, t0); 338951c6300SRichard Henderson tcg_temp_free_i32(t0); 339951c6300SRichard Henderson } 340951c6300SRichard Henderson } 341951c6300SRichard Henderson 342951c6300SRichard Henderson void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 343951c6300SRichard Henderson { 344951c6300SRichard Henderson if (TCG_TARGET_HAS_eqv_i32) { 345951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_eqv_i32, ret, arg1, arg2); 346951c6300SRichard Henderson } else { 347951c6300SRichard Henderson tcg_gen_xor_i32(ret, arg1, arg2); 348951c6300SRichard Henderson tcg_gen_not_i32(ret, ret); 349951c6300SRichard Henderson } 350951c6300SRichard Henderson } 351951c6300SRichard Henderson 352951c6300SRichard Henderson void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 353951c6300SRichard Henderson { 354951c6300SRichard Henderson if (TCG_TARGET_HAS_nand_i32) { 355951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_nand_i32, ret, arg1, arg2); 356951c6300SRichard Henderson } else { 357951c6300SRichard Henderson tcg_gen_and_i32(ret, arg1, arg2); 358951c6300SRichard Henderson tcg_gen_not_i32(ret, ret); 359951c6300SRichard Henderson } 360951c6300SRichard Henderson } 361951c6300SRichard Henderson 362951c6300SRichard Henderson void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 363951c6300SRichard Henderson { 364951c6300SRichard Henderson if (TCG_TARGET_HAS_nor_i32) { 365951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_nor_i32, ret, arg1, arg2); 366951c6300SRichard Henderson } else { 367951c6300SRichard Henderson tcg_gen_or_i32(ret, arg1, arg2); 368951c6300SRichard Henderson tcg_gen_not_i32(ret, ret); 369951c6300SRichard Henderson } 370951c6300SRichard Henderson } 371951c6300SRichard Henderson 372951c6300SRichard Henderson void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 373951c6300SRichard Henderson { 374951c6300SRichard Henderson if (TCG_TARGET_HAS_orc_i32) { 375951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2); 376951c6300SRichard Henderson } else { 377951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 378951c6300SRichard Henderson tcg_gen_not_i32(t0, arg2); 379951c6300SRichard Henderson tcg_gen_or_i32(ret, arg1, t0); 380951c6300SRichard Henderson tcg_temp_free_i32(t0); 381951c6300SRichard Henderson } 382951c6300SRichard Henderson } 383951c6300SRichard Henderson 3840e28d006SRichard Henderson void tcg_gen_clz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 3850e28d006SRichard Henderson { 3860e28d006SRichard Henderson if (TCG_TARGET_HAS_clz_i32) { 3870e28d006SRichard Henderson tcg_gen_op3_i32(INDEX_op_clz_i32, ret, arg1, arg2); 3880e28d006SRichard Henderson } else if (TCG_TARGET_HAS_clz_i64) { 3890e28d006SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 3900e28d006SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 3910e28d006SRichard Henderson tcg_gen_extu_i32_i64(t1, arg1); 3920e28d006SRichard Henderson tcg_gen_extu_i32_i64(t2, arg2); 3930e28d006SRichard Henderson tcg_gen_addi_i64(t2, t2, 32); 3940e28d006SRichard Henderson tcg_gen_clz_i64(t1, t1, t2); 3950e28d006SRichard Henderson tcg_gen_extrl_i64_i32(ret, t1); 3960e28d006SRichard Henderson tcg_temp_free_i64(t1); 3970e28d006SRichard Henderson tcg_temp_free_i64(t2); 3980e28d006SRichard Henderson tcg_gen_subi_i32(ret, ret, 32); 3990e28d006SRichard Henderson } else { 4000e28d006SRichard Henderson gen_helper_clz_i32(ret, arg1, arg2); 4010e28d006SRichard Henderson } 4020e28d006SRichard Henderson } 4030e28d006SRichard Henderson 4040e28d006SRichard Henderson void tcg_gen_clzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) 4050e28d006SRichard Henderson { 40611d11d61SRichard Henderson tcg_gen_clz_i32(ret, arg1, tcg_constant_i32(arg2)); 4070e28d006SRichard Henderson } 4080e28d006SRichard Henderson 4090e28d006SRichard Henderson void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 4100e28d006SRichard Henderson { 4110e28d006SRichard Henderson if (TCG_TARGET_HAS_ctz_i32) { 4120e28d006SRichard Henderson tcg_gen_op3_i32(INDEX_op_ctz_i32, ret, arg1, arg2); 4130e28d006SRichard Henderson } else if (TCG_TARGET_HAS_ctz_i64) { 4140e28d006SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 4150e28d006SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 4160e28d006SRichard Henderson tcg_gen_extu_i32_i64(t1, arg1); 4170e28d006SRichard Henderson tcg_gen_extu_i32_i64(t2, arg2); 4180e28d006SRichard Henderson tcg_gen_ctz_i64(t1, t1, t2); 4190e28d006SRichard Henderson tcg_gen_extrl_i64_i32(ret, t1); 4200e28d006SRichard Henderson tcg_temp_free_i64(t1); 4210e28d006SRichard Henderson tcg_temp_free_i64(t2); 42214e99210SRichard Henderson } else if (TCG_TARGET_HAS_ctpop_i32 42314e99210SRichard Henderson || TCG_TARGET_HAS_ctpop_i64 42414e99210SRichard Henderson || TCG_TARGET_HAS_clz_i32 42514e99210SRichard Henderson || TCG_TARGET_HAS_clz_i64) { 42614e99210SRichard Henderson TCGv_i32 z, t = tcg_temp_new_i32(); 42714e99210SRichard Henderson 42814e99210SRichard Henderson if (TCG_TARGET_HAS_ctpop_i32 || TCG_TARGET_HAS_ctpop_i64) { 42914e99210SRichard Henderson tcg_gen_subi_i32(t, arg1, 1); 43014e99210SRichard Henderson tcg_gen_andc_i32(t, t, arg1); 43114e99210SRichard Henderson tcg_gen_ctpop_i32(t, t); 43214e99210SRichard Henderson } else { 43314e99210SRichard Henderson /* Since all non-x86 hosts have clz(0) == 32, don't fight it. */ 43414e99210SRichard Henderson tcg_gen_neg_i32(t, arg1); 43514e99210SRichard Henderson tcg_gen_and_i32(t, t, arg1); 43614e99210SRichard Henderson tcg_gen_clzi_i32(t, t, 32); 43714e99210SRichard Henderson tcg_gen_xori_i32(t, t, 31); 43814e99210SRichard Henderson } 43911d11d61SRichard Henderson z = tcg_constant_i32(0); 44014e99210SRichard Henderson tcg_gen_movcond_i32(TCG_COND_EQ, ret, arg1, z, arg2, t); 44114e99210SRichard Henderson tcg_temp_free_i32(t); 4420e28d006SRichard Henderson } else { 4430e28d006SRichard Henderson gen_helper_ctz_i32(ret, arg1, arg2); 4440e28d006SRichard Henderson } 4450e28d006SRichard Henderson } 4460e28d006SRichard Henderson 4470e28d006SRichard Henderson void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) 4480e28d006SRichard Henderson { 44914e99210SRichard Henderson if (!TCG_TARGET_HAS_ctz_i32 && TCG_TARGET_HAS_ctpop_i32 && arg2 == 32) { 45014e99210SRichard Henderson /* This equivalence has the advantage of not requiring a fixup. */ 45114e99210SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 45214e99210SRichard Henderson tcg_gen_subi_i32(t, arg1, 1); 45314e99210SRichard Henderson tcg_gen_andc_i32(t, t, arg1); 45414e99210SRichard Henderson tcg_gen_ctpop_i32(ret, t); 45514e99210SRichard Henderson tcg_temp_free_i32(t); 45614e99210SRichard Henderson } else { 45711d11d61SRichard Henderson tcg_gen_ctz_i32(ret, arg1, tcg_constant_i32(arg2)); 4580e28d006SRichard Henderson } 45914e99210SRichard Henderson } 4600e28d006SRichard Henderson 461086920c2SRichard Henderson void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg) 462086920c2SRichard Henderson { 463086920c2SRichard Henderson if (TCG_TARGET_HAS_clz_i32) { 464086920c2SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 465086920c2SRichard Henderson tcg_gen_sari_i32(t, arg, 31); 466086920c2SRichard Henderson tcg_gen_xor_i32(t, t, arg); 467086920c2SRichard Henderson tcg_gen_clzi_i32(t, t, 32); 468086920c2SRichard Henderson tcg_gen_subi_i32(ret, t, 1); 469086920c2SRichard Henderson tcg_temp_free_i32(t); 470086920c2SRichard Henderson } else { 471086920c2SRichard Henderson gen_helper_clrsb_i32(ret, arg); 472086920c2SRichard Henderson } 473086920c2SRichard Henderson } 474086920c2SRichard Henderson 475a768e4e9SRichard Henderson void tcg_gen_ctpop_i32(TCGv_i32 ret, TCGv_i32 arg1) 476a768e4e9SRichard Henderson { 477a768e4e9SRichard Henderson if (TCG_TARGET_HAS_ctpop_i32) { 478a768e4e9SRichard Henderson tcg_gen_op2_i32(INDEX_op_ctpop_i32, ret, arg1); 479a768e4e9SRichard Henderson } else if (TCG_TARGET_HAS_ctpop_i64) { 480a768e4e9SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 481a768e4e9SRichard Henderson tcg_gen_extu_i32_i64(t, arg1); 482a768e4e9SRichard Henderson tcg_gen_ctpop_i64(t, t); 483a768e4e9SRichard Henderson tcg_gen_extrl_i64_i32(ret, t); 484a768e4e9SRichard Henderson tcg_temp_free_i64(t); 485a768e4e9SRichard Henderson } else { 486a768e4e9SRichard Henderson gen_helper_ctpop_i32(ret, arg1); 487a768e4e9SRichard Henderson } 488a768e4e9SRichard Henderson } 489a768e4e9SRichard Henderson 490951c6300SRichard Henderson void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 491951c6300SRichard Henderson { 492951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i32) { 493951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2); 494951c6300SRichard Henderson } else { 495951c6300SRichard Henderson TCGv_i32 t0, t1; 496951c6300SRichard Henderson 497951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 498951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 499951c6300SRichard Henderson tcg_gen_shl_i32(t0, arg1, arg2); 500951c6300SRichard Henderson tcg_gen_subfi_i32(t1, 32, arg2); 501951c6300SRichard Henderson tcg_gen_shr_i32(t1, arg1, t1); 502951c6300SRichard Henderson tcg_gen_or_i32(ret, t0, t1); 503951c6300SRichard Henderson tcg_temp_free_i32(t0); 504951c6300SRichard Henderson tcg_temp_free_i32(t1); 505951c6300SRichard Henderson } 506951c6300SRichard Henderson } 507951c6300SRichard Henderson 50807dada03SRichard Henderson void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 509951c6300SRichard Henderson { 51007dada03SRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 511951c6300SRichard Henderson /* some cases can be optimized here */ 512951c6300SRichard Henderson if (arg2 == 0) { 513951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 514951c6300SRichard Henderson } else if (TCG_TARGET_HAS_rot_i32) { 51511d11d61SRichard Henderson tcg_gen_rotl_i32(ret, arg1, tcg_constant_i32(arg2)); 516951c6300SRichard Henderson } else { 517951c6300SRichard Henderson TCGv_i32 t0, t1; 518951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 519951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 520951c6300SRichard Henderson tcg_gen_shli_i32(t0, arg1, arg2); 521951c6300SRichard Henderson tcg_gen_shri_i32(t1, arg1, 32 - arg2); 522951c6300SRichard Henderson tcg_gen_or_i32(ret, t0, t1); 523951c6300SRichard Henderson tcg_temp_free_i32(t0); 524951c6300SRichard Henderson tcg_temp_free_i32(t1); 525951c6300SRichard Henderson } 526951c6300SRichard Henderson } 527951c6300SRichard Henderson 528951c6300SRichard Henderson void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 529951c6300SRichard Henderson { 530951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i32) { 531951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2); 532951c6300SRichard Henderson } else { 533951c6300SRichard Henderson TCGv_i32 t0, t1; 534951c6300SRichard Henderson 535951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 536951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 537951c6300SRichard Henderson tcg_gen_shr_i32(t0, arg1, arg2); 538951c6300SRichard Henderson tcg_gen_subfi_i32(t1, 32, arg2); 539951c6300SRichard Henderson tcg_gen_shl_i32(t1, arg1, t1); 540951c6300SRichard Henderson tcg_gen_or_i32(ret, t0, t1); 541951c6300SRichard Henderson tcg_temp_free_i32(t0); 542951c6300SRichard Henderson tcg_temp_free_i32(t1); 543951c6300SRichard Henderson } 544951c6300SRichard Henderson } 545951c6300SRichard Henderson 54607dada03SRichard Henderson void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 547951c6300SRichard Henderson { 54807dada03SRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 549951c6300SRichard Henderson /* some cases can be optimized here */ 550951c6300SRichard Henderson if (arg2 == 0) { 551951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 552951c6300SRichard Henderson } else { 553951c6300SRichard Henderson tcg_gen_rotli_i32(ret, arg1, 32 - arg2); 554951c6300SRichard Henderson } 555951c6300SRichard Henderson } 556951c6300SRichard Henderson 557951c6300SRichard Henderson void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2, 558951c6300SRichard Henderson unsigned int ofs, unsigned int len) 559951c6300SRichard Henderson { 560951c6300SRichard Henderson uint32_t mask; 561951c6300SRichard Henderson TCGv_i32 t1; 562951c6300SRichard Henderson 563951c6300SRichard Henderson tcg_debug_assert(ofs < 32); 5640d0d309dSRichard Henderson tcg_debug_assert(len > 0); 565951c6300SRichard Henderson tcg_debug_assert(len <= 32); 566951c6300SRichard Henderson tcg_debug_assert(ofs + len <= 32); 567951c6300SRichard Henderson 5680d0d309dSRichard Henderson if (len == 32) { 569951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg2); 570951c6300SRichard Henderson return; 571951c6300SRichard Henderson } 572951c6300SRichard Henderson if (TCG_TARGET_HAS_deposit_i32 && TCG_TARGET_deposit_i32_valid(ofs, len)) { 573951c6300SRichard Henderson tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len); 574951c6300SRichard Henderson return; 575951c6300SRichard Henderson } 576951c6300SRichard Henderson 577951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 578951c6300SRichard Henderson 579b0a60567SRichard Henderson if (TCG_TARGET_HAS_extract2_i32) { 580b0a60567SRichard Henderson if (ofs + len == 32) { 581b0a60567SRichard Henderson tcg_gen_shli_i32(t1, arg1, len); 582b0a60567SRichard Henderson tcg_gen_extract2_i32(ret, t1, arg2, len); 583b0a60567SRichard Henderson goto done; 584b0a60567SRichard Henderson } 585b0a60567SRichard Henderson if (ofs == 0) { 586b0a60567SRichard Henderson tcg_gen_extract2_i32(ret, arg1, arg2, len); 587b0a60567SRichard Henderson tcg_gen_rotli_i32(ret, ret, len); 588b0a60567SRichard Henderson goto done; 589b0a60567SRichard Henderson } 590b0a60567SRichard Henderson } 591b0a60567SRichard Henderson 592b0a60567SRichard Henderson mask = (1u << len) - 1; 593951c6300SRichard Henderson if (ofs + len < 32) { 594951c6300SRichard Henderson tcg_gen_andi_i32(t1, arg2, mask); 595951c6300SRichard Henderson tcg_gen_shli_i32(t1, t1, ofs); 596951c6300SRichard Henderson } else { 597951c6300SRichard Henderson tcg_gen_shli_i32(t1, arg2, ofs); 598951c6300SRichard Henderson } 599951c6300SRichard Henderson tcg_gen_andi_i32(ret, arg1, ~(mask << ofs)); 600951c6300SRichard Henderson tcg_gen_or_i32(ret, ret, t1); 601b0a60567SRichard Henderson done: 602951c6300SRichard Henderson tcg_temp_free_i32(t1); 603951c6300SRichard Henderson } 604951c6300SRichard Henderson 60507cc68d5SRichard Henderson void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg, 60607cc68d5SRichard Henderson unsigned int ofs, unsigned int len) 60707cc68d5SRichard Henderson { 60807cc68d5SRichard Henderson tcg_debug_assert(ofs < 32); 60907cc68d5SRichard Henderson tcg_debug_assert(len > 0); 61007cc68d5SRichard Henderson tcg_debug_assert(len <= 32); 61107cc68d5SRichard Henderson tcg_debug_assert(ofs + len <= 32); 61207cc68d5SRichard Henderson 61307cc68d5SRichard Henderson if (ofs + len == 32) { 61407cc68d5SRichard Henderson tcg_gen_shli_i32(ret, arg, ofs); 61507cc68d5SRichard Henderson } else if (ofs == 0) { 61607cc68d5SRichard Henderson tcg_gen_andi_i32(ret, arg, (1u << len) - 1); 61707cc68d5SRichard Henderson } else if (TCG_TARGET_HAS_deposit_i32 61807cc68d5SRichard Henderson && TCG_TARGET_deposit_i32_valid(ofs, len)) { 61911d11d61SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0); 62007cc68d5SRichard Henderson tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, zero, arg, ofs, len); 62107cc68d5SRichard Henderson } else { 62207cc68d5SRichard Henderson /* To help two-operand hosts we prefer to zero-extend first, 62307cc68d5SRichard Henderson which allows ARG to stay live. */ 62407cc68d5SRichard Henderson switch (len) { 62507cc68d5SRichard Henderson case 16: 62607cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 62707cc68d5SRichard Henderson tcg_gen_ext16u_i32(ret, arg); 62807cc68d5SRichard Henderson tcg_gen_shli_i32(ret, ret, ofs); 62907cc68d5SRichard Henderson return; 63007cc68d5SRichard Henderson } 63107cc68d5SRichard Henderson break; 63207cc68d5SRichard Henderson case 8: 63307cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 63407cc68d5SRichard Henderson tcg_gen_ext8u_i32(ret, arg); 63507cc68d5SRichard Henderson tcg_gen_shli_i32(ret, ret, ofs); 63607cc68d5SRichard Henderson return; 63707cc68d5SRichard Henderson } 63807cc68d5SRichard Henderson break; 63907cc68d5SRichard Henderson } 64007cc68d5SRichard Henderson /* Otherwise prefer zero-extension over AND for code size. */ 64107cc68d5SRichard Henderson switch (ofs + len) { 64207cc68d5SRichard Henderson case 16: 64307cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 64407cc68d5SRichard Henderson tcg_gen_shli_i32(ret, arg, ofs); 64507cc68d5SRichard Henderson tcg_gen_ext16u_i32(ret, ret); 64607cc68d5SRichard Henderson return; 64707cc68d5SRichard Henderson } 64807cc68d5SRichard Henderson break; 64907cc68d5SRichard Henderson case 8: 65007cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 65107cc68d5SRichard Henderson tcg_gen_shli_i32(ret, arg, ofs); 65207cc68d5SRichard Henderson tcg_gen_ext8u_i32(ret, ret); 65307cc68d5SRichard Henderson return; 65407cc68d5SRichard Henderson } 65507cc68d5SRichard Henderson break; 65607cc68d5SRichard Henderson } 65707cc68d5SRichard Henderson tcg_gen_andi_i32(ret, arg, (1u << len) - 1); 65807cc68d5SRichard Henderson tcg_gen_shli_i32(ret, ret, ofs); 65907cc68d5SRichard Henderson } 66007cc68d5SRichard Henderson } 66107cc68d5SRichard Henderson 6627ec8bab3SRichard Henderson void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg, 6637ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 6647ec8bab3SRichard Henderson { 6657ec8bab3SRichard Henderson tcg_debug_assert(ofs < 32); 6667ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 6677ec8bab3SRichard Henderson tcg_debug_assert(len <= 32); 6687ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 32); 6697ec8bab3SRichard Henderson 6707ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if extract is supported. */ 6717ec8bab3SRichard Henderson if (ofs + len == 32) { 6727ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, 32 - len); 6737ec8bab3SRichard Henderson return; 6747ec8bab3SRichard Henderson } 6757ec8bab3SRichard Henderson if (ofs == 0) { 6767ec8bab3SRichard Henderson tcg_gen_andi_i32(ret, arg, (1u << len) - 1); 6777ec8bab3SRichard Henderson return; 6787ec8bab3SRichard Henderson } 6797ec8bab3SRichard Henderson 6807ec8bab3SRichard Henderson if (TCG_TARGET_HAS_extract_i32 6817ec8bab3SRichard Henderson && TCG_TARGET_extract_i32_valid(ofs, len)) { 6827ec8bab3SRichard Henderson tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, ofs, len); 6837ec8bab3SRichard Henderson return; 6847ec8bab3SRichard Henderson } 6857ec8bab3SRichard Henderson 6867ec8bab3SRichard Henderson /* Assume that zero-extension, if available, is cheaper than a shift. */ 6877ec8bab3SRichard Henderson switch (ofs + len) { 6887ec8bab3SRichard Henderson case 16: 6897ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 6907ec8bab3SRichard Henderson tcg_gen_ext16u_i32(ret, arg); 6917ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, ret, ofs); 6927ec8bab3SRichard Henderson return; 6937ec8bab3SRichard Henderson } 6947ec8bab3SRichard Henderson break; 6957ec8bab3SRichard Henderson case 8: 6967ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 6977ec8bab3SRichard Henderson tcg_gen_ext8u_i32(ret, arg); 6987ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, ret, ofs); 6997ec8bab3SRichard Henderson return; 7007ec8bab3SRichard Henderson } 7017ec8bab3SRichard Henderson break; 7027ec8bab3SRichard Henderson } 7037ec8bab3SRichard Henderson 7047ec8bab3SRichard Henderson /* ??? Ideally we'd know what values are available for immediate AND. 7057ec8bab3SRichard Henderson Assume that 8 bits are available, plus the special case of 16, 7067ec8bab3SRichard Henderson so that we get ext8u, ext16u. */ 7077ec8bab3SRichard Henderson switch (len) { 7087ec8bab3SRichard Henderson case 1 ... 8: case 16: 7097ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, ofs); 7107ec8bab3SRichard Henderson tcg_gen_andi_i32(ret, ret, (1u << len) - 1); 7117ec8bab3SRichard Henderson break; 7127ec8bab3SRichard Henderson default: 7137ec8bab3SRichard Henderson tcg_gen_shli_i32(ret, arg, 32 - len - ofs); 7147ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, ret, 32 - len); 7157ec8bab3SRichard Henderson break; 7167ec8bab3SRichard Henderson } 7177ec8bab3SRichard Henderson } 7187ec8bab3SRichard Henderson 7197ec8bab3SRichard Henderson void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg, 7207ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 7217ec8bab3SRichard Henderson { 7227ec8bab3SRichard Henderson tcg_debug_assert(ofs < 32); 7237ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 7247ec8bab3SRichard Henderson tcg_debug_assert(len <= 32); 7257ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 32); 7267ec8bab3SRichard Henderson 7277ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if extract is supported. */ 7287ec8bab3SRichard Henderson if (ofs + len == 32) { 7297ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, arg, 32 - len); 7307ec8bab3SRichard Henderson return; 7317ec8bab3SRichard Henderson } 7327ec8bab3SRichard Henderson if (ofs == 0) { 7337ec8bab3SRichard Henderson switch (len) { 7347ec8bab3SRichard Henderson case 16: 7357ec8bab3SRichard Henderson tcg_gen_ext16s_i32(ret, arg); 7367ec8bab3SRichard Henderson return; 7377ec8bab3SRichard Henderson case 8: 7387ec8bab3SRichard Henderson tcg_gen_ext8s_i32(ret, arg); 7397ec8bab3SRichard Henderson return; 7407ec8bab3SRichard Henderson } 7417ec8bab3SRichard Henderson } 7427ec8bab3SRichard Henderson 7437ec8bab3SRichard Henderson if (TCG_TARGET_HAS_sextract_i32 7447ec8bab3SRichard Henderson && TCG_TARGET_extract_i32_valid(ofs, len)) { 7457ec8bab3SRichard Henderson tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, ofs, len); 7467ec8bab3SRichard Henderson return; 7477ec8bab3SRichard Henderson } 7487ec8bab3SRichard Henderson 7497ec8bab3SRichard Henderson /* Assume that sign-extension, if available, is cheaper than a shift. */ 7507ec8bab3SRichard Henderson switch (ofs + len) { 7517ec8bab3SRichard Henderson case 16: 7527ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i32) { 7537ec8bab3SRichard Henderson tcg_gen_ext16s_i32(ret, arg); 7547ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, ret, ofs); 7557ec8bab3SRichard Henderson return; 7567ec8bab3SRichard Henderson } 7577ec8bab3SRichard Henderson break; 7587ec8bab3SRichard Henderson case 8: 7597ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i32) { 7607ec8bab3SRichard Henderson tcg_gen_ext8s_i32(ret, arg); 7617ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, ret, ofs); 7627ec8bab3SRichard Henderson return; 7637ec8bab3SRichard Henderson } 7647ec8bab3SRichard Henderson break; 7657ec8bab3SRichard Henderson } 7667ec8bab3SRichard Henderson switch (len) { 7677ec8bab3SRichard Henderson case 16: 7687ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i32) { 7697ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, ofs); 7707ec8bab3SRichard Henderson tcg_gen_ext16s_i32(ret, ret); 7717ec8bab3SRichard Henderson return; 7727ec8bab3SRichard Henderson } 7737ec8bab3SRichard Henderson break; 7747ec8bab3SRichard Henderson case 8: 7757ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i32) { 7767ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, ofs); 7777ec8bab3SRichard Henderson tcg_gen_ext8s_i32(ret, ret); 7787ec8bab3SRichard Henderson return; 7797ec8bab3SRichard Henderson } 7807ec8bab3SRichard Henderson break; 7817ec8bab3SRichard Henderson } 7827ec8bab3SRichard Henderson 7837ec8bab3SRichard Henderson tcg_gen_shli_i32(ret, arg, 32 - len - ofs); 7847ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, ret, 32 - len); 7857ec8bab3SRichard Henderson } 7867ec8bab3SRichard Henderson 7872089fcc9SDavid Hildenbrand /* 7882089fcc9SDavid Hildenbrand * Extract 32-bits from a 64-bit input, ah:al, starting from ofs. 7892089fcc9SDavid Hildenbrand * Unlike tcg_gen_extract_i32 above, len is fixed at 32. 7902089fcc9SDavid Hildenbrand */ 7912089fcc9SDavid Hildenbrand void tcg_gen_extract2_i32(TCGv_i32 ret, TCGv_i32 al, TCGv_i32 ah, 7922089fcc9SDavid Hildenbrand unsigned int ofs) 7932089fcc9SDavid Hildenbrand { 7942089fcc9SDavid Hildenbrand tcg_debug_assert(ofs <= 32); 7952089fcc9SDavid Hildenbrand if (ofs == 0) { 7962089fcc9SDavid Hildenbrand tcg_gen_mov_i32(ret, al); 7972089fcc9SDavid Hildenbrand } else if (ofs == 32) { 7982089fcc9SDavid Hildenbrand tcg_gen_mov_i32(ret, ah); 7992089fcc9SDavid Hildenbrand } else if (al == ah) { 8002089fcc9SDavid Hildenbrand tcg_gen_rotri_i32(ret, al, ofs); 801fce1296fSRichard Henderson } else if (TCG_TARGET_HAS_extract2_i32) { 802fce1296fSRichard Henderson tcg_gen_op4i_i32(INDEX_op_extract2_i32, ret, al, ah, ofs); 8032089fcc9SDavid Hildenbrand } else { 8042089fcc9SDavid Hildenbrand TCGv_i32 t0 = tcg_temp_new_i32(); 8052089fcc9SDavid Hildenbrand tcg_gen_shri_i32(t0, al, ofs); 8062089fcc9SDavid Hildenbrand tcg_gen_deposit_i32(ret, t0, ah, 32 - ofs, ofs); 8072089fcc9SDavid Hildenbrand tcg_temp_free_i32(t0); 8082089fcc9SDavid Hildenbrand } 8092089fcc9SDavid Hildenbrand } 8102089fcc9SDavid Hildenbrand 811951c6300SRichard Henderson void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1, 812951c6300SRichard Henderson TCGv_i32 c2, TCGv_i32 v1, TCGv_i32 v2) 813951c6300SRichard Henderson { 81437ed3bf1SRichard Henderson if (cond == TCG_COND_ALWAYS) { 81537ed3bf1SRichard Henderson tcg_gen_mov_i32(ret, v1); 81637ed3bf1SRichard Henderson } else if (cond == TCG_COND_NEVER) { 81737ed3bf1SRichard Henderson tcg_gen_mov_i32(ret, v2); 81837ed3bf1SRichard Henderson } else if (TCG_TARGET_HAS_movcond_i32) { 819951c6300SRichard Henderson tcg_gen_op6i_i32(INDEX_op_movcond_i32, ret, c1, c2, v1, v2, cond); 820951c6300SRichard Henderson } else { 821951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 822951c6300SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 823951c6300SRichard Henderson tcg_gen_setcond_i32(cond, t0, c1, c2); 824951c6300SRichard Henderson tcg_gen_neg_i32(t0, t0); 825951c6300SRichard Henderson tcg_gen_and_i32(t1, v1, t0); 826951c6300SRichard Henderson tcg_gen_andc_i32(ret, v2, t0); 827951c6300SRichard Henderson tcg_gen_or_i32(ret, ret, t1); 828951c6300SRichard Henderson tcg_temp_free_i32(t0); 829951c6300SRichard Henderson tcg_temp_free_i32(t1); 830951c6300SRichard Henderson } 831951c6300SRichard Henderson } 832951c6300SRichard Henderson 833951c6300SRichard Henderson void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, 834951c6300SRichard Henderson TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) 835951c6300SRichard Henderson { 836951c6300SRichard Henderson if (TCG_TARGET_HAS_add2_i32) { 837951c6300SRichard Henderson tcg_gen_op6_i32(INDEX_op_add2_i32, rl, rh, al, ah, bl, bh); 838951c6300SRichard Henderson } else { 839951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 840951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 841951c6300SRichard Henderson tcg_gen_concat_i32_i64(t0, al, ah); 842951c6300SRichard Henderson tcg_gen_concat_i32_i64(t1, bl, bh); 843951c6300SRichard Henderson tcg_gen_add_i64(t0, t0, t1); 844951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 845951c6300SRichard Henderson tcg_temp_free_i64(t0); 846951c6300SRichard Henderson tcg_temp_free_i64(t1); 847951c6300SRichard Henderson } 848951c6300SRichard Henderson } 849951c6300SRichard Henderson 850951c6300SRichard Henderson void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, 851951c6300SRichard Henderson TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) 852951c6300SRichard Henderson { 853951c6300SRichard Henderson if (TCG_TARGET_HAS_sub2_i32) { 854951c6300SRichard Henderson tcg_gen_op6_i32(INDEX_op_sub2_i32, rl, rh, al, ah, bl, bh); 855951c6300SRichard Henderson } else { 856951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 857951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 858951c6300SRichard Henderson tcg_gen_concat_i32_i64(t0, al, ah); 859951c6300SRichard Henderson tcg_gen_concat_i32_i64(t1, bl, bh); 860951c6300SRichard Henderson tcg_gen_sub_i64(t0, t0, t1); 861951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 862951c6300SRichard Henderson tcg_temp_free_i64(t0); 863951c6300SRichard Henderson tcg_temp_free_i64(t1); 864951c6300SRichard Henderson } 865951c6300SRichard Henderson } 866951c6300SRichard Henderson 867951c6300SRichard Henderson void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) 868951c6300SRichard Henderson { 869951c6300SRichard Henderson if (TCG_TARGET_HAS_mulu2_i32) { 870951c6300SRichard Henderson tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2); 871951c6300SRichard Henderson } else if (TCG_TARGET_HAS_muluh_i32) { 872951c6300SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 873951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2); 874951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_muluh_i32, rh, arg1, arg2); 875951c6300SRichard Henderson tcg_gen_mov_i32(rl, t); 876951c6300SRichard Henderson tcg_temp_free_i32(t); 8779fd86b51SRichard Henderson } else if (TCG_TARGET_REG_BITS == 64) { 878951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 879951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 880951c6300SRichard Henderson tcg_gen_extu_i32_i64(t0, arg1); 881951c6300SRichard Henderson tcg_gen_extu_i32_i64(t1, arg2); 882951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, t1); 883951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 884951c6300SRichard Henderson tcg_temp_free_i64(t0); 885951c6300SRichard Henderson tcg_temp_free_i64(t1); 8869fd86b51SRichard Henderson } else { 8879fd86b51SRichard Henderson qemu_build_not_reached(); 888951c6300SRichard Henderson } 889951c6300SRichard Henderson } 890951c6300SRichard Henderson 891951c6300SRichard Henderson void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) 892951c6300SRichard Henderson { 893951c6300SRichard Henderson if (TCG_TARGET_HAS_muls2_i32) { 894951c6300SRichard Henderson tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2); 895951c6300SRichard Henderson } else if (TCG_TARGET_HAS_mulsh_i32) { 896951c6300SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 897951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2); 898951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_mulsh_i32, rh, arg1, arg2); 899951c6300SRichard Henderson tcg_gen_mov_i32(rl, t); 900951c6300SRichard Henderson tcg_temp_free_i32(t); 901951c6300SRichard Henderson } else if (TCG_TARGET_REG_BITS == 32) { 902951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 903951c6300SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 904951c6300SRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 905951c6300SRichard Henderson TCGv_i32 t3 = tcg_temp_new_i32(); 906951c6300SRichard Henderson tcg_gen_mulu2_i32(t0, t1, arg1, arg2); 907951c6300SRichard Henderson /* Adjust for negative inputs. */ 908951c6300SRichard Henderson tcg_gen_sari_i32(t2, arg1, 31); 909951c6300SRichard Henderson tcg_gen_sari_i32(t3, arg2, 31); 910951c6300SRichard Henderson tcg_gen_and_i32(t2, t2, arg2); 911951c6300SRichard Henderson tcg_gen_and_i32(t3, t3, arg1); 912951c6300SRichard Henderson tcg_gen_sub_i32(rh, t1, t2); 913951c6300SRichard Henderson tcg_gen_sub_i32(rh, rh, t3); 914951c6300SRichard Henderson tcg_gen_mov_i32(rl, t0); 915951c6300SRichard Henderson tcg_temp_free_i32(t0); 916951c6300SRichard Henderson tcg_temp_free_i32(t1); 917951c6300SRichard Henderson tcg_temp_free_i32(t2); 918951c6300SRichard Henderson tcg_temp_free_i32(t3); 919951c6300SRichard Henderson } else { 920951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 921951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 922951c6300SRichard Henderson tcg_gen_ext_i32_i64(t0, arg1); 923951c6300SRichard Henderson tcg_gen_ext_i32_i64(t1, arg2); 924951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, t1); 925951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 926951c6300SRichard Henderson tcg_temp_free_i64(t0); 927951c6300SRichard Henderson tcg_temp_free_i64(t1); 928951c6300SRichard Henderson } 929951c6300SRichard Henderson } 930951c6300SRichard Henderson 9315087abfbSRichard Henderson void tcg_gen_mulsu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) 9325087abfbSRichard Henderson { 9335087abfbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 9345087abfbSRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 9355087abfbSRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 9365087abfbSRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 9375087abfbSRichard Henderson tcg_gen_mulu2_i32(t0, t1, arg1, arg2); 9385087abfbSRichard Henderson /* Adjust for negative input for the signed arg1. */ 9395087abfbSRichard Henderson tcg_gen_sari_i32(t2, arg1, 31); 9405087abfbSRichard Henderson tcg_gen_and_i32(t2, t2, arg2); 9415087abfbSRichard Henderson tcg_gen_sub_i32(rh, t1, t2); 9425087abfbSRichard Henderson tcg_gen_mov_i32(rl, t0); 9435087abfbSRichard Henderson tcg_temp_free_i32(t0); 9445087abfbSRichard Henderson tcg_temp_free_i32(t1); 9455087abfbSRichard Henderson tcg_temp_free_i32(t2); 9465087abfbSRichard Henderson } else { 9475087abfbSRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 9485087abfbSRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 9495087abfbSRichard Henderson tcg_gen_ext_i32_i64(t0, arg1); 9505087abfbSRichard Henderson tcg_gen_extu_i32_i64(t1, arg2); 9515087abfbSRichard Henderson tcg_gen_mul_i64(t0, t0, t1); 9525087abfbSRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 9535087abfbSRichard Henderson tcg_temp_free_i64(t0); 9545087abfbSRichard Henderson tcg_temp_free_i64(t1); 9555087abfbSRichard Henderson } 9565087abfbSRichard Henderson } 9575087abfbSRichard Henderson 958951c6300SRichard Henderson void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg) 959951c6300SRichard Henderson { 960951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8s_i32) { 961951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg); 962951c6300SRichard Henderson } else { 963951c6300SRichard Henderson tcg_gen_shli_i32(ret, arg, 24); 964951c6300SRichard Henderson tcg_gen_sari_i32(ret, ret, 24); 965951c6300SRichard Henderson } 966951c6300SRichard Henderson } 967951c6300SRichard Henderson 968951c6300SRichard Henderson void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg) 969951c6300SRichard Henderson { 970951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16s_i32) { 971951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg); 972951c6300SRichard Henderson } else { 973951c6300SRichard Henderson tcg_gen_shli_i32(ret, arg, 16); 974951c6300SRichard Henderson tcg_gen_sari_i32(ret, ret, 16); 975951c6300SRichard Henderson } 976951c6300SRichard Henderson } 977951c6300SRichard Henderson 978951c6300SRichard Henderson void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg) 979951c6300SRichard Henderson { 980951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 981951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg); 982951c6300SRichard Henderson } else { 983951c6300SRichard Henderson tcg_gen_andi_i32(ret, arg, 0xffu); 984951c6300SRichard Henderson } 985951c6300SRichard Henderson } 986951c6300SRichard Henderson 987951c6300SRichard Henderson void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg) 988951c6300SRichard Henderson { 989951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 990951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg); 991951c6300SRichard Henderson } else { 992951c6300SRichard Henderson tcg_gen_andi_i32(ret, arg, 0xffffu); 993951c6300SRichard Henderson } 994951c6300SRichard Henderson } 995951c6300SRichard Henderson 9962b836c2aSRichard Henderson void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags) 997951c6300SRichard Henderson { 9982b836c2aSRichard Henderson /* Only one extension flag may be present. */ 9992b836c2aSRichard Henderson tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); 10002b836c2aSRichard Henderson 1001951c6300SRichard Henderson if (TCG_TARGET_HAS_bswap16_i32) { 10022b836c2aSRichard Henderson tcg_gen_op3i_i32(INDEX_op_bswap16_i32, ret, arg, flags); 1003951c6300SRichard Henderson } else { 1004951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 10052b836c2aSRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 1006951c6300SRichard Henderson 10072b836c2aSRichard Henderson tcg_gen_shri_i32(t0, arg, 8); 10082b836c2aSRichard Henderson if (!(flags & TCG_BSWAP_IZ)) { 10092b836c2aSRichard Henderson tcg_gen_ext8u_i32(t0, t0); 10102b836c2aSRichard Henderson } 10112b836c2aSRichard Henderson 10122b836c2aSRichard Henderson if (flags & TCG_BSWAP_OS) { 10132b836c2aSRichard Henderson tcg_gen_shli_i32(t1, arg, 24); 10142b836c2aSRichard Henderson tcg_gen_sari_i32(t1, t1, 16); 10152b836c2aSRichard Henderson } else if (flags & TCG_BSWAP_OZ) { 10162b836c2aSRichard Henderson tcg_gen_ext8u_i32(t1, arg); 10172b836c2aSRichard Henderson tcg_gen_shli_i32(t1, t1, 8); 10182b836c2aSRichard Henderson } else { 10192b836c2aSRichard Henderson tcg_gen_shli_i32(t1, arg, 8); 10202b836c2aSRichard Henderson } 10212b836c2aSRichard Henderson 10222b836c2aSRichard Henderson tcg_gen_or_i32(ret, t0, t1); 1023951c6300SRichard Henderson tcg_temp_free_i32(t0); 10242b836c2aSRichard Henderson tcg_temp_free_i32(t1); 1025951c6300SRichard Henderson } 1026951c6300SRichard Henderson } 1027951c6300SRichard Henderson 1028951c6300SRichard Henderson void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) 1029951c6300SRichard Henderson { 1030951c6300SRichard Henderson if (TCG_TARGET_HAS_bswap32_i32) { 1031587195bdSRichard Henderson tcg_gen_op3i_i32(INDEX_op_bswap32_i32, ret, arg, 0); 1032951c6300SRichard Henderson } else { 1033a686dc71SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 1034a686dc71SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 103511d11d61SRichard Henderson TCGv_i32 t2 = tcg_constant_i32(0x00ff00ff); 1036951c6300SRichard Henderson 1037a686dc71SRichard Henderson /* arg = abcd */ 1038a686dc71SRichard Henderson tcg_gen_shri_i32(t0, arg, 8); /* t0 = .abc */ 1039a686dc71SRichard Henderson tcg_gen_and_i32(t1, arg, t2); /* t1 = .b.d */ 1040a686dc71SRichard Henderson tcg_gen_and_i32(t0, t0, t2); /* t0 = .a.c */ 1041a686dc71SRichard Henderson tcg_gen_shli_i32(t1, t1, 8); /* t1 = b.d. */ 1042a686dc71SRichard Henderson tcg_gen_or_i32(ret, t0, t1); /* ret = badc */ 1043951c6300SRichard Henderson 1044a686dc71SRichard Henderson tcg_gen_shri_i32(t0, ret, 16); /* t0 = ..ba */ 1045a686dc71SRichard Henderson tcg_gen_shli_i32(t1, ret, 16); /* t1 = dc.. */ 1046a686dc71SRichard Henderson tcg_gen_or_i32(ret, t0, t1); /* ret = dcba */ 1047951c6300SRichard Henderson 1048951c6300SRichard Henderson tcg_temp_free_i32(t0); 1049951c6300SRichard Henderson tcg_temp_free_i32(t1); 1050951c6300SRichard Henderson } 1051951c6300SRichard Henderson } 1052951c6300SRichard Henderson 105346be8425SRichard Henderson void tcg_gen_hswap_i32(TCGv_i32 ret, TCGv_i32 arg) 105446be8425SRichard Henderson { 105546be8425SRichard Henderson /* Swapping 2 16-bit elements is a rotate. */ 105646be8425SRichard Henderson tcg_gen_rotli_i32(ret, arg, 16); 105746be8425SRichard Henderson } 105846be8425SRichard Henderson 1059b87fb8cdSRichard Henderson void tcg_gen_smin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1060b87fb8cdSRichard Henderson { 1061b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, a, b); 1062b87fb8cdSRichard Henderson } 1063b87fb8cdSRichard Henderson 1064b87fb8cdSRichard Henderson void tcg_gen_umin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1065b87fb8cdSRichard Henderson { 1066b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, a, b); 1067b87fb8cdSRichard Henderson } 1068b87fb8cdSRichard Henderson 1069b87fb8cdSRichard Henderson void tcg_gen_smax_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1070b87fb8cdSRichard Henderson { 1071b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, b, a); 1072b87fb8cdSRichard Henderson } 1073b87fb8cdSRichard Henderson 1074b87fb8cdSRichard Henderson void tcg_gen_umax_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1075b87fb8cdSRichard Henderson { 1076b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, b, a); 1077b87fb8cdSRichard Henderson } 1078b87fb8cdSRichard Henderson 1079ff1f11f7SRichard Henderson void tcg_gen_abs_i32(TCGv_i32 ret, TCGv_i32 a) 1080ff1f11f7SRichard Henderson { 1081ff1f11f7SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 1082ff1f11f7SRichard Henderson 1083ff1f11f7SRichard Henderson tcg_gen_sari_i32(t, a, 31); 1084ff1f11f7SRichard Henderson tcg_gen_xor_i32(ret, a, t); 1085ff1f11f7SRichard Henderson tcg_gen_sub_i32(ret, ret, t); 1086ff1f11f7SRichard Henderson tcg_temp_free_i32(t); 1087ff1f11f7SRichard Henderson } 1088ff1f11f7SRichard Henderson 1089951c6300SRichard Henderson /* 64-bit ops */ 1090951c6300SRichard Henderson 1091951c6300SRichard Henderson #if TCG_TARGET_REG_BITS == 32 1092951c6300SRichard Henderson /* These are all inline for TCG_TARGET_REG_BITS == 64. */ 1093951c6300SRichard Henderson 1094951c6300SRichard Henderson void tcg_gen_discard_i64(TCGv_i64 arg) 1095951c6300SRichard Henderson { 1096951c6300SRichard Henderson tcg_gen_discard_i32(TCGV_LOW(arg)); 1097951c6300SRichard Henderson tcg_gen_discard_i32(TCGV_HIGH(arg)); 1098951c6300SRichard Henderson } 1099951c6300SRichard Henderson 1100951c6300SRichard Henderson void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg) 1101951c6300SRichard Henderson { 110211d11d61SRichard Henderson TCGTemp *ts = tcgv_i64_temp(arg); 110311d11d61SRichard Henderson 110411d11d61SRichard Henderson /* Canonicalize TCGv_i64 TEMP_CONST into TCGv_i32 TEMP_CONST. */ 110511d11d61SRichard Henderson if (ts->kind == TEMP_CONST) { 110611d11d61SRichard Henderson tcg_gen_movi_i64(ret, ts->val); 110711d11d61SRichard Henderson } else { 1108951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1109951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); 1110951c6300SRichard Henderson } 111111d11d61SRichard Henderson } 1112951c6300SRichard Henderson 1113951c6300SRichard Henderson void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg) 1114951c6300SRichard Henderson { 1115951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_LOW(ret), arg); 1116951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32); 1117951c6300SRichard Henderson } 1118951c6300SRichard Henderson 1119951c6300SRichard Henderson void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1120951c6300SRichard Henderson { 1121951c6300SRichard Henderson tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset); 1122951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1123951c6300SRichard Henderson } 1124951c6300SRichard Henderson 1125951c6300SRichard Henderson void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1126951c6300SRichard Henderson { 1127951c6300SRichard Henderson tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset); 11283ff91d7eSJoseph Myers tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 1129951c6300SRichard Henderson } 1130951c6300SRichard Henderson 1131951c6300SRichard Henderson void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1132951c6300SRichard Henderson { 1133951c6300SRichard Henderson tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset); 1134951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1135951c6300SRichard Henderson } 1136951c6300SRichard Henderson 1137951c6300SRichard Henderson void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1138951c6300SRichard Henderson { 1139951c6300SRichard Henderson tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset); 1140951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 1141951c6300SRichard Henderson } 1142951c6300SRichard Henderson 1143951c6300SRichard Henderson void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1144951c6300SRichard Henderson { 1145951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); 1146951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1147951c6300SRichard Henderson } 1148951c6300SRichard Henderson 1149951c6300SRichard Henderson void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1150951c6300SRichard Henderson { 1151951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); 1152951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 1153951c6300SRichard Henderson } 1154951c6300SRichard Henderson 1155951c6300SRichard Henderson void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1156951c6300SRichard Henderson { 1157951c6300SRichard Henderson /* Since arg2 and ret have different types, 1158951c6300SRichard Henderson they cannot be the same temporary */ 1159e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 1160951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset); 1161951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4); 1162951c6300SRichard Henderson #else 1163951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); 1164951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4); 1165951c6300SRichard Henderson #endif 1166951c6300SRichard Henderson } 1167951c6300SRichard Henderson 1168d56fea79SRichard Henderson void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) 1169d56fea79SRichard Henderson { 1170d56fea79SRichard Henderson tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset); 1171d56fea79SRichard Henderson } 1172d56fea79SRichard Henderson 1173d56fea79SRichard Henderson void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) 1174d56fea79SRichard Henderson { 1175d56fea79SRichard Henderson tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset); 1176d56fea79SRichard Henderson } 1177d56fea79SRichard Henderson 1178d56fea79SRichard Henderson void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) 1179d56fea79SRichard Henderson { 1180d56fea79SRichard Henderson tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); 1181d56fea79SRichard Henderson } 1182d56fea79SRichard Henderson 1183951c6300SRichard Henderson void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) 1184951c6300SRichard Henderson { 1185e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 1186951c6300SRichard Henderson tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset); 1187951c6300SRichard Henderson tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4); 1188951c6300SRichard Henderson #else 1189951c6300SRichard Henderson tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); 1190951c6300SRichard Henderson tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4); 1191951c6300SRichard Henderson #endif 1192951c6300SRichard Henderson } 1193951c6300SRichard Henderson 1194d56fea79SRichard Henderson void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1195d56fea79SRichard Henderson { 1196d56fea79SRichard Henderson tcg_gen_add2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), 1197d56fea79SRichard Henderson TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); 1198d56fea79SRichard Henderson } 1199d56fea79SRichard Henderson 1200d56fea79SRichard Henderson void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1201d56fea79SRichard Henderson { 1202d56fea79SRichard Henderson tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), 1203d56fea79SRichard Henderson TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); 1204d56fea79SRichard Henderson } 1205d56fea79SRichard Henderson 1206951c6300SRichard Henderson void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1207951c6300SRichard Henderson { 1208951c6300SRichard Henderson tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 1209951c6300SRichard Henderson tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 1210951c6300SRichard Henderson } 1211951c6300SRichard Henderson 1212951c6300SRichard Henderson void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1213951c6300SRichard Henderson { 1214951c6300SRichard Henderson tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 1215951c6300SRichard Henderson tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 1216951c6300SRichard Henderson } 1217951c6300SRichard Henderson 1218951c6300SRichard Henderson void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1219951c6300SRichard Henderson { 1220951c6300SRichard Henderson tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 1221951c6300SRichard Henderson tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 1222951c6300SRichard Henderson } 1223951c6300SRichard Henderson 1224951c6300SRichard Henderson void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1225951c6300SRichard Henderson { 1226951c6300SRichard Henderson gen_helper_shl_i64(ret, arg1, arg2); 1227951c6300SRichard Henderson } 1228951c6300SRichard Henderson 1229951c6300SRichard Henderson void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1230951c6300SRichard Henderson { 1231951c6300SRichard Henderson gen_helper_shr_i64(ret, arg1, arg2); 1232951c6300SRichard Henderson } 1233951c6300SRichard Henderson 1234951c6300SRichard Henderson void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1235951c6300SRichard Henderson { 1236951c6300SRichard Henderson gen_helper_sar_i64(ret, arg1, arg2); 1237951c6300SRichard Henderson } 1238951c6300SRichard Henderson 1239951c6300SRichard Henderson void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1240951c6300SRichard Henderson { 1241951c6300SRichard Henderson TCGv_i64 t0; 1242951c6300SRichard Henderson TCGv_i32 t1; 1243951c6300SRichard Henderson 1244951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 1245951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 1246951c6300SRichard Henderson 1247951c6300SRichard Henderson tcg_gen_mulu2_i32(TCGV_LOW(t0), TCGV_HIGH(t0), 1248951c6300SRichard Henderson TCGV_LOW(arg1), TCGV_LOW(arg2)); 1249951c6300SRichard Henderson 1250951c6300SRichard Henderson tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2)); 1251951c6300SRichard Henderson tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); 1252951c6300SRichard Henderson tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), TCGV_LOW(arg2)); 1253951c6300SRichard Henderson tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); 1254951c6300SRichard Henderson 1255951c6300SRichard Henderson tcg_gen_mov_i64(ret, t0); 1256951c6300SRichard Henderson tcg_temp_free_i64(t0); 1257951c6300SRichard Henderson tcg_temp_free_i32(t1); 1258951c6300SRichard Henderson } 125911d11d61SRichard Henderson 126011d11d61SRichard Henderson #else 126111d11d61SRichard Henderson 126211d11d61SRichard Henderson void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg) 126311d11d61SRichard Henderson { 126411d11d61SRichard Henderson tcg_gen_mov_i64(ret, tcg_constant_i64(arg)); 126511d11d61SRichard Henderson } 126611d11d61SRichard Henderson 1267951c6300SRichard Henderson #endif /* TCG_TARGET_REG_SIZE == 32 */ 1268951c6300SRichard Henderson 1269951c6300SRichard Henderson void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1270951c6300SRichard Henderson { 1271951c6300SRichard Henderson /* some cases can be optimized here */ 1272951c6300SRichard Henderson if (arg2 == 0) { 1273951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 127411d11d61SRichard Henderson } else if (TCG_TARGET_REG_BITS == 64) { 127511d11d61SRichard Henderson tcg_gen_add_i64(ret, arg1, tcg_constant_i64(arg2)); 1276951c6300SRichard Henderson } else { 127711d11d61SRichard Henderson tcg_gen_add2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), 127811d11d61SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 127911d11d61SRichard Henderson tcg_constant_i32(arg2), tcg_constant_i32(arg2 >> 32)); 1280951c6300SRichard Henderson } 1281951c6300SRichard Henderson } 1282951c6300SRichard Henderson 1283951c6300SRichard Henderson void tcg_gen_subfi_i64(TCGv_i64 ret, int64_t arg1, TCGv_i64 arg2) 1284951c6300SRichard Henderson { 1285951c6300SRichard Henderson if (arg1 == 0 && TCG_TARGET_HAS_neg_i64) { 1286951c6300SRichard Henderson /* Don't recurse with tcg_gen_neg_i64. */ 1287951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg2); 128811d11d61SRichard Henderson } else if (TCG_TARGET_REG_BITS == 64) { 128911d11d61SRichard Henderson tcg_gen_sub_i64(ret, tcg_constant_i64(arg1), arg2); 1290951c6300SRichard Henderson } else { 129111d11d61SRichard Henderson tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), 129211d11d61SRichard Henderson tcg_constant_i32(arg1), tcg_constant_i32(arg1 >> 32), 129311d11d61SRichard Henderson TCGV_LOW(arg2), TCGV_HIGH(arg2)); 1294951c6300SRichard Henderson } 1295951c6300SRichard Henderson } 1296951c6300SRichard Henderson 1297951c6300SRichard Henderson void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1298951c6300SRichard Henderson { 1299951c6300SRichard Henderson /* some cases can be optimized here */ 1300951c6300SRichard Henderson if (arg2 == 0) { 1301951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 130211d11d61SRichard Henderson } else if (TCG_TARGET_REG_BITS == 64) { 130311d11d61SRichard Henderson tcg_gen_sub_i64(ret, arg1, tcg_constant_i64(arg2)); 1304951c6300SRichard Henderson } else { 130511d11d61SRichard Henderson tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), 130611d11d61SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 130711d11d61SRichard Henderson tcg_constant_i32(arg2), tcg_constant_i32(arg2 >> 32)); 1308951c6300SRichard Henderson } 1309951c6300SRichard Henderson } 1310951c6300SRichard Henderson 1311474b2e8fSRichard Henderson void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1312951c6300SRichard Henderson { 13133a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1314951c6300SRichard Henderson tcg_gen_andi_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); 1315951c6300SRichard Henderson tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); 13163a13c3f3SRichard Henderson return; 13173a13c3f3SRichard Henderson } 13183a13c3f3SRichard Henderson 1319951c6300SRichard Henderson /* Some cases can be optimized here. */ 1320951c6300SRichard Henderson switch (arg2) { 1321951c6300SRichard Henderson case 0: 1322951c6300SRichard Henderson tcg_gen_movi_i64(ret, 0); 1323951c6300SRichard Henderson return; 1324474b2e8fSRichard Henderson case -1: 1325951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1326951c6300SRichard Henderson return; 1327474b2e8fSRichard Henderson case 0xff: 1328951c6300SRichard Henderson /* Don't recurse with tcg_gen_ext8u_i64. */ 1329951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 1330951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg1); 1331951c6300SRichard Henderson return; 1332951c6300SRichard Henderson } 1333951c6300SRichard Henderson break; 1334474b2e8fSRichard Henderson case 0xffff: 1335951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 1336951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg1); 1337951c6300SRichard Henderson return; 1338951c6300SRichard Henderson } 1339951c6300SRichard Henderson break; 1340474b2e8fSRichard Henderson case 0xffffffffu: 1341951c6300SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 1342951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg1); 1343951c6300SRichard Henderson return; 1344951c6300SRichard Henderson } 1345951c6300SRichard Henderson break; 1346951c6300SRichard Henderson } 134711d11d61SRichard Henderson 134811d11d61SRichard Henderson tcg_gen_and_i64(ret, arg1, tcg_constant_i64(arg2)); 1349951c6300SRichard Henderson } 1350951c6300SRichard Henderson 1351951c6300SRichard Henderson void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1352951c6300SRichard Henderson { 13533a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1354951c6300SRichard Henderson tcg_gen_ori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); 1355951c6300SRichard Henderson tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); 13563a13c3f3SRichard Henderson return; 13573a13c3f3SRichard Henderson } 1358951c6300SRichard Henderson /* Some cases can be optimized here. */ 1359951c6300SRichard Henderson if (arg2 == -1) { 1360951c6300SRichard Henderson tcg_gen_movi_i64(ret, -1); 1361951c6300SRichard Henderson } else if (arg2 == 0) { 1362951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1363951c6300SRichard Henderson } else { 136411d11d61SRichard Henderson tcg_gen_or_i64(ret, arg1, tcg_constant_i64(arg2)); 1365951c6300SRichard Henderson } 1366951c6300SRichard Henderson } 1367951c6300SRichard Henderson 1368951c6300SRichard Henderson void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1369951c6300SRichard Henderson { 13703a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1371951c6300SRichard Henderson tcg_gen_xori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); 1372951c6300SRichard Henderson tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); 13733a13c3f3SRichard Henderson return; 13743a13c3f3SRichard Henderson } 1375951c6300SRichard Henderson /* Some cases can be optimized here. */ 1376951c6300SRichard Henderson if (arg2 == 0) { 1377951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1378951c6300SRichard Henderson } else if (arg2 == -1 && TCG_TARGET_HAS_not_i64) { 1379951c6300SRichard Henderson /* Don't recurse with tcg_gen_not_i64. */ 1380951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg1); 1381951c6300SRichard Henderson } else { 138211d11d61SRichard Henderson tcg_gen_xor_i64(ret, arg1, tcg_constant_i64(arg2)); 1383951c6300SRichard Henderson } 1384951c6300SRichard Henderson } 1385951c6300SRichard Henderson 1386951c6300SRichard Henderson static inline void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, 1387951c6300SRichard Henderson unsigned c, bool right, bool arith) 1388951c6300SRichard Henderson { 1389951c6300SRichard Henderson tcg_debug_assert(c < 64); 1390951c6300SRichard Henderson if (c == 0) { 1391951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); 1392951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 1393951c6300SRichard Henderson } else if (c >= 32) { 1394951c6300SRichard Henderson c -= 32; 1395951c6300SRichard Henderson if (right) { 1396951c6300SRichard Henderson if (arith) { 1397951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); 1398951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); 1399951c6300SRichard Henderson } else { 1400951c6300SRichard Henderson tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); 1401951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1402951c6300SRichard Henderson } 1403951c6300SRichard Henderson } else { 1404951c6300SRichard Henderson tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c); 1405951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_LOW(ret), 0); 1406951c6300SRichard Henderson } 140702616badSRichard Henderson } else if (right) { 140802616badSRichard Henderson if (TCG_TARGET_HAS_extract2_i32) { 140902616badSRichard Henderson tcg_gen_extract2_i32(TCGV_LOW(ret), 141002616badSRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), c); 1411951c6300SRichard Henderson } else { 1412951c6300SRichard Henderson tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); 141302616badSRichard Henderson tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(ret), 141402616badSRichard Henderson TCGV_HIGH(arg1), 32 - c, c); 1415951c6300SRichard Henderson } 141602616badSRichard Henderson if (arith) { 141702616badSRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); 141802616badSRichard Henderson } else { 141902616badSRichard Henderson tcg_gen_shri_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); 142002616badSRichard Henderson } 142102616badSRichard Henderson } else { 142202616badSRichard Henderson if (TCG_TARGET_HAS_extract2_i32) { 142302616badSRichard Henderson tcg_gen_extract2_i32(TCGV_HIGH(ret), 142402616badSRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 32 - c); 142502616badSRichard Henderson } else { 142602616badSRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 142702616badSRichard Henderson tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c); 142802616badSRichard Henderson tcg_gen_deposit_i32(TCGV_HIGH(ret), t0, 142902616badSRichard Henderson TCGV_HIGH(arg1), c, 32 - c); 1430951c6300SRichard Henderson tcg_temp_free_i32(t0); 143102616badSRichard Henderson } 143202616badSRichard Henderson tcg_gen_shli_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); 1433951c6300SRichard Henderson } 1434951c6300SRichard Henderson } 1435951c6300SRichard Henderson 1436474b2e8fSRichard Henderson void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1437951c6300SRichard Henderson { 1438474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 14393a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 14403a13c3f3SRichard Henderson tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0); 14413a13c3f3SRichard Henderson } else if (arg2 == 0) { 1442951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1443951c6300SRichard Henderson } else { 144411d11d61SRichard Henderson tcg_gen_shl_i64(ret, arg1, tcg_constant_i64(arg2)); 1445951c6300SRichard Henderson } 1446951c6300SRichard Henderson } 1447951c6300SRichard Henderson 1448474b2e8fSRichard Henderson void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1449951c6300SRichard Henderson { 1450474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 14513a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 14523a13c3f3SRichard Henderson tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0); 14533a13c3f3SRichard Henderson } else if (arg2 == 0) { 1454951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1455951c6300SRichard Henderson } else { 145611d11d61SRichard Henderson tcg_gen_shr_i64(ret, arg1, tcg_constant_i64(arg2)); 1457951c6300SRichard Henderson } 1458951c6300SRichard Henderson } 1459951c6300SRichard Henderson 1460474b2e8fSRichard Henderson void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1461951c6300SRichard Henderson { 1462474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 14633a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 14643a13c3f3SRichard Henderson tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1); 14653a13c3f3SRichard Henderson } else if (arg2 == 0) { 1466951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1467951c6300SRichard Henderson } else { 146811d11d61SRichard Henderson tcg_gen_sar_i64(ret, arg1, tcg_constant_i64(arg2)); 1469951c6300SRichard Henderson } 1470951c6300SRichard Henderson } 1471951c6300SRichard Henderson 147242a268c2SRichard Henderson void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, TCGLabel *l) 1473951c6300SRichard Henderson { 1474951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 147542a268c2SRichard Henderson tcg_gen_br(l); 1476951c6300SRichard Henderson } else if (cond != TCG_COND_NEVER) { 1477d88a117eSRichard Henderson l->refs++; 14783a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1479951c6300SRichard Henderson tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, TCGV_LOW(arg1), 1480951c6300SRichard Henderson TCGV_HIGH(arg1), TCGV_LOW(arg2), 148142a268c2SRichard Henderson TCGV_HIGH(arg2), cond, label_arg(l)); 14823a13c3f3SRichard Henderson } else { 148342a268c2SRichard Henderson tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, 148442a268c2SRichard Henderson label_arg(l)); 14853a13c3f3SRichard Henderson } 1486951c6300SRichard Henderson } 1487951c6300SRichard Henderson } 1488951c6300SRichard Henderson 148942a268c2SRichard Henderson void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1, int64_t arg2, TCGLabel *l) 1490951c6300SRichard Henderson { 149111d11d61SRichard Henderson if (TCG_TARGET_REG_BITS == 64) { 149211d11d61SRichard Henderson tcg_gen_brcond_i64(cond, arg1, tcg_constant_i64(arg2), l); 149311d11d61SRichard Henderson } else if (cond == TCG_COND_ALWAYS) { 149442a268c2SRichard Henderson tcg_gen_br(l); 1495951c6300SRichard Henderson } else if (cond != TCG_COND_NEVER) { 149611d11d61SRichard Henderson l->refs++; 149711d11d61SRichard Henderson tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, 149811d11d61SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 149911d11d61SRichard Henderson tcg_constant_i32(arg2), 150011d11d61SRichard Henderson tcg_constant_i32(arg2 >> 32), 150111d11d61SRichard Henderson cond, label_arg(l)); 1502951c6300SRichard Henderson } 1503951c6300SRichard Henderson } 1504951c6300SRichard Henderson 1505951c6300SRichard Henderson void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret, 1506951c6300SRichard Henderson TCGv_i64 arg1, TCGv_i64 arg2) 1507951c6300SRichard Henderson { 1508951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 1509951c6300SRichard Henderson tcg_gen_movi_i64(ret, 1); 1510951c6300SRichard Henderson } else if (cond == TCG_COND_NEVER) { 1511951c6300SRichard Henderson tcg_gen_movi_i64(ret, 0); 1512951c6300SRichard Henderson } else { 15133a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1514951c6300SRichard Henderson tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), 1515951c6300SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 1516951c6300SRichard Henderson TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); 1517951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 15183a13c3f3SRichard Henderson } else { 1519951c6300SRichard Henderson tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond); 15203a13c3f3SRichard Henderson } 1521951c6300SRichard Henderson } 1522951c6300SRichard Henderson } 1523951c6300SRichard Henderson 1524951c6300SRichard Henderson void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret, 1525951c6300SRichard Henderson TCGv_i64 arg1, int64_t arg2) 1526951c6300SRichard Henderson { 152711d11d61SRichard Henderson if (TCG_TARGET_REG_BITS == 64) { 152811d11d61SRichard Henderson tcg_gen_setcond_i64(cond, ret, arg1, tcg_constant_i64(arg2)); 152911d11d61SRichard Henderson } else if (cond == TCG_COND_ALWAYS) { 153011d11d61SRichard Henderson tcg_gen_movi_i64(ret, 1); 153111d11d61SRichard Henderson } else if (cond == TCG_COND_NEVER) { 153211d11d61SRichard Henderson tcg_gen_movi_i64(ret, 0); 153311d11d61SRichard Henderson } else { 153411d11d61SRichard Henderson tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), 153511d11d61SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 153611d11d61SRichard Henderson tcg_constant_i32(arg2), 153711d11d61SRichard Henderson tcg_constant_i32(arg2 >> 32), cond); 153811d11d61SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 153911d11d61SRichard Henderson } 1540951c6300SRichard Henderson } 1541951c6300SRichard Henderson 1542951c6300SRichard Henderson void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1543951c6300SRichard Henderson { 1544b2e3ae94SRichard Henderson if (arg2 == 0) { 1545b2e3ae94SRichard Henderson tcg_gen_movi_i64(ret, 0); 1546b2e3ae94SRichard Henderson } else if (is_power_of_2(arg2)) { 1547b2e3ae94SRichard Henderson tcg_gen_shli_i64(ret, arg1, ctz64(arg2)); 1548b2e3ae94SRichard Henderson } else { 1549951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1550951c6300SRichard Henderson tcg_gen_mul_i64(ret, arg1, t0); 1551951c6300SRichard Henderson tcg_temp_free_i64(t0); 1552951c6300SRichard Henderson } 1553b2e3ae94SRichard Henderson } 1554951c6300SRichard Henderson 1555951c6300SRichard Henderson void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1556951c6300SRichard Henderson { 1557951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i64) { 1558951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2); 1559951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1560951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1561951c6300SRichard Henderson tcg_gen_sari_i64(t0, arg1, 63); 1562951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2); 1563951c6300SRichard Henderson tcg_temp_free_i64(t0); 1564951c6300SRichard Henderson } else { 1565951c6300SRichard Henderson gen_helper_div_i64(ret, arg1, arg2); 1566951c6300SRichard Henderson } 1567951c6300SRichard Henderson } 1568951c6300SRichard Henderson 1569951c6300SRichard Henderson void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1570951c6300SRichard Henderson { 1571951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i64) { 1572951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2); 1573951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i64) { 1574951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1575951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_div_i64, t0, arg1, arg2); 1576951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, arg2); 1577951c6300SRichard Henderson tcg_gen_sub_i64(ret, arg1, t0); 1578951c6300SRichard Henderson tcg_temp_free_i64(t0); 1579951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1580951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1581951c6300SRichard Henderson tcg_gen_sari_i64(t0, arg1, 63); 1582951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2); 1583951c6300SRichard Henderson tcg_temp_free_i64(t0); 1584951c6300SRichard Henderson } else { 1585951c6300SRichard Henderson gen_helper_rem_i64(ret, arg1, arg2); 1586951c6300SRichard Henderson } 1587951c6300SRichard Henderson } 1588951c6300SRichard Henderson 1589951c6300SRichard Henderson void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1590951c6300SRichard Henderson { 1591951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i64) { 1592951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2); 1593951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1594951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1595951c6300SRichard Henderson tcg_gen_movi_i64(t0, 0); 1596951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2); 1597951c6300SRichard Henderson tcg_temp_free_i64(t0); 1598951c6300SRichard Henderson } else { 1599951c6300SRichard Henderson gen_helper_divu_i64(ret, arg1, arg2); 1600951c6300SRichard Henderson } 1601951c6300SRichard Henderson } 1602951c6300SRichard Henderson 1603951c6300SRichard Henderson void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1604951c6300SRichard Henderson { 1605951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i64) { 1606951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2); 1607951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i64) { 1608951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1609951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_divu_i64, t0, arg1, arg2); 1610951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, arg2); 1611951c6300SRichard Henderson tcg_gen_sub_i64(ret, arg1, t0); 1612951c6300SRichard Henderson tcg_temp_free_i64(t0); 1613951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1614951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1615951c6300SRichard Henderson tcg_gen_movi_i64(t0, 0); 1616951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2); 1617951c6300SRichard Henderson tcg_temp_free_i64(t0); 1618951c6300SRichard Henderson } else { 1619951c6300SRichard Henderson gen_helper_remu_i64(ret, arg1, arg2); 1620951c6300SRichard Henderson } 1621951c6300SRichard Henderson } 1622951c6300SRichard Henderson 1623951c6300SRichard Henderson void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg) 1624951c6300SRichard Henderson { 16253a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1626951c6300SRichard Henderson tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1627951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 16283a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext8s_i64) { 1629951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg); 1630951c6300SRichard Henderson } else { 1631951c6300SRichard Henderson tcg_gen_shli_i64(ret, arg, 56); 1632951c6300SRichard Henderson tcg_gen_sari_i64(ret, ret, 56); 1633951c6300SRichard Henderson } 1634951c6300SRichard Henderson } 1635951c6300SRichard Henderson 1636951c6300SRichard Henderson void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg) 1637951c6300SRichard Henderson { 16383a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1639951c6300SRichard Henderson tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1640951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 16413a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext16s_i64) { 1642951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg); 1643951c6300SRichard Henderson } else { 1644951c6300SRichard Henderson tcg_gen_shli_i64(ret, arg, 48); 1645951c6300SRichard Henderson tcg_gen_sari_i64(ret, ret, 48); 1646951c6300SRichard Henderson } 1647951c6300SRichard Henderson } 1648951c6300SRichard Henderson 1649951c6300SRichard Henderson void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg) 1650951c6300SRichard Henderson { 16513a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1652951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1653951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 16543a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext32s_i64) { 1655951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg); 1656951c6300SRichard Henderson } else { 1657951c6300SRichard Henderson tcg_gen_shli_i64(ret, arg, 32); 1658951c6300SRichard Henderson tcg_gen_sari_i64(ret, ret, 32); 1659951c6300SRichard Henderson } 1660951c6300SRichard Henderson } 1661951c6300SRichard Henderson 1662951c6300SRichard Henderson void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg) 1663951c6300SRichard Henderson { 16643a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1665951c6300SRichard Henderson tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1666951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16673a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext8u_i64) { 1668951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg); 1669951c6300SRichard Henderson } else { 1670951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg, 0xffu); 1671951c6300SRichard Henderson } 1672951c6300SRichard Henderson } 1673951c6300SRichard Henderson 1674951c6300SRichard Henderson void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg) 1675951c6300SRichard Henderson { 16763a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1677951c6300SRichard Henderson tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1678951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16793a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext16u_i64) { 1680951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg); 1681951c6300SRichard Henderson } else { 1682951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg, 0xffffu); 1683951c6300SRichard Henderson } 1684951c6300SRichard Henderson } 1685951c6300SRichard Henderson 1686951c6300SRichard Henderson void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg) 1687951c6300SRichard Henderson { 16883a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1689951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1690951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16913a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext32u_i64) { 1692951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg); 1693951c6300SRichard Henderson } else { 1694951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg, 0xffffffffu); 1695951c6300SRichard Henderson } 1696951c6300SRichard Henderson } 1697951c6300SRichard Henderson 16982b836c2aSRichard Henderson void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) 1699951c6300SRichard Henderson { 17002b836c2aSRichard Henderson /* Only one extension flag may be present. */ 17012b836c2aSRichard Henderson tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); 17022b836c2aSRichard Henderson 17033a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 17042b836c2aSRichard Henderson tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg), flags); 17052b836c2aSRichard Henderson if (flags & TCG_BSWAP_OS) { 17062b836c2aSRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 17072b836c2aSRichard Henderson } else { 1708951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 17092b836c2aSRichard Henderson } 17103a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_bswap16_i64) { 17112b836c2aSRichard Henderson tcg_gen_op3i_i64(INDEX_op_bswap16_i64, ret, arg, flags); 1712951c6300SRichard Henderson } else { 1713951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 17142b836c2aSRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 1715951c6300SRichard Henderson 17162b836c2aSRichard Henderson tcg_gen_shri_i64(t0, arg, 8); 17172b836c2aSRichard Henderson if (!(flags & TCG_BSWAP_IZ)) { 17182b836c2aSRichard Henderson tcg_gen_ext8u_i64(t0, t0); 17192b836c2aSRichard Henderson } 17202b836c2aSRichard Henderson 17212b836c2aSRichard Henderson if (flags & TCG_BSWAP_OS) { 17222b836c2aSRichard Henderson tcg_gen_shli_i64(t1, arg, 56); 17232b836c2aSRichard Henderson tcg_gen_sari_i64(t1, t1, 48); 17242b836c2aSRichard Henderson } else if (flags & TCG_BSWAP_OZ) { 17252b836c2aSRichard Henderson tcg_gen_ext8u_i64(t1, arg); 17262b836c2aSRichard Henderson tcg_gen_shli_i64(t1, t1, 8); 17272b836c2aSRichard Henderson } else { 17282b836c2aSRichard Henderson tcg_gen_shli_i64(t1, arg, 8); 17292b836c2aSRichard Henderson } 17302b836c2aSRichard Henderson 17312b836c2aSRichard Henderson tcg_gen_or_i64(ret, t0, t1); 1732951c6300SRichard Henderson tcg_temp_free_i64(t0); 17332b836c2aSRichard Henderson tcg_temp_free_i64(t1); 1734951c6300SRichard Henderson } 1735951c6300SRichard Henderson } 1736951c6300SRichard Henderson 17372b836c2aSRichard Henderson void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) 1738951c6300SRichard Henderson { 17392b836c2aSRichard Henderson /* Only one extension flag may be present. */ 17402b836c2aSRichard Henderson tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); 17412b836c2aSRichard Henderson 17423a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1743951c6300SRichard Henderson tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 17442b836c2aSRichard Henderson if (flags & TCG_BSWAP_OS) { 17452b836c2aSRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 17462b836c2aSRichard Henderson } else { 1747951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 17482b836c2aSRichard Henderson } 17493a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_bswap32_i64) { 17502b836c2aSRichard Henderson tcg_gen_op3i_i64(INDEX_op_bswap32_i64, ret, arg, flags); 1751951c6300SRichard Henderson } else { 1752a686dc71SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1753a686dc71SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 175411d11d61SRichard Henderson TCGv_i64 t2 = tcg_constant_i64(0x00ff00ff); 1755951c6300SRichard Henderson 17562b836c2aSRichard Henderson /* arg = xxxxabcd */ 17572b836c2aSRichard Henderson tcg_gen_shri_i64(t0, arg, 8); /* t0 = .xxxxabc */ 1758a686dc71SRichard Henderson tcg_gen_and_i64(t1, arg, t2); /* t1 = .....b.d */ 1759a686dc71SRichard Henderson tcg_gen_and_i64(t0, t0, t2); /* t0 = .....a.c */ 1760a686dc71SRichard Henderson tcg_gen_shli_i64(t1, t1, 8); /* t1 = ....b.d. */ 1761a686dc71SRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = ....badc */ 1762951c6300SRichard Henderson 1763a686dc71SRichard Henderson tcg_gen_shli_i64(t1, ret, 48); /* t1 = dc...... */ 1764a686dc71SRichard Henderson tcg_gen_shri_i64(t0, ret, 16); /* t0 = ......ba */ 17652b836c2aSRichard Henderson if (flags & TCG_BSWAP_OS) { 17662b836c2aSRichard Henderson tcg_gen_sari_i64(t1, t1, 32); /* t1 = ssssdc.. */ 17672b836c2aSRichard Henderson } else { 1768a686dc71SRichard Henderson tcg_gen_shri_i64(t1, t1, 32); /* t1 = ....dc.. */ 17692b836c2aSRichard Henderson } 17702b836c2aSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = ssssdcba */ 1771951c6300SRichard Henderson 1772951c6300SRichard Henderson tcg_temp_free_i64(t0); 1773951c6300SRichard Henderson tcg_temp_free_i64(t1); 1774951c6300SRichard Henderson } 1775951c6300SRichard Henderson } 1776951c6300SRichard Henderson 1777951c6300SRichard Henderson void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) 1778951c6300SRichard Henderson { 17793a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1780951c6300SRichard Henderson TCGv_i32 t0, t1; 1781951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 1782951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 1783951c6300SRichard Henderson 1784951c6300SRichard Henderson tcg_gen_bswap32_i32(t0, TCGV_LOW(arg)); 1785951c6300SRichard Henderson tcg_gen_bswap32_i32(t1, TCGV_HIGH(arg)); 1786951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), t1); 1787951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), t0); 1788951c6300SRichard Henderson tcg_temp_free_i32(t0); 1789951c6300SRichard Henderson tcg_temp_free_i32(t1); 17903a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_bswap64_i64) { 1791587195bdSRichard Henderson tcg_gen_op3i_i64(INDEX_op_bswap64_i64, ret, arg, 0); 1792951c6300SRichard Henderson } else { 1793951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1794951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 17959e821eabSRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 1796951c6300SRichard Henderson 17979e821eabSRichard Henderson /* arg = abcdefgh */ 17989e821eabSRichard Henderson tcg_gen_movi_i64(t2, 0x00ff00ff00ff00ffull); 17999e821eabSRichard Henderson tcg_gen_shri_i64(t0, arg, 8); /* t0 = .abcdefg */ 18009e821eabSRichard Henderson tcg_gen_and_i64(t1, arg, t2); /* t1 = .b.d.f.h */ 18019e821eabSRichard Henderson tcg_gen_and_i64(t0, t0, t2); /* t0 = .a.c.e.g */ 18029e821eabSRichard Henderson tcg_gen_shli_i64(t1, t1, 8); /* t1 = b.d.f.h. */ 18039e821eabSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = badcfehg */ 1804951c6300SRichard Henderson 18059e821eabSRichard Henderson tcg_gen_movi_i64(t2, 0x0000ffff0000ffffull); 18069e821eabSRichard Henderson tcg_gen_shri_i64(t0, ret, 16); /* t0 = ..badcfe */ 18079e821eabSRichard Henderson tcg_gen_and_i64(t1, ret, t2); /* t1 = ..dc..hg */ 18089e821eabSRichard Henderson tcg_gen_and_i64(t0, t0, t2); /* t0 = ..ba..fe */ 18099e821eabSRichard Henderson tcg_gen_shli_i64(t1, t1, 16); /* t1 = dc..hg.. */ 18109e821eabSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = dcbahgfe */ 1811951c6300SRichard Henderson 18129e821eabSRichard Henderson tcg_gen_shri_i64(t0, ret, 32); /* t0 = ....dcba */ 18139e821eabSRichard Henderson tcg_gen_shli_i64(t1, ret, 32); /* t1 = hgfe.... */ 18149e821eabSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = hgfedcba */ 1815951c6300SRichard Henderson 1816951c6300SRichard Henderson tcg_temp_free_i64(t0); 1817951c6300SRichard Henderson tcg_temp_free_i64(t1); 18189e821eabSRichard Henderson tcg_temp_free_i64(t2); 1819951c6300SRichard Henderson } 1820951c6300SRichard Henderson } 1821951c6300SRichard Henderson 182246be8425SRichard Henderson void tcg_gen_hswap_i64(TCGv_i64 ret, TCGv_i64 arg) 182346be8425SRichard Henderson { 182446be8425SRichard Henderson uint64_t m = 0x0000ffff0000ffffull; 182546be8425SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 182646be8425SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 182746be8425SRichard Henderson 182846be8425SRichard Henderson /* See include/qemu/bitops.h, hswap64. */ 182946be8425SRichard Henderson tcg_gen_rotli_i64(t1, arg, 32); 183046be8425SRichard Henderson tcg_gen_andi_i64(t0, t1, m); 183146be8425SRichard Henderson tcg_gen_shli_i64(t0, t0, 16); 183246be8425SRichard Henderson tcg_gen_shri_i64(t1, t1, 16); 183346be8425SRichard Henderson tcg_gen_andi_i64(t1, t1, m); 183446be8425SRichard Henderson tcg_gen_or_i64(ret, t0, t1); 183546be8425SRichard Henderson 183646be8425SRichard Henderson tcg_temp_free_i64(t0); 183746be8425SRichard Henderson tcg_temp_free_i64(t1); 183846be8425SRichard Henderson } 183946be8425SRichard Henderson 184046be8425SRichard Henderson void tcg_gen_wswap_i64(TCGv_i64 ret, TCGv_i64 arg) 184146be8425SRichard Henderson { 184246be8425SRichard Henderson /* Swapping 2 32-bit elements is a rotate. */ 184346be8425SRichard Henderson tcg_gen_rotli_i64(ret, arg, 32); 184446be8425SRichard Henderson } 184546be8425SRichard Henderson 1846951c6300SRichard Henderson void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) 1847951c6300SRichard Henderson { 18483a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18493a13c3f3SRichard Henderson tcg_gen_not_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 18503a13c3f3SRichard Henderson tcg_gen_not_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); 18513a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_not_i64) { 1852951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg); 1853951c6300SRichard Henderson } else { 1854951c6300SRichard Henderson tcg_gen_xori_i64(ret, arg, -1); 1855951c6300SRichard Henderson } 1856951c6300SRichard Henderson } 1857951c6300SRichard Henderson 1858951c6300SRichard Henderson void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1859951c6300SRichard Henderson { 18603a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18613a13c3f3SRichard Henderson tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18623a13c3f3SRichard Henderson tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18633a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_andc_i64) { 1864951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2); 1865951c6300SRichard Henderson } else { 1866951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1867951c6300SRichard Henderson tcg_gen_not_i64(t0, arg2); 1868951c6300SRichard Henderson tcg_gen_and_i64(ret, arg1, t0); 1869951c6300SRichard Henderson tcg_temp_free_i64(t0); 1870951c6300SRichard Henderson } 1871951c6300SRichard Henderson } 1872951c6300SRichard Henderson 1873951c6300SRichard Henderson void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1874951c6300SRichard Henderson { 18753a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18763a13c3f3SRichard Henderson tcg_gen_eqv_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18773a13c3f3SRichard Henderson tcg_gen_eqv_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18783a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_eqv_i64) { 1879951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2); 1880951c6300SRichard Henderson } else { 1881951c6300SRichard Henderson tcg_gen_xor_i64(ret, arg1, arg2); 1882951c6300SRichard Henderson tcg_gen_not_i64(ret, ret); 1883951c6300SRichard Henderson } 1884951c6300SRichard Henderson } 1885951c6300SRichard Henderson 1886951c6300SRichard Henderson void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1887951c6300SRichard Henderson { 18883a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18893a13c3f3SRichard Henderson tcg_gen_nand_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18903a13c3f3SRichard Henderson tcg_gen_nand_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18913a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_nand_i64) { 1892951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2); 1893951c6300SRichard Henderson } else { 1894951c6300SRichard Henderson tcg_gen_and_i64(ret, arg1, arg2); 1895951c6300SRichard Henderson tcg_gen_not_i64(ret, ret); 1896951c6300SRichard Henderson } 1897951c6300SRichard Henderson } 1898951c6300SRichard Henderson 1899951c6300SRichard Henderson void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1900951c6300SRichard Henderson { 19013a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 19023a13c3f3SRichard Henderson tcg_gen_nor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 19033a13c3f3SRichard Henderson tcg_gen_nor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 19043a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_nor_i64) { 1905951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2); 1906951c6300SRichard Henderson } else { 1907951c6300SRichard Henderson tcg_gen_or_i64(ret, arg1, arg2); 1908951c6300SRichard Henderson tcg_gen_not_i64(ret, ret); 1909951c6300SRichard Henderson } 1910951c6300SRichard Henderson } 1911951c6300SRichard Henderson 1912951c6300SRichard Henderson void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1913951c6300SRichard Henderson { 19143a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 19153a13c3f3SRichard Henderson tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 19163a13c3f3SRichard Henderson tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 19173a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_orc_i64) { 1918951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2); 1919951c6300SRichard Henderson } else { 1920951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1921951c6300SRichard Henderson tcg_gen_not_i64(t0, arg2); 1922951c6300SRichard Henderson tcg_gen_or_i64(ret, arg1, t0); 1923951c6300SRichard Henderson tcg_temp_free_i64(t0); 1924951c6300SRichard Henderson } 1925951c6300SRichard Henderson } 1926951c6300SRichard Henderson 19270e28d006SRichard Henderson void tcg_gen_clz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 19280e28d006SRichard Henderson { 19290e28d006SRichard Henderson if (TCG_TARGET_HAS_clz_i64) { 19300e28d006SRichard Henderson tcg_gen_op3_i64(INDEX_op_clz_i64, ret, arg1, arg2); 19310e28d006SRichard Henderson } else { 19320e28d006SRichard Henderson gen_helper_clz_i64(ret, arg1, arg2); 19330e28d006SRichard Henderson } 19340e28d006SRichard Henderson } 19350e28d006SRichard Henderson 19360e28d006SRichard Henderson void tcg_gen_clzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) 19370e28d006SRichard Henderson { 19380e28d006SRichard Henderson if (TCG_TARGET_REG_BITS == 32 19390e28d006SRichard Henderson && TCG_TARGET_HAS_clz_i32 19400e28d006SRichard Henderson && arg2 <= 0xffffffffu) { 194111d11d61SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 194211d11d61SRichard Henderson tcg_gen_clzi_i32(t, TCGV_LOW(arg1), arg2 - 32); 19430e28d006SRichard Henderson tcg_gen_addi_i32(t, t, 32); 19440e28d006SRichard Henderson tcg_gen_clz_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), t); 19450e28d006SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 19460e28d006SRichard Henderson tcg_temp_free_i32(t); 19470e28d006SRichard Henderson } else { 194811d11d61SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 194911d11d61SRichard Henderson tcg_gen_clz_i64(ret, arg1, t0); 195011d11d61SRichard Henderson tcg_temp_free_i64(t0); 19510e28d006SRichard Henderson } 19520e28d006SRichard Henderson } 19530e28d006SRichard Henderson 19540e28d006SRichard Henderson void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 19550e28d006SRichard Henderson { 19560e28d006SRichard Henderson if (TCG_TARGET_HAS_ctz_i64) { 19570e28d006SRichard Henderson tcg_gen_op3_i64(INDEX_op_ctz_i64, ret, arg1, arg2); 195814e99210SRichard Henderson } else if (TCG_TARGET_HAS_ctpop_i64 || TCG_TARGET_HAS_clz_i64) { 195914e99210SRichard Henderson TCGv_i64 z, t = tcg_temp_new_i64(); 196014e99210SRichard Henderson 196114e99210SRichard Henderson if (TCG_TARGET_HAS_ctpop_i64) { 196214e99210SRichard Henderson tcg_gen_subi_i64(t, arg1, 1); 196314e99210SRichard Henderson tcg_gen_andc_i64(t, t, arg1); 196414e99210SRichard Henderson tcg_gen_ctpop_i64(t, t); 196514e99210SRichard Henderson } else { 196614e99210SRichard Henderson /* Since all non-x86 hosts have clz(0) == 64, don't fight it. */ 196714e99210SRichard Henderson tcg_gen_neg_i64(t, arg1); 196814e99210SRichard Henderson tcg_gen_and_i64(t, t, arg1); 196914e99210SRichard Henderson tcg_gen_clzi_i64(t, t, 64); 197014e99210SRichard Henderson tcg_gen_xori_i64(t, t, 63); 197114e99210SRichard Henderson } 197211d11d61SRichard Henderson z = tcg_constant_i64(0); 197314e99210SRichard Henderson tcg_gen_movcond_i64(TCG_COND_EQ, ret, arg1, z, arg2, t); 197414e99210SRichard Henderson tcg_temp_free_i64(t); 197514e99210SRichard Henderson tcg_temp_free_i64(z); 19760e28d006SRichard Henderson } else { 19770e28d006SRichard Henderson gen_helper_ctz_i64(ret, arg1, arg2); 19780e28d006SRichard Henderson } 19790e28d006SRichard Henderson } 19800e28d006SRichard Henderson 19810e28d006SRichard Henderson void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) 19820e28d006SRichard Henderson { 19830e28d006SRichard Henderson if (TCG_TARGET_REG_BITS == 32 19840e28d006SRichard Henderson && TCG_TARGET_HAS_ctz_i32 19850e28d006SRichard Henderson && arg2 <= 0xffffffffu) { 198611d11d61SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 198711d11d61SRichard Henderson tcg_gen_ctzi_i32(t32, TCGV_HIGH(arg1), arg2 - 32); 19880e28d006SRichard Henderson tcg_gen_addi_i32(t32, t32, 32); 19890e28d006SRichard Henderson tcg_gen_ctz_i32(TCGV_LOW(ret), TCGV_LOW(arg1), t32); 19900e28d006SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 19910e28d006SRichard Henderson tcg_temp_free_i32(t32); 199214e99210SRichard Henderson } else if (!TCG_TARGET_HAS_ctz_i64 199314e99210SRichard Henderson && TCG_TARGET_HAS_ctpop_i64 199414e99210SRichard Henderson && arg2 == 64) { 199514e99210SRichard Henderson /* This equivalence has the advantage of not requiring a fixup. */ 199614e99210SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 199714e99210SRichard Henderson tcg_gen_subi_i64(t, arg1, 1); 199814e99210SRichard Henderson tcg_gen_andc_i64(t, t, arg1); 199914e99210SRichard Henderson tcg_gen_ctpop_i64(ret, t); 200014e99210SRichard Henderson tcg_temp_free_i64(t); 20010e28d006SRichard Henderson } else { 200211d11d61SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 200311d11d61SRichard Henderson tcg_gen_ctz_i64(ret, arg1, t0); 200411d11d61SRichard Henderson tcg_temp_free_i64(t0); 20050e28d006SRichard Henderson } 20060e28d006SRichard Henderson } 20070e28d006SRichard Henderson 2008086920c2SRichard Henderson void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg) 2009086920c2SRichard Henderson { 2010086920c2SRichard Henderson if (TCG_TARGET_HAS_clz_i64 || TCG_TARGET_HAS_clz_i32) { 2011086920c2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2012086920c2SRichard Henderson tcg_gen_sari_i64(t, arg, 63); 2013086920c2SRichard Henderson tcg_gen_xor_i64(t, t, arg); 2014086920c2SRichard Henderson tcg_gen_clzi_i64(t, t, 64); 2015086920c2SRichard Henderson tcg_gen_subi_i64(ret, t, 1); 2016086920c2SRichard Henderson tcg_temp_free_i64(t); 2017086920c2SRichard Henderson } else { 2018086920c2SRichard Henderson gen_helper_clrsb_i64(ret, arg); 2019086920c2SRichard Henderson } 2020086920c2SRichard Henderson } 2021086920c2SRichard Henderson 2022a768e4e9SRichard Henderson void tcg_gen_ctpop_i64(TCGv_i64 ret, TCGv_i64 arg1) 2023a768e4e9SRichard Henderson { 2024a768e4e9SRichard Henderson if (TCG_TARGET_HAS_ctpop_i64) { 2025a768e4e9SRichard Henderson tcg_gen_op2_i64(INDEX_op_ctpop_i64, ret, arg1); 2026a768e4e9SRichard Henderson } else if (TCG_TARGET_REG_BITS == 32 && TCG_TARGET_HAS_ctpop_i32) { 2027a768e4e9SRichard Henderson tcg_gen_ctpop_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 2028a768e4e9SRichard Henderson tcg_gen_ctpop_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); 2029a768e4e9SRichard Henderson tcg_gen_add_i32(TCGV_LOW(ret), TCGV_LOW(ret), TCGV_HIGH(ret)); 2030a768e4e9SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 2031a768e4e9SRichard Henderson } else { 2032a768e4e9SRichard Henderson gen_helper_ctpop_i64(ret, arg1); 2033a768e4e9SRichard Henderson } 2034a768e4e9SRichard Henderson } 2035a768e4e9SRichard Henderson 2036951c6300SRichard Henderson void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 2037951c6300SRichard Henderson { 2038951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i64) { 2039951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2); 2040951c6300SRichard Henderson } else { 2041951c6300SRichard Henderson TCGv_i64 t0, t1; 2042951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 2043951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 2044951c6300SRichard Henderson tcg_gen_shl_i64(t0, arg1, arg2); 2045951c6300SRichard Henderson tcg_gen_subfi_i64(t1, 64, arg2); 2046951c6300SRichard Henderson tcg_gen_shr_i64(t1, arg1, t1); 2047951c6300SRichard Henderson tcg_gen_or_i64(ret, t0, t1); 2048951c6300SRichard Henderson tcg_temp_free_i64(t0); 2049951c6300SRichard Henderson tcg_temp_free_i64(t1); 2050951c6300SRichard Henderson } 2051951c6300SRichard Henderson } 2052951c6300SRichard Henderson 205307dada03SRichard Henderson void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 2054951c6300SRichard Henderson { 205507dada03SRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 2056951c6300SRichard Henderson /* some cases can be optimized here */ 2057951c6300SRichard Henderson if (arg2 == 0) { 2058951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 2059951c6300SRichard Henderson } else if (TCG_TARGET_HAS_rot_i64) { 206011d11d61SRichard Henderson tcg_gen_rotl_i64(ret, arg1, tcg_constant_i64(arg2)); 2061951c6300SRichard Henderson } else { 2062951c6300SRichard Henderson TCGv_i64 t0, t1; 2063951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 2064951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 2065951c6300SRichard Henderson tcg_gen_shli_i64(t0, arg1, arg2); 2066951c6300SRichard Henderson tcg_gen_shri_i64(t1, arg1, 64 - arg2); 2067951c6300SRichard Henderson tcg_gen_or_i64(ret, t0, t1); 2068951c6300SRichard Henderson tcg_temp_free_i64(t0); 2069951c6300SRichard Henderson tcg_temp_free_i64(t1); 2070951c6300SRichard Henderson } 2071951c6300SRichard Henderson } 2072951c6300SRichard Henderson 2073951c6300SRichard Henderson void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 2074951c6300SRichard Henderson { 2075951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i64) { 2076951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2); 2077951c6300SRichard Henderson } else { 2078951c6300SRichard Henderson TCGv_i64 t0, t1; 2079951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 2080951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 2081951c6300SRichard Henderson tcg_gen_shr_i64(t0, arg1, arg2); 2082951c6300SRichard Henderson tcg_gen_subfi_i64(t1, 64, arg2); 2083951c6300SRichard Henderson tcg_gen_shl_i64(t1, arg1, t1); 2084951c6300SRichard Henderson tcg_gen_or_i64(ret, t0, t1); 2085951c6300SRichard Henderson tcg_temp_free_i64(t0); 2086951c6300SRichard Henderson tcg_temp_free_i64(t1); 2087951c6300SRichard Henderson } 2088951c6300SRichard Henderson } 2089951c6300SRichard Henderson 209007dada03SRichard Henderson void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 2091951c6300SRichard Henderson { 209207dada03SRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 2093951c6300SRichard Henderson /* some cases can be optimized here */ 2094951c6300SRichard Henderson if (arg2 == 0) { 2095951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 2096951c6300SRichard Henderson } else { 2097951c6300SRichard Henderson tcg_gen_rotli_i64(ret, arg1, 64 - arg2); 2098951c6300SRichard Henderson } 2099951c6300SRichard Henderson } 2100951c6300SRichard Henderson 2101951c6300SRichard Henderson void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2, 2102951c6300SRichard Henderson unsigned int ofs, unsigned int len) 2103951c6300SRichard Henderson { 2104951c6300SRichard Henderson uint64_t mask; 2105951c6300SRichard Henderson TCGv_i64 t1; 2106951c6300SRichard Henderson 2107951c6300SRichard Henderson tcg_debug_assert(ofs < 64); 21080d0d309dSRichard Henderson tcg_debug_assert(len > 0); 2109951c6300SRichard Henderson tcg_debug_assert(len <= 64); 2110951c6300SRichard Henderson tcg_debug_assert(ofs + len <= 64); 2111951c6300SRichard Henderson 21120d0d309dSRichard Henderson if (len == 64) { 2113951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg2); 2114951c6300SRichard Henderson return; 2115951c6300SRichard Henderson } 2116951c6300SRichard Henderson if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(ofs, len)) { 2117951c6300SRichard Henderson tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len); 2118951c6300SRichard Henderson return; 2119951c6300SRichard Henderson } 2120951c6300SRichard Henderson 21213a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2122951c6300SRichard Henderson if (ofs >= 32) { 2123951c6300SRichard Henderson tcg_gen_deposit_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 2124951c6300SRichard Henderson TCGV_LOW(arg2), ofs - 32, len); 2125951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); 2126951c6300SRichard Henderson return; 2127951c6300SRichard Henderson } 2128951c6300SRichard Henderson if (ofs + len <= 32) { 2129951c6300SRichard Henderson tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(arg1), 2130951c6300SRichard Henderson TCGV_LOW(arg2), ofs, len); 2131951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 2132951c6300SRichard Henderson return; 2133951c6300SRichard Henderson } 21343a13c3f3SRichard Henderson } 2135951c6300SRichard Henderson 2136951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 2137951c6300SRichard Henderson 2138b0a60567SRichard Henderson if (TCG_TARGET_HAS_extract2_i64) { 2139b0a60567SRichard Henderson if (ofs + len == 64) { 2140b0a60567SRichard Henderson tcg_gen_shli_i64(t1, arg1, len); 2141b0a60567SRichard Henderson tcg_gen_extract2_i64(ret, t1, arg2, len); 2142b0a60567SRichard Henderson goto done; 2143b0a60567SRichard Henderson } 2144b0a60567SRichard Henderson if (ofs == 0) { 2145b0a60567SRichard Henderson tcg_gen_extract2_i64(ret, arg1, arg2, len); 2146b0a60567SRichard Henderson tcg_gen_rotli_i64(ret, ret, len); 2147b0a60567SRichard Henderson goto done; 2148b0a60567SRichard Henderson } 2149b0a60567SRichard Henderson } 2150b0a60567SRichard Henderson 2151b0a60567SRichard Henderson mask = (1ull << len) - 1; 2152951c6300SRichard Henderson if (ofs + len < 64) { 2153951c6300SRichard Henderson tcg_gen_andi_i64(t1, arg2, mask); 2154951c6300SRichard Henderson tcg_gen_shli_i64(t1, t1, ofs); 2155951c6300SRichard Henderson } else { 2156951c6300SRichard Henderson tcg_gen_shli_i64(t1, arg2, ofs); 2157951c6300SRichard Henderson } 2158951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg1, ~(mask << ofs)); 2159951c6300SRichard Henderson tcg_gen_or_i64(ret, ret, t1); 2160b0a60567SRichard Henderson done: 2161951c6300SRichard Henderson tcg_temp_free_i64(t1); 2162951c6300SRichard Henderson } 2163951c6300SRichard Henderson 216407cc68d5SRichard Henderson void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg, 216507cc68d5SRichard Henderson unsigned int ofs, unsigned int len) 216607cc68d5SRichard Henderson { 216707cc68d5SRichard Henderson tcg_debug_assert(ofs < 64); 216807cc68d5SRichard Henderson tcg_debug_assert(len > 0); 216907cc68d5SRichard Henderson tcg_debug_assert(len <= 64); 217007cc68d5SRichard Henderson tcg_debug_assert(ofs + len <= 64); 217107cc68d5SRichard Henderson 217207cc68d5SRichard Henderson if (ofs + len == 64) { 217307cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 217407cc68d5SRichard Henderson } else if (ofs == 0) { 217507cc68d5SRichard Henderson tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); 217607cc68d5SRichard Henderson } else if (TCG_TARGET_HAS_deposit_i64 217707cc68d5SRichard Henderson && TCG_TARGET_deposit_i64_valid(ofs, len)) { 217811d11d61SRichard Henderson TCGv_i64 zero = tcg_constant_i64(0); 217907cc68d5SRichard Henderson tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, zero, arg, ofs, len); 218007cc68d5SRichard Henderson } else { 218107cc68d5SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 218207cc68d5SRichard Henderson if (ofs >= 32) { 218307cc68d5SRichard Henderson tcg_gen_deposit_z_i32(TCGV_HIGH(ret), TCGV_LOW(arg), 218407cc68d5SRichard Henderson ofs - 32, len); 218507cc68d5SRichard Henderson tcg_gen_movi_i32(TCGV_LOW(ret), 0); 218607cc68d5SRichard Henderson return; 218707cc68d5SRichard Henderson } 218807cc68d5SRichard Henderson if (ofs + len <= 32) { 218907cc68d5SRichard Henderson tcg_gen_deposit_z_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len); 219007cc68d5SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 219107cc68d5SRichard Henderson return; 219207cc68d5SRichard Henderson } 219307cc68d5SRichard Henderson } 219407cc68d5SRichard Henderson /* To help two-operand hosts we prefer to zero-extend first, 219507cc68d5SRichard Henderson which allows ARG to stay live. */ 219607cc68d5SRichard Henderson switch (len) { 219707cc68d5SRichard Henderson case 32: 219807cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 219907cc68d5SRichard Henderson tcg_gen_ext32u_i64(ret, arg); 220007cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 220107cc68d5SRichard Henderson return; 220207cc68d5SRichard Henderson } 220307cc68d5SRichard Henderson break; 220407cc68d5SRichard Henderson case 16: 220507cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 220607cc68d5SRichard Henderson tcg_gen_ext16u_i64(ret, arg); 220707cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 220807cc68d5SRichard Henderson return; 220907cc68d5SRichard Henderson } 221007cc68d5SRichard Henderson break; 221107cc68d5SRichard Henderson case 8: 221207cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 221307cc68d5SRichard Henderson tcg_gen_ext8u_i64(ret, arg); 221407cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 221507cc68d5SRichard Henderson return; 221607cc68d5SRichard Henderson } 221707cc68d5SRichard Henderson break; 221807cc68d5SRichard Henderson } 221907cc68d5SRichard Henderson /* Otherwise prefer zero-extension over AND for code size. */ 222007cc68d5SRichard Henderson switch (ofs + len) { 222107cc68d5SRichard Henderson case 32: 222207cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 222307cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 222407cc68d5SRichard Henderson tcg_gen_ext32u_i64(ret, ret); 222507cc68d5SRichard Henderson return; 222607cc68d5SRichard Henderson } 222707cc68d5SRichard Henderson break; 222807cc68d5SRichard Henderson case 16: 222907cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 223007cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 223107cc68d5SRichard Henderson tcg_gen_ext16u_i64(ret, ret); 223207cc68d5SRichard Henderson return; 223307cc68d5SRichard Henderson } 223407cc68d5SRichard Henderson break; 223507cc68d5SRichard Henderson case 8: 223607cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 223707cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 223807cc68d5SRichard Henderson tcg_gen_ext8u_i64(ret, ret); 223907cc68d5SRichard Henderson return; 224007cc68d5SRichard Henderson } 224107cc68d5SRichard Henderson break; 224207cc68d5SRichard Henderson } 224307cc68d5SRichard Henderson tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); 224407cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 224507cc68d5SRichard Henderson } 224607cc68d5SRichard Henderson } 224707cc68d5SRichard Henderson 22487ec8bab3SRichard Henderson void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg, 22497ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 22507ec8bab3SRichard Henderson { 22517ec8bab3SRichard Henderson tcg_debug_assert(ofs < 64); 22527ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 22537ec8bab3SRichard Henderson tcg_debug_assert(len <= 64); 22547ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 64); 22557ec8bab3SRichard Henderson 22567ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if extract is supported. */ 22577ec8bab3SRichard Henderson if (ofs + len == 64) { 22587ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, 64 - len); 22597ec8bab3SRichard Henderson return; 22607ec8bab3SRichard Henderson } 22617ec8bab3SRichard Henderson if (ofs == 0) { 22627ec8bab3SRichard Henderson tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); 22637ec8bab3SRichard Henderson return; 22647ec8bab3SRichard Henderson } 22657ec8bab3SRichard Henderson 22667ec8bab3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 22677ec8bab3SRichard Henderson /* Look for a 32-bit extract within one of the two words. */ 22687ec8bab3SRichard Henderson if (ofs >= 32) { 22697ec8bab3SRichard Henderson tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len); 22707ec8bab3SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 22717ec8bab3SRichard Henderson return; 22727ec8bab3SRichard Henderson } 22737ec8bab3SRichard Henderson if (ofs + len <= 32) { 22747ec8bab3SRichard Henderson tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len); 22757ec8bab3SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 22767ec8bab3SRichard Henderson return; 22777ec8bab3SRichard Henderson } 22787ec8bab3SRichard Henderson /* The field is split across two words. One double-word 22797ec8bab3SRichard Henderson shift is better than two double-word shifts. */ 22807ec8bab3SRichard Henderson goto do_shift_and; 22817ec8bab3SRichard Henderson } 22827ec8bab3SRichard Henderson 22837ec8bab3SRichard Henderson if (TCG_TARGET_HAS_extract_i64 22847ec8bab3SRichard Henderson && TCG_TARGET_extract_i64_valid(ofs, len)) { 22857ec8bab3SRichard Henderson tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, ofs, len); 22867ec8bab3SRichard Henderson return; 22877ec8bab3SRichard Henderson } 22887ec8bab3SRichard Henderson 22897ec8bab3SRichard Henderson /* Assume that zero-extension, if available, is cheaper than a shift. */ 22907ec8bab3SRichard Henderson switch (ofs + len) { 22917ec8bab3SRichard Henderson case 32: 22927ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 22937ec8bab3SRichard Henderson tcg_gen_ext32u_i64(ret, arg); 22947ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, ofs); 22957ec8bab3SRichard Henderson return; 22967ec8bab3SRichard Henderson } 22977ec8bab3SRichard Henderson break; 22987ec8bab3SRichard Henderson case 16: 22997ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 23007ec8bab3SRichard Henderson tcg_gen_ext16u_i64(ret, arg); 23017ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, ofs); 23027ec8bab3SRichard Henderson return; 23037ec8bab3SRichard Henderson } 23047ec8bab3SRichard Henderson break; 23057ec8bab3SRichard Henderson case 8: 23067ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 23077ec8bab3SRichard Henderson tcg_gen_ext8u_i64(ret, arg); 23087ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, ofs); 23097ec8bab3SRichard Henderson return; 23107ec8bab3SRichard Henderson } 23117ec8bab3SRichard Henderson break; 23127ec8bab3SRichard Henderson } 23137ec8bab3SRichard Henderson 23147ec8bab3SRichard Henderson /* ??? Ideally we'd know what values are available for immediate AND. 23157ec8bab3SRichard Henderson Assume that 8 bits are available, plus the special cases of 16 and 32, 23167ec8bab3SRichard Henderson so that we get ext8u, ext16u, and ext32u. */ 23177ec8bab3SRichard Henderson switch (len) { 23187ec8bab3SRichard Henderson case 1 ... 8: case 16: case 32: 23197ec8bab3SRichard Henderson do_shift_and: 23207ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 23217ec8bab3SRichard Henderson tcg_gen_andi_i64(ret, ret, (1ull << len) - 1); 23227ec8bab3SRichard Henderson break; 23237ec8bab3SRichard Henderson default: 23247ec8bab3SRichard Henderson tcg_gen_shli_i64(ret, arg, 64 - len - ofs); 23257ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, 64 - len); 23267ec8bab3SRichard Henderson break; 23277ec8bab3SRichard Henderson } 23287ec8bab3SRichard Henderson } 23297ec8bab3SRichard Henderson 23307ec8bab3SRichard Henderson void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg, 23317ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 23327ec8bab3SRichard Henderson { 23337ec8bab3SRichard Henderson tcg_debug_assert(ofs < 64); 23347ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 23357ec8bab3SRichard Henderson tcg_debug_assert(len <= 64); 23367ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 64); 23377ec8bab3SRichard Henderson 23387ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if sextract is supported. */ 23397ec8bab3SRichard Henderson if (ofs + len == 64) { 23407ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, arg, 64 - len); 23417ec8bab3SRichard Henderson return; 23427ec8bab3SRichard Henderson } 23437ec8bab3SRichard Henderson if (ofs == 0) { 23447ec8bab3SRichard Henderson switch (len) { 23457ec8bab3SRichard Henderson case 32: 23467ec8bab3SRichard Henderson tcg_gen_ext32s_i64(ret, arg); 23477ec8bab3SRichard Henderson return; 23487ec8bab3SRichard Henderson case 16: 23497ec8bab3SRichard Henderson tcg_gen_ext16s_i64(ret, arg); 23507ec8bab3SRichard Henderson return; 23517ec8bab3SRichard Henderson case 8: 23527ec8bab3SRichard Henderson tcg_gen_ext8s_i64(ret, arg); 23537ec8bab3SRichard Henderson return; 23547ec8bab3SRichard Henderson } 23557ec8bab3SRichard Henderson } 23567ec8bab3SRichard Henderson 23577ec8bab3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 23587ec8bab3SRichard Henderson /* Look for a 32-bit extract within one of the two words. */ 23597ec8bab3SRichard Henderson if (ofs >= 32) { 23607ec8bab3SRichard Henderson tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len); 23617ec8bab3SRichard Henderson } else if (ofs + len <= 32) { 23627ec8bab3SRichard Henderson tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len); 23637ec8bab3SRichard Henderson } else if (ofs == 0) { 23647ec8bab3SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 23657ec8bab3SRichard Henderson tcg_gen_sextract_i32(TCGV_HIGH(ret), TCGV_HIGH(arg), 0, len - 32); 23667ec8bab3SRichard Henderson return; 23677ec8bab3SRichard Henderson } else if (len > 32) { 23687ec8bab3SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 23697ec8bab3SRichard Henderson /* Extract the bits for the high word normally. */ 23707ec8bab3SRichard Henderson tcg_gen_sextract_i32(t, TCGV_HIGH(arg), ofs + 32, len - 32); 23717ec8bab3SRichard Henderson /* Shift the field down for the low part. */ 23727ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 23737ec8bab3SRichard Henderson /* Overwrite the shift into the high part. */ 23747ec8bab3SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), t); 23757ec8bab3SRichard Henderson tcg_temp_free_i32(t); 23767ec8bab3SRichard Henderson return; 23777ec8bab3SRichard Henderson } else { 23787ec8bab3SRichard Henderson /* Shift the field down for the low part, such that the 23797ec8bab3SRichard Henderson field sits at the MSB. */ 23807ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs + len - 32); 23817ec8bab3SRichard Henderson /* Shift the field down from the MSB, sign extending. */ 23827ec8bab3SRichard Henderson tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_LOW(ret), 32 - len); 23837ec8bab3SRichard Henderson } 23847ec8bab3SRichard Henderson /* Sign-extend the field from 32 bits. */ 23857ec8bab3SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 23867ec8bab3SRichard Henderson return; 23877ec8bab3SRichard Henderson } 23887ec8bab3SRichard Henderson 23897ec8bab3SRichard Henderson if (TCG_TARGET_HAS_sextract_i64 23907ec8bab3SRichard Henderson && TCG_TARGET_extract_i64_valid(ofs, len)) { 23917ec8bab3SRichard Henderson tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, ofs, len); 23927ec8bab3SRichard Henderson return; 23937ec8bab3SRichard Henderson } 23947ec8bab3SRichard Henderson 23957ec8bab3SRichard Henderson /* Assume that sign-extension, if available, is cheaper than a shift. */ 23967ec8bab3SRichard Henderson switch (ofs + len) { 23977ec8bab3SRichard Henderson case 32: 23987ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext32s_i64) { 23997ec8bab3SRichard Henderson tcg_gen_ext32s_i64(ret, arg); 24007ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, ofs); 24017ec8bab3SRichard Henderson return; 24027ec8bab3SRichard Henderson } 24037ec8bab3SRichard Henderson break; 24047ec8bab3SRichard Henderson case 16: 24057ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i64) { 24067ec8bab3SRichard Henderson tcg_gen_ext16s_i64(ret, arg); 24077ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, ofs); 24087ec8bab3SRichard Henderson return; 24097ec8bab3SRichard Henderson } 24107ec8bab3SRichard Henderson break; 24117ec8bab3SRichard Henderson case 8: 24127ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i64) { 24137ec8bab3SRichard Henderson tcg_gen_ext8s_i64(ret, arg); 24147ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, ofs); 24157ec8bab3SRichard Henderson return; 24167ec8bab3SRichard Henderson } 24177ec8bab3SRichard Henderson break; 24187ec8bab3SRichard Henderson } 24197ec8bab3SRichard Henderson switch (len) { 24207ec8bab3SRichard Henderson case 32: 24217ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext32s_i64) { 24227ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 24237ec8bab3SRichard Henderson tcg_gen_ext32s_i64(ret, ret); 24247ec8bab3SRichard Henderson return; 24257ec8bab3SRichard Henderson } 24267ec8bab3SRichard Henderson break; 24277ec8bab3SRichard Henderson case 16: 24287ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i64) { 24297ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 24307ec8bab3SRichard Henderson tcg_gen_ext16s_i64(ret, ret); 24317ec8bab3SRichard Henderson return; 24327ec8bab3SRichard Henderson } 24337ec8bab3SRichard Henderson break; 24347ec8bab3SRichard Henderson case 8: 24357ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i64) { 24367ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 24377ec8bab3SRichard Henderson tcg_gen_ext8s_i64(ret, ret); 24387ec8bab3SRichard Henderson return; 24397ec8bab3SRichard Henderson } 24407ec8bab3SRichard Henderson break; 24417ec8bab3SRichard Henderson } 24427ec8bab3SRichard Henderson tcg_gen_shli_i64(ret, arg, 64 - len - ofs); 24437ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, 64 - len); 24447ec8bab3SRichard Henderson } 24457ec8bab3SRichard Henderson 24462089fcc9SDavid Hildenbrand /* 24472089fcc9SDavid Hildenbrand * Extract 64 bits from a 128-bit input, ah:al, starting from ofs. 24482089fcc9SDavid Hildenbrand * Unlike tcg_gen_extract_i64 above, len is fixed at 64. 24492089fcc9SDavid Hildenbrand */ 24502089fcc9SDavid Hildenbrand void tcg_gen_extract2_i64(TCGv_i64 ret, TCGv_i64 al, TCGv_i64 ah, 24512089fcc9SDavid Hildenbrand unsigned int ofs) 24522089fcc9SDavid Hildenbrand { 24532089fcc9SDavid Hildenbrand tcg_debug_assert(ofs <= 64); 24542089fcc9SDavid Hildenbrand if (ofs == 0) { 24552089fcc9SDavid Hildenbrand tcg_gen_mov_i64(ret, al); 24562089fcc9SDavid Hildenbrand } else if (ofs == 64) { 24572089fcc9SDavid Hildenbrand tcg_gen_mov_i64(ret, ah); 24582089fcc9SDavid Hildenbrand } else if (al == ah) { 24592089fcc9SDavid Hildenbrand tcg_gen_rotri_i64(ret, al, ofs); 2460fce1296fSRichard Henderson } else if (TCG_TARGET_HAS_extract2_i64) { 2461fce1296fSRichard Henderson tcg_gen_op4i_i64(INDEX_op_extract2_i64, ret, al, ah, ofs); 24622089fcc9SDavid Hildenbrand } else { 24632089fcc9SDavid Hildenbrand TCGv_i64 t0 = tcg_temp_new_i64(); 24642089fcc9SDavid Hildenbrand tcg_gen_shri_i64(t0, al, ofs); 24652089fcc9SDavid Hildenbrand tcg_gen_deposit_i64(ret, t0, ah, 64 - ofs, ofs); 24662089fcc9SDavid Hildenbrand tcg_temp_free_i64(t0); 24672089fcc9SDavid Hildenbrand } 24682089fcc9SDavid Hildenbrand } 24692089fcc9SDavid Hildenbrand 2470951c6300SRichard Henderson void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1, 2471951c6300SRichard Henderson TCGv_i64 c2, TCGv_i64 v1, TCGv_i64 v2) 2472951c6300SRichard Henderson { 247337ed3bf1SRichard Henderson if (cond == TCG_COND_ALWAYS) { 247437ed3bf1SRichard Henderson tcg_gen_mov_i64(ret, v1); 247537ed3bf1SRichard Henderson } else if (cond == TCG_COND_NEVER) { 247637ed3bf1SRichard Henderson tcg_gen_mov_i64(ret, v2); 247737ed3bf1SRichard Henderson } else if (TCG_TARGET_REG_BITS == 32) { 2478951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 2479951c6300SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 2480951c6300SRichard Henderson tcg_gen_op6i_i32(INDEX_op_setcond2_i32, t0, 2481951c6300SRichard Henderson TCGV_LOW(c1), TCGV_HIGH(c1), 2482951c6300SRichard Henderson TCGV_LOW(c2), TCGV_HIGH(c2), cond); 2483951c6300SRichard Henderson 2484951c6300SRichard Henderson if (TCG_TARGET_HAS_movcond_i32) { 2485951c6300SRichard Henderson tcg_gen_movi_i32(t1, 0); 2486951c6300SRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, TCGV_LOW(ret), t0, t1, 2487951c6300SRichard Henderson TCGV_LOW(v1), TCGV_LOW(v2)); 2488951c6300SRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, TCGV_HIGH(ret), t0, t1, 2489951c6300SRichard Henderson TCGV_HIGH(v1), TCGV_HIGH(v2)); 2490951c6300SRichard Henderson } else { 2491951c6300SRichard Henderson tcg_gen_neg_i32(t0, t0); 2492951c6300SRichard Henderson 2493951c6300SRichard Henderson tcg_gen_and_i32(t1, TCGV_LOW(v1), t0); 2494951c6300SRichard Henderson tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(v2), t0); 2495951c6300SRichard Henderson tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t1); 2496951c6300SRichard Henderson 2497951c6300SRichard Henderson tcg_gen_and_i32(t1, TCGV_HIGH(v1), t0); 2498951c6300SRichard Henderson tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(v2), t0); 2499951c6300SRichard Henderson tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t1); 2500951c6300SRichard Henderson } 2501951c6300SRichard Henderson tcg_temp_free_i32(t0); 2502951c6300SRichard Henderson tcg_temp_free_i32(t1); 25033a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_movcond_i64) { 2504951c6300SRichard Henderson tcg_gen_op6i_i64(INDEX_op_movcond_i64, ret, c1, c2, v1, v2, cond); 2505951c6300SRichard Henderson } else { 2506951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2507951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2508951c6300SRichard Henderson tcg_gen_setcond_i64(cond, t0, c1, c2); 2509951c6300SRichard Henderson tcg_gen_neg_i64(t0, t0); 2510951c6300SRichard Henderson tcg_gen_and_i64(t1, v1, t0); 2511951c6300SRichard Henderson tcg_gen_andc_i64(ret, v2, t0); 2512951c6300SRichard Henderson tcg_gen_or_i64(ret, ret, t1); 2513951c6300SRichard Henderson tcg_temp_free_i64(t0); 2514951c6300SRichard Henderson tcg_temp_free_i64(t1); 2515951c6300SRichard Henderson } 2516951c6300SRichard Henderson } 2517951c6300SRichard Henderson 2518951c6300SRichard Henderson void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, 2519951c6300SRichard Henderson TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) 2520951c6300SRichard Henderson { 2521951c6300SRichard Henderson if (TCG_TARGET_HAS_add2_i64) { 2522951c6300SRichard Henderson tcg_gen_op6_i64(INDEX_op_add2_i64, rl, rh, al, ah, bl, bh); 2523951c6300SRichard Henderson } else { 2524951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2525951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2526951c6300SRichard Henderson tcg_gen_add_i64(t0, al, bl); 2527951c6300SRichard Henderson tcg_gen_setcond_i64(TCG_COND_LTU, t1, t0, al); 2528951c6300SRichard Henderson tcg_gen_add_i64(rh, ah, bh); 2529951c6300SRichard Henderson tcg_gen_add_i64(rh, rh, t1); 2530951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2531951c6300SRichard Henderson tcg_temp_free_i64(t0); 2532951c6300SRichard Henderson tcg_temp_free_i64(t1); 2533951c6300SRichard Henderson } 2534951c6300SRichard Henderson } 2535951c6300SRichard Henderson 2536951c6300SRichard Henderson void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, 2537951c6300SRichard Henderson TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) 2538951c6300SRichard Henderson { 2539951c6300SRichard Henderson if (TCG_TARGET_HAS_sub2_i64) { 2540951c6300SRichard Henderson tcg_gen_op6_i64(INDEX_op_sub2_i64, rl, rh, al, ah, bl, bh); 2541951c6300SRichard Henderson } else { 2542951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2543951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2544951c6300SRichard Henderson tcg_gen_sub_i64(t0, al, bl); 2545951c6300SRichard Henderson tcg_gen_setcond_i64(TCG_COND_LTU, t1, al, bl); 2546951c6300SRichard Henderson tcg_gen_sub_i64(rh, ah, bh); 2547951c6300SRichard Henderson tcg_gen_sub_i64(rh, rh, t1); 2548951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2549951c6300SRichard Henderson tcg_temp_free_i64(t0); 2550951c6300SRichard Henderson tcg_temp_free_i64(t1); 2551951c6300SRichard Henderson } 2552951c6300SRichard Henderson } 2553951c6300SRichard Henderson 2554951c6300SRichard Henderson void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) 2555951c6300SRichard Henderson { 2556951c6300SRichard Henderson if (TCG_TARGET_HAS_mulu2_i64) { 2557951c6300SRichard Henderson tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2); 2558951c6300SRichard Henderson } else if (TCG_TARGET_HAS_muluh_i64) { 2559951c6300SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2560951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2); 2561951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_muluh_i64, rh, arg1, arg2); 2562951c6300SRichard Henderson tcg_gen_mov_i64(rl, t); 2563951c6300SRichard Henderson tcg_temp_free_i64(t); 2564951c6300SRichard Henderson } else { 2565951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2566951c6300SRichard Henderson tcg_gen_mul_i64(t0, arg1, arg2); 2567951c6300SRichard Henderson gen_helper_muluh_i64(rh, arg1, arg2); 2568951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2569951c6300SRichard Henderson tcg_temp_free_i64(t0); 2570951c6300SRichard Henderson } 2571951c6300SRichard Henderson } 2572951c6300SRichard Henderson 2573951c6300SRichard Henderson void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) 2574951c6300SRichard Henderson { 2575951c6300SRichard Henderson if (TCG_TARGET_HAS_muls2_i64) { 2576951c6300SRichard Henderson tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2); 2577951c6300SRichard Henderson } else if (TCG_TARGET_HAS_mulsh_i64) { 2578951c6300SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2579951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2); 2580951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_mulsh_i64, rh, arg1, arg2); 2581951c6300SRichard Henderson tcg_gen_mov_i64(rl, t); 2582951c6300SRichard Henderson tcg_temp_free_i64(t); 2583951c6300SRichard Henderson } else if (TCG_TARGET_HAS_mulu2_i64 || TCG_TARGET_HAS_muluh_i64) { 2584951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2585951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2586951c6300SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 2587951c6300SRichard Henderson TCGv_i64 t3 = tcg_temp_new_i64(); 2588951c6300SRichard Henderson tcg_gen_mulu2_i64(t0, t1, arg1, arg2); 2589951c6300SRichard Henderson /* Adjust for negative inputs. */ 2590951c6300SRichard Henderson tcg_gen_sari_i64(t2, arg1, 63); 2591951c6300SRichard Henderson tcg_gen_sari_i64(t3, arg2, 63); 2592951c6300SRichard Henderson tcg_gen_and_i64(t2, t2, arg2); 2593951c6300SRichard Henderson tcg_gen_and_i64(t3, t3, arg1); 2594951c6300SRichard Henderson tcg_gen_sub_i64(rh, t1, t2); 2595951c6300SRichard Henderson tcg_gen_sub_i64(rh, rh, t3); 2596951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2597951c6300SRichard Henderson tcg_temp_free_i64(t0); 2598951c6300SRichard Henderson tcg_temp_free_i64(t1); 2599951c6300SRichard Henderson tcg_temp_free_i64(t2); 2600951c6300SRichard Henderson tcg_temp_free_i64(t3); 2601951c6300SRichard Henderson } else { 2602951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2603951c6300SRichard Henderson tcg_gen_mul_i64(t0, arg1, arg2); 2604951c6300SRichard Henderson gen_helper_mulsh_i64(rh, arg1, arg2); 2605951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2606951c6300SRichard Henderson tcg_temp_free_i64(t0); 2607951c6300SRichard Henderson } 2608951c6300SRichard Henderson } 2609951c6300SRichard Henderson 26105087abfbSRichard Henderson void tcg_gen_mulsu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) 26115087abfbSRichard Henderson { 26125087abfbSRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 26135087abfbSRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 26145087abfbSRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 26155087abfbSRichard Henderson tcg_gen_mulu2_i64(t0, t1, arg1, arg2); 26165087abfbSRichard Henderson /* Adjust for negative input for the signed arg1. */ 26175087abfbSRichard Henderson tcg_gen_sari_i64(t2, arg1, 63); 26185087abfbSRichard Henderson tcg_gen_and_i64(t2, t2, arg2); 26195087abfbSRichard Henderson tcg_gen_sub_i64(rh, t1, t2); 26205087abfbSRichard Henderson tcg_gen_mov_i64(rl, t0); 26215087abfbSRichard Henderson tcg_temp_free_i64(t0); 26225087abfbSRichard Henderson tcg_temp_free_i64(t1); 26235087abfbSRichard Henderson tcg_temp_free_i64(t2); 26245087abfbSRichard Henderson } 26255087abfbSRichard Henderson 2626b87fb8cdSRichard Henderson void tcg_gen_smin_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2627b87fb8cdSRichard Henderson { 2628b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LT, ret, a, b, a, b); 2629b87fb8cdSRichard Henderson } 2630b87fb8cdSRichard Henderson 2631b87fb8cdSRichard Henderson void tcg_gen_umin_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2632b87fb8cdSRichard Henderson { 2633b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, a, b); 2634b87fb8cdSRichard Henderson } 2635b87fb8cdSRichard Henderson 2636b87fb8cdSRichard Henderson void tcg_gen_smax_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2637b87fb8cdSRichard Henderson { 2638b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LT, ret, a, b, b, a); 2639b87fb8cdSRichard Henderson } 2640b87fb8cdSRichard Henderson 2641b87fb8cdSRichard Henderson void tcg_gen_umax_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2642b87fb8cdSRichard Henderson { 2643b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, b, a); 2644b87fb8cdSRichard Henderson } 2645b87fb8cdSRichard Henderson 2646ff1f11f7SRichard Henderson void tcg_gen_abs_i64(TCGv_i64 ret, TCGv_i64 a) 2647ff1f11f7SRichard Henderson { 2648ff1f11f7SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2649ff1f11f7SRichard Henderson 2650ff1f11f7SRichard Henderson tcg_gen_sari_i64(t, a, 63); 2651ff1f11f7SRichard Henderson tcg_gen_xor_i64(ret, a, t); 2652ff1f11f7SRichard Henderson tcg_gen_sub_i64(ret, ret, t); 2653ff1f11f7SRichard Henderson tcg_temp_free_i64(t); 2654ff1f11f7SRichard Henderson } 2655ff1f11f7SRichard Henderson 2656951c6300SRichard Henderson /* Size changing operations. */ 2657951c6300SRichard Henderson 2658609ad705SRichard Henderson void tcg_gen_extrl_i64_i32(TCGv_i32 ret, TCGv_i64 arg) 2659951c6300SRichard Henderson { 26603a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2661951c6300SRichard Henderson tcg_gen_mov_i32(ret, TCGV_LOW(arg)); 2662609ad705SRichard Henderson } else if (TCG_TARGET_HAS_extrl_i64_i32) { 2663b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_extrl_i64_i32, 2664ae8b75dcSRichard Henderson tcgv_i32_arg(ret), tcgv_i64_arg(arg)); 2665951c6300SRichard Henderson } else { 2666dc41aa7dSRichard Henderson tcg_gen_mov_i32(ret, (TCGv_i32)arg); 2667609ad705SRichard Henderson } 2668609ad705SRichard Henderson } 2669609ad705SRichard Henderson 2670609ad705SRichard Henderson void tcg_gen_extrh_i64_i32(TCGv_i32 ret, TCGv_i64 arg) 2671609ad705SRichard Henderson { 2672609ad705SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2673609ad705SRichard Henderson tcg_gen_mov_i32(ret, TCGV_HIGH(arg)); 2674609ad705SRichard Henderson } else if (TCG_TARGET_HAS_extrh_i64_i32) { 2675b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_extrh_i64_i32, 2676ae8b75dcSRichard Henderson tcgv_i32_arg(ret), tcgv_i64_arg(arg)); 2677951c6300SRichard Henderson } else { 2678951c6300SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2679609ad705SRichard Henderson tcg_gen_shri_i64(t, arg, 32); 2680dc41aa7dSRichard Henderson tcg_gen_mov_i32(ret, (TCGv_i32)t); 2681951c6300SRichard Henderson tcg_temp_free_i64(t); 2682951c6300SRichard Henderson } 2683951c6300SRichard Henderson } 2684951c6300SRichard Henderson 2685951c6300SRichard Henderson void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg) 2686951c6300SRichard Henderson { 26873a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2688951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), arg); 2689951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 26903a13c3f3SRichard Henderson } else { 2691b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_extu_i32_i64, 2692ae8b75dcSRichard Henderson tcgv_i64_arg(ret), tcgv_i32_arg(arg)); 26933a13c3f3SRichard Henderson } 2694951c6300SRichard Henderson } 2695951c6300SRichard Henderson 2696951c6300SRichard Henderson void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg) 2697951c6300SRichard Henderson { 26983a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2699951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), arg); 2700951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 27013a13c3f3SRichard Henderson } else { 2702b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_ext_i32_i64, 2703ae8b75dcSRichard Henderson tcgv_i64_arg(ret), tcgv_i32_arg(arg)); 27043a13c3f3SRichard Henderson } 2705951c6300SRichard Henderson } 2706951c6300SRichard Henderson 2707951c6300SRichard Henderson void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high) 2708951c6300SRichard Henderson { 27093a13c3f3SRichard Henderson TCGv_i64 tmp; 27103a13c3f3SRichard Henderson 27113a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2712951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(dest), low); 2713951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(dest), high); 27143a13c3f3SRichard Henderson return; 27153a13c3f3SRichard Henderson } 27163a13c3f3SRichard Henderson 27173a13c3f3SRichard Henderson tmp = tcg_temp_new_i64(); 2718951c6300SRichard Henderson /* These extensions are only needed for type correctness. 2719951c6300SRichard Henderson We may be able to do better given target specific information. */ 2720951c6300SRichard Henderson tcg_gen_extu_i32_i64(tmp, high); 2721951c6300SRichard Henderson tcg_gen_extu_i32_i64(dest, low); 2722951c6300SRichard Henderson /* If deposit is available, use it. Otherwise use the extra 2723951c6300SRichard Henderson knowledge that we have of the zero-extensions above. */ 2724951c6300SRichard Henderson if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(32, 32)) { 2725951c6300SRichard Henderson tcg_gen_deposit_i64(dest, dest, tmp, 32, 32); 2726951c6300SRichard Henderson } else { 2727951c6300SRichard Henderson tcg_gen_shli_i64(tmp, tmp, 32); 2728951c6300SRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 2729951c6300SRichard Henderson } 2730951c6300SRichard Henderson tcg_temp_free_i64(tmp); 2731951c6300SRichard Henderson } 2732951c6300SRichard Henderson 2733951c6300SRichard Henderson void tcg_gen_extr_i64_i32(TCGv_i32 lo, TCGv_i32 hi, TCGv_i64 arg) 2734951c6300SRichard Henderson { 27353a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2736951c6300SRichard Henderson tcg_gen_mov_i32(lo, TCGV_LOW(arg)); 2737951c6300SRichard Henderson tcg_gen_mov_i32(hi, TCGV_HIGH(arg)); 27383a13c3f3SRichard Henderson } else { 2739609ad705SRichard Henderson tcg_gen_extrl_i64_i32(lo, arg); 2740609ad705SRichard Henderson tcg_gen_extrh_i64_i32(hi, arg); 27413a13c3f3SRichard Henderson } 2742951c6300SRichard Henderson } 2743951c6300SRichard Henderson 2744951c6300SRichard Henderson void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg) 2745951c6300SRichard Henderson { 2746951c6300SRichard Henderson tcg_gen_ext32u_i64(lo, arg); 2747951c6300SRichard Henderson tcg_gen_shri_i64(hi, arg, 32); 2748951c6300SRichard Henderson } 2749951c6300SRichard Henderson 2750*4771e71cSRichard Henderson void tcg_gen_extr_i128_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i128 arg) 2751*4771e71cSRichard Henderson { 2752*4771e71cSRichard Henderson tcg_gen_mov_i64(lo, TCGV128_LOW(arg)); 2753*4771e71cSRichard Henderson tcg_gen_mov_i64(hi, TCGV128_HIGH(arg)); 2754*4771e71cSRichard Henderson } 2755*4771e71cSRichard Henderson 2756*4771e71cSRichard Henderson void tcg_gen_concat_i64_i128(TCGv_i128 ret, TCGv_i64 lo, TCGv_i64 hi) 2757*4771e71cSRichard Henderson { 2758*4771e71cSRichard Henderson tcg_gen_mov_i64(TCGV128_LOW(ret), lo); 2759*4771e71cSRichard Henderson tcg_gen_mov_i64(TCGV128_HIGH(ret), hi); 2760*4771e71cSRichard Henderson } 2761*4771e71cSRichard Henderson 2762*4771e71cSRichard Henderson void tcg_gen_mov_i128(TCGv_i128 dst, TCGv_i128 src) 2763*4771e71cSRichard Henderson { 2764*4771e71cSRichard Henderson if (dst != src) { 2765*4771e71cSRichard Henderson tcg_gen_mov_i64(TCGV128_LOW(dst), TCGV128_LOW(src)); 2766*4771e71cSRichard Henderson tcg_gen_mov_i64(TCGV128_HIGH(dst), TCGV128_HIGH(src)); 2767*4771e71cSRichard Henderson } 2768*4771e71cSRichard Henderson } 2769*4771e71cSRichard Henderson 2770951c6300SRichard Henderson /* QEMU specific operations. */ 2771951c6300SRichard Henderson 2772d9971435SRichard Henderson void tcg_gen_exit_tb(const TranslationBlock *tb, unsigned idx) 277307ea28b4SRichard Henderson { 2774eba40358SRichard Henderson /* 2775eba40358SRichard Henderson * Let the jit code return the read-only version of the 2776eba40358SRichard Henderson * TranslationBlock, so that we minimize the pc-relative 2777eba40358SRichard Henderson * distance of the address of the exit_tb code to TB. 2778eba40358SRichard Henderson * This will improve utilization of pc-relative address loads. 2779eba40358SRichard Henderson * 2780eba40358SRichard Henderson * TODO: Move this to translator_loop, so that all const 2781eba40358SRichard Henderson * TranslationBlock pointers refer to read-only memory. 2782eba40358SRichard Henderson * This requires coordination with targets that do not use 2783eba40358SRichard Henderson * the translator_loop. 2784eba40358SRichard Henderson */ 2785eba40358SRichard Henderson uintptr_t val = (uintptr_t)tcg_splitwx_to_rx((void *)tb) + idx; 278607ea28b4SRichard Henderson 278707ea28b4SRichard Henderson if (tb == NULL) { 278807ea28b4SRichard Henderson tcg_debug_assert(idx == 0); 278907ea28b4SRichard Henderson } else if (idx <= TB_EXIT_IDXMAX) { 279007ea28b4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 279107ea28b4SRichard Henderson /* This is an exit following a goto_tb. Verify that we have 279207ea28b4SRichard Henderson seen this numbered exit before, via tcg_gen_goto_tb. */ 279307ea28b4SRichard Henderson tcg_debug_assert(tcg_ctx->goto_tb_issue_mask & (1 << idx)); 279407ea28b4SRichard Henderson #endif 279507ea28b4SRichard Henderson } else { 279607ea28b4SRichard Henderson /* This is an exit via the exitreq label. */ 279707ea28b4SRichard Henderson tcg_debug_assert(idx == TB_EXIT_REQUESTED); 279807ea28b4SRichard Henderson } 279907ea28b4SRichard Henderson 2800e6d86bedSEmilio G. Cota plugin_gen_disable_mem_helpers(); 280107ea28b4SRichard Henderson tcg_gen_op1i(INDEX_op_exit_tb, val); 280207ea28b4SRichard Henderson } 280307ea28b4SRichard Henderson 2804951c6300SRichard Henderson void tcg_gen_goto_tb(unsigned idx) 2805951c6300SRichard Henderson { 280684f15616SRichard Henderson /* We tested CF_NO_GOTO_TB in translator_use_goto_tb. */ 2807b7e4afbdSRichard Henderson tcg_debug_assert(!(tcg_ctx->gen_tb->cflags & CF_NO_GOTO_TB)); 2808951c6300SRichard Henderson /* We only support two chained exits. */ 280907ea28b4SRichard Henderson tcg_debug_assert(idx <= TB_EXIT_IDXMAX); 2810951c6300SRichard Henderson #ifdef CONFIG_DEBUG_TCG 2811a4761232SPhilippe Mathieu-Daudé /* Verify that we haven't seen this numbered exit before. */ 2812b1311c4aSEmilio G. Cota tcg_debug_assert((tcg_ctx->goto_tb_issue_mask & (1 << idx)) == 0); 2813b1311c4aSEmilio G. Cota tcg_ctx->goto_tb_issue_mask |= 1 << idx; 2814951c6300SRichard Henderson #endif 2815e6d86bedSEmilio G. Cota plugin_gen_disable_mem_helpers(); 2816951c6300SRichard Henderson tcg_gen_op1i(INDEX_op_goto_tb, idx); 2817951c6300SRichard Henderson } 2818951c6300SRichard Henderson 28197f11636dSEmilio G. Cota void tcg_gen_lookup_and_goto_ptr(void) 2820cedbcb01SEmilio G. Cota { 2821e6d86bedSEmilio G. Cota TCGv_ptr ptr; 2822e6d86bedSEmilio G. Cota 2823b7e4afbdSRichard Henderson if (tcg_ctx->gen_tb->cflags & CF_NO_GOTO_PTR) { 282484f15616SRichard Henderson tcg_gen_exit_tb(NULL, 0); 282584f15616SRichard Henderson return; 282684f15616SRichard Henderson } 282784f15616SRichard Henderson 2828e6d86bedSEmilio G. Cota plugin_gen_disable_mem_helpers(); 2829e6d86bedSEmilio G. Cota ptr = tcg_temp_new_ptr(); 28301c2adb95SRichard Henderson gen_helper_lookup_tb_ptr(ptr, cpu_env); 2831ae8b75dcSRichard Henderson tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr)); 2832cedbcb01SEmilio G. Cota tcg_temp_free_ptr(ptr); 2833cedbcb01SEmilio G. Cota } 2834cedbcb01SEmilio G. Cota 283514776ab5STony Nguyen static inline MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st) 2836951c6300SRichard Henderson { 28371f00b27fSSergey Sorokin /* Trigger the asserts within as early as possible. */ 283876e366e7SRichard Henderson unsigned a_bits = get_alignment_bits(op); 283976e366e7SRichard Henderson 284076e366e7SRichard Henderson /* Prefer MO_ALIGN+MO_XX over MO_ALIGN_XX+MO_XX */ 284176e366e7SRichard Henderson if (a_bits == (op & MO_SIZE)) { 284276e366e7SRichard Henderson op = (op & ~MO_AMASK) | MO_ALIGN; 284376e366e7SRichard Henderson } 28441f00b27fSSergey Sorokin 2845951c6300SRichard Henderson switch (op & MO_SIZE) { 2846951c6300SRichard Henderson case MO_8: 2847951c6300SRichard Henderson op &= ~MO_BSWAP; 2848951c6300SRichard Henderson break; 2849951c6300SRichard Henderson case MO_16: 2850951c6300SRichard Henderson break; 2851951c6300SRichard Henderson case MO_32: 2852951c6300SRichard Henderson if (!is64) { 2853951c6300SRichard Henderson op &= ~MO_SIGN; 2854951c6300SRichard Henderson } 2855951c6300SRichard Henderson break; 2856951c6300SRichard Henderson case MO_64: 28574b473e0cSRichard Henderson if (is64) { 28584b473e0cSRichard Henderson op &= ~MO_SIGN; 2859951c6300SRichard Henderson break; 2860951c6300SRichard Henderson } 28614b473e0cSRichard Henderson /* fall through */ 28624b473e0cSRichard Henderson default: 28634b473e0cSRichard Henderson g_assert_not_reached(); 28644b473e0cSRichard Henderson } 2865951c6300SRichard Henderson if (st) { 2866951c6300SRichard Henderson op &= ~MO_SIGN; 2867951c6300SRichard Henderson } 2868951c6300SRichard Henderson return op; 2869951c6300SRichard Henderson } 2870951c6300SRichard Henderson 2871c45cb8bbSRichard Henderson static void gen_ldst_i32(TCGOpcode opc, TCGv_i32 val, TCGv addr, 287214776ab5STony Nguyen MemOp memop, TCGArg idx) 2873951c6300SRichard Henderson { 28749002ffcbSRichard Henderson MemOpIdx oi = make_memop_idx(memop, idx); 2875951c6300SRichard Henderson #if TARGET_LONG_BITS == 32 287659227d5dSRichard Henderson tcg_gen_op3i_i32(opc, val, addr, oi); 2877951c6300SRichard Henderson #else 2878c45cb8bbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 287959227d5dSRichard Henderson tcg_gen_op4i_i32(opc, val, TCGV_LOW(addr), TCGV_HIGH(addr), oi); 2880c45cb8bbSRichard Henderson } else { 2881ae8b75dcSRichard Henderson tcg_gen_op3(opc, tcgv_i32_arg(val), tcgv_i64_arg(addr), oi); 2882c45cb8bbSRichard Henderson } 2883951c6300SRichard Henderson #endif 2884c45cb8bbSRichard Henderson } 2885c45cb8bbSRichard Henderson 2886c45cb8bbSRichard Henderson static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 val, TCGv addr, 288714776ab5STony Nguyen MemOp memop, TCGArg idx) 2888c45cb8bbSRichard Henderson { 28899002ffcbSRichard Henderson MemOpIdx oi = make_memop_idx(memop, idx); 2890c45cb8bbSRichard Henderson #if TARGET_LONG_BITS == 32 2891c45cb8bbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 289259227d5dSRichard Henderson tcg_gen_op4i_i32(opc, TCGV_LOW(val), TCGV_HIGH(val), addr, oi); 2893c45cb8bbSRichard Henderson } else { 2894ae8b75dcSRichard Henderson tcg_gen_op3(opc, tcgv_i64_arg(val), tcgv_i32_arg(addr), oi); 2895c45cb8bbSRichard Henderson } 2896c45cb8bbSRichard Henderson #else 2897c45cb8bbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 289859227d5dSRichard Henderson tcg_gen_op5i_i32(opc, TCGV_LOW(val), TCGV_HIGH(val), 289959227d5dSRichard Henderson TCGV_LOW(addr), TCGV_HIGH(addr), oi); 2900c45cb8bbSRichard Henderson } else { 290159227d5dSRichard Henderson tcg_gen_op3i_i64(opc, val, addr, oi); 2902c45cb8bbSRichard Henderson } 2903c45cb8bbSRichard Henderson #endif 2904c45cb8bbSRichard Henderson } 2905951c6300SRichard Henderson 2906b32dc337SPranith Kumar static void tcg_gen_req_mo(TCGBar type) 2907b32dc337SPranith Kumar { 2908b32dc337SPranith Kumar #ifdef TCG_GUEST_DEFAULT_MO 2909b32dc337SPranith Kumar type &= TCG_GUEST_DEFAULT_MO; 2910b32dc337SPranith Kumar #endif 2911b32dc337SPranith Kumar type &= ~TCG_TARGET_DEFAULT_MO; 2912b32dc337SPranith Kumar if (type) { 2913b32dc337SPranith Kumar tcg_gen_mb(type | TCG_BAR_SC); 2914b32dc337SPranith Kumar } 2915b32dc337SPranith Kumar } 2916b32dc337SPranith Kumar 2917fcc54ab5SAlex Bennée static inline TCGv plugin_prep_mem_callbacks(TCGv vaddr) 2918fcc54ab5SAlex Bennée { 2919fcc54ab5SAlex Bennée #ifdef CONFIG_PLUGIN 2920fcc54ab5SAlex Bennée if (tcg_ctx->plugin_insn != NULL) { 2921fcc54ab5SAlex Bennée /* Save a copy of the vaddr for use after a load. */ 2922fcc54ab5SAlex Bennée TCGv temp = tcg_temp_new(); 2923fcc54ab5SAlex Bennée tcg_gen_mov_tl(temp, vaddr); 2924fcc54ab5SAlex Bennée return temp; 2925fcc54ab5SAlex Bennée } 2926fcc54ab5SAlex Bennée #endif 2927fcc54ab5SAlex Bennée return vaddr; 2928fcc54ab5SAlex Bennée } 2929fcc54ab5SAlex Bennée 293037aff087SRichard Henderson static void plugin_gen_mem_callbacks(TCGv vaddr, MemOpIdx oi, 293137aff087SRichard Henderson enum qemu_plugin_mem_rw rw) 2932e6d86bedSEmilio G. Cota { 2933e6d86bedSEmilio G. Cota #ifdef CONFIG_PLUGIN 2934fcc54ab5SAlex Bennée if (tcg_ctx->plugin_insn != NULL) { 293537aff087SRichard Henderson qemu_plugin_meminfo_t info = make_plugin_meminfo(oi, rw); 2936e6d86bedSEmilio G. Cota plugin_gen_empty_mem_callback(vaddr, info); 2937fcc54ab5SAlex Bennée tcg_temp_free(vaddr); 2938fcc54ab5SAlex Bennée } 2939e6d86bedSEmilio G. Cota #endif 2940e6d86bedSEmilio G. Cota } 2941e6d86bedSEmilio G. Cota 294214776ab5STony Nguyen void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) 2943951c6300SRichard Henderson { 294414776ab5STony Nguyen MemOp orig_memop; 294537aff087SRichard Henderson MemOpIdx oi; 2946e1dcf352SRichard Henderson 2947b32dc337SPranith Kumar tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 2948951c6300SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 294937aff087SRichard Henderson oi = make_memop_idx(memop, idx); 2950e1dcf352SRichard Henderson 2951e1dcf352SRichard Henderson orig_memop = memop; 2952e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 2953e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 2954359feba5SRichard Henderson /* The bswap primitive benefits from zero-extended input. */ 2955e1dcf352SRichard Henderson if ((memop & MO_SSIZE) == MO_SW) { 2956e1dcf352SRichard Henderson memop &= ~MO_SIGN; 2957e1dcf352SRichard Henderson } 2958e1dcf352SRichard Henderson } 2959e1dcf352SRichard Henderson 2960fcc54ab5SAlex Bennée addr = plugin_prep_mem_callbacks(addr); 2961c45cb8bbSRichard Henderson gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx); 296237aff087SRichard Henderson plugin_gen_mem_callbacks(addr, oi, QEMU_PLUGIN_MEM_R); 2963e1dcf352SRichard Henderson 2964e1dcf352SRichard Henderson if ((orig_memop ^ memop) & MO_BSWAP) { 2965e1dcf352SRichard Henderson switch (orig_memop & MO_SIZE) { 2966e1dcf352SRichard Henderson case MO_16: 2967359feba5SRichard Henderson tcg_gen_bswap16_i32(val, val, (orig_memop & MO_SIGN 2968359feba5SRichard Henderson ? TCG_BSWAP_IZ | TCG_BSWAP_OS 2969359feba5SRichard Henderson : TCG_BSWAP_IZ | TCG_BSWAP_OZ)); 2970e1dcf352SRichard Henderson break; 2971e1dcf352SRichard Henderson case MO_32: 2972e1dcf352SRichard Henderson tcg_gen_bswap32_i32(val, val); 2973e1dcf352SRichard Henderson break; 2974e1dcf352SRichard Henderson default: 2975e1dcf352SRichard Henderson g_assert_not_reached(); 2976e1dcf352SRichard Henderson } 2977e1dcf352SRichard Henderson } 2978951c6300SRichard Henderson } 2979951c6300SRichard Henderson 298014776ab5STony Nguyen void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) 2981951c6300SRichard Henderson { 2982e1dcf352SRichard Henderson TCGv_i32 swap = NULL; 298337aff087SRichard Henderson MemOpIdx oi; 2984e1dcf352SRichard Henderson 2985b32dc337SPranith Kumar tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 2986951c6300SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 1); 298737aff087SRichard Henderson oi = make_memop_idx(memop, idx); 2988e1dcf352SRichard Henderson 2989e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 2990e1dcf352SRichard Henderson swap = tcg_temp_new_i32(); 2991e1dcf352SRichard Henderson switch (memop & MO_SIZE) { 2992e1dcf352SRichard Henderson case MO_16: 2993b53357acSRichard Henderson tcg_gen_bswap16_i32(swap, val, 0); 2994e1dcf352SRichard Henderson break; 2995e1dcf352SRichard Henderson case MO_32: 2996e1dcf352SRichard Henderson tcg_gen_bswap32_i32(swap, val); 2997e1dcf352SRichard Henderson break; 2998e1dcf352SRichard Henderson default: 2999e1dcf352SRichard Henderson g_assert_not_reached(); 3000e1dcf352SRichard Henderson } 3001e1dcf352SRichard Henderson val = swap; 3002e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 3003e1dcf352SRichard Henderson } 3004e1dcf352SRichard Henderson 3005fcc54ab5SAlex Bennée addr = plugin_prep_mem_callbacks(addr); 300607ce0b05SRichard Henderson if (TCG_TARGET_HAS_qemu_st8_i32 && (memop & MO_SIZE) == MO_8) { 300707ce0b05SRichard Henderson gen_ldst_i32(INDEX_op_qemu_st8_i32, val, addr, memop, idx); 300807ce0b05SRichard Henderson } else { 3009c45cb8bbSRichard Henderson gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx); 301007ce0b05SRichard Henderson } 301137aff087SRichard Henderson plugin_gen_mem_callbacks(addr, oi, QEMU_PLUGIN_MEM_W); 3012e1dcf352SRichard Henderson 3013e1dcf352SRichard Henderson if (swap) { 3014e1dcf352SRichard Henderson tcg_temp_free_i32(swap); 3015e1dcf352SRichard Henderson } 3016951c6300SRichard Henderson } 3017951c6300SRichard Henderson 301814776ab5STony Nguyen void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) 3019951c6300SRichard Henderson { 302014776ab5STony Nguyen MemOp orig_memop; 302137aff087SRichard Henderson MemOpIdx oi; 3022e1dcf352SRichard Henderson 30233a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) { 3024951c6300SRichard Henderson tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop); 3025951c6300SRichard Henderson if (memop & MO_SIGN) { 3026951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(val), TCGV_LOW(val), 31); 3027951c6300SRichard Henderson } else { 3028951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(val), 0); 3029951c6300SRichard Henderson } 3030951c6300SRichard Henderson return; 3031951c6300SRichard Henderson } 3032951c6300SRichard Henderson 3033e1dcf352SRichard Henderson tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 3034c45cb8bbSRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 303537aff087SRichard Henderson oi = make_memop_idx(memop, idx); 3036e1dcf352SRichard Henderson 3037e1dcf352SRichard Henderson orig_memop = memop; 3038e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 3039e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 3040359feba5SRichard Henderson /* The bswap primitive benefits from zero-extended input. */ 3041e1dcf352SRichard Henderson if ((memop & MO_SIGN) && (memop & MO_SIZE) < MO_64) { 3042e1dcf352SRichard Henderson memop &= ~MO_SIGN; 3043e1dcf352SRichard Henderson } 3044e1dcf352SRichard Henderson } 3045e1dcf352SRichard Henderson 3046fcc54ab5SAlex Bennée addr = plugin_prep_mem_callbacks(addr); 3047c45cb8bbSRichard Henderson gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx); 304837aff087SRichard Henderson plugin_gen_mem_callbacks(addr, oi, QEMU_PLUGIN_MEM_R); 3049e1dcf352SRichard Henderson 3050e1dcf352SRichard Henderson if ((orig_memop ^ memop) & MO_BSWAP) { 3051359feba5SRichard Henderson int flags = (orig_memop & MO_SIGN 3052359feba5SRichard Henderson ? TCG_BSWAP_IZ | TCG_BSWAP_OS 3053359feba5SRichard Henderson : TCG_BSWAP_IZ | TCG_BSWAP_OZ); 3054e1dcf352SRichard Henderson switch (orig_memop & MO_SIZE) { 3055e1dcf352SRichard Henderson case MO_16: 3056359feba5SRichard Henderson tcg_gen_bswap16_i64(val, val, flags); 3057e1dcf352SRichard Henderson break; 3058e1dcf352SRichard Henderson case MO_32: 3059359feba5SRichard Henderson tcg_gen_bswap32_i64(val, val, flags); 3060e1dcf352SRichard Henderson break; 3061e1dcf352SRichard Henderson case MO_64: 3062e1dcf352SRichard Henderson tcg_gen_bswap64_i64(val, val); 3063e1dcf352SRichard Henderson break; 3064e1dcf352SRichard Henderson default: 3065e1dcf352SRichard Henderson g_assert_not_reached(); 3066e1dcf352SRichard Henderson } 3067e1dcf352SRichard Henderson } 3068951c6300SRichard Henderson } 3069951c6300SRichard Henderson 307014776ab5STony Nguyen void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) 3071951c6300SRichard Henderson { 3072e1dcf352SRichard Henderson TCGv_i64 swap = NULL; 307337aff087SRichard Henderson MemOpIdx oi; 3074e1dcf352SRichard Henderson 30753a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) { 3076951c6300SRichard Henderson tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop); 3077951c6300SRichard Henderson return; 3078951c6300SRichard Henderson } 3079951c6300SRichard Henderson 3080e1dcf352SRichard Henderson tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 3081c45cb8bbSRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 1); 308237aff087SRichard Henderson oi = make_memop_idx(memop, idx); 3083e1dcf352SRichard Henderson 3084e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 3085e1dcf352SRichard Henderson swap = tcg_temp_new_i64(); 3086e1dcf352SRichard Henderson switch (memop & MO_SIZE) { 3087e1dcf352SRichard Henderson case MO_16: 3088b53357acSRichard Henderson tcg_gen_bswap16_i64(swap, val, 0); 3089e1dcf352SRichard Henderson break; 3090e1dcf352SRichard Henderson case MO_32: 3091b53357acSRichard Henderson tcg_gen_bswap32_i64(swap, val, 0); 3092e1dcf352SRichard Henderson break; 3093e1dcf352SRichard Henderson case MO_64: 3094e1dcf352SRichard Henderson tcg_gen_bswap64_i64(swap, val); 3095e1dcf352SRichard Henderson break; 3096e1dcf352SRichard Henderson default: 3097e1dcf352SRichard Henderson g_assert_not_reached(); 3098e1dcf352SRichard Henderson } 3099e1dcf352SRichard Henderson val = swap; 3100e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 3101e1dcf352SRichard Henderson } 3102e1dcf352SRichard Henderson 3103fcc54ab5SAlex Bennée addr = plugin_prep_mem_callbacks(addr); 3104c45cb8bbSRichard Henderson gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx); 310537aff087SRichard Henderson plugin_gen_mem_callbacks(addr, oi, QEMU_PLUGIN_MEM_W); 3106e1dcf352SRichard Henderson 3107e1dcf352SRichard Henderson if (swap) { 3108e1dcf352SRichard Henderson tcg_temp_free_i64(swap); 3109e1dcf352SRichard Henderson } 3110951c6300SRichard Henderson } 3111c482cb11SRichard Henderson 311214776ab5STony Nguyen static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc) 3113c482cb11SRichard Henderson { 3114c482cb11SRichard Henderson switch (opc & MO_SSIZE) { 3115c482cb11SRichard Henderson case MO_SB: 3116c482cb11SRichard Henderson tcg_gen_ext8s_i32(ret, val); 3117c482cb11SRichard Henderson break; 3118c482cb11SRichard Henderson case MO_UB: 3119c482cb11SRichard Henderson tcg_gen_ext8u_i32(ret, val); 3120c482cb11SRichard Henderson break; 3121c482cb11SRichard Henderson case MO_SW: 3122c482cb11SRichard Henderson tcg_gen_ext16s_i32(ret, val); 3123c482cb11SRichard Henderson break; 3124c482cb11SRichard Henderson case MO_UW: 3125c482cb11SRichard Henderson tcg_gen_ext16u_i32(ret, val); 3126c482cb11SRichard Henderson break; 3127c482cb11SRichard Henderson default: 3128c482cb11SRichard Henderson tcg_gen_mov_i32(ret, val); 3129c482cb11SRichard Henderson break; 3130c482cb11SRichard Henderson } 3131c482cb11SRichard Henderson } 3132c482cb11SRichard Henderson 313314776ab5STony Nguyen static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc) 3134c482cb11SRichard Henderson { 3135c482cb11SRichard Henderson switch (opc & MO_SSIZE) { 3136c482cb11SRichard Henderson case MO_SB: 3137c482cb11SRichard Henderson tcg_gen_ext8s_i64(ret, val); 3138c482cb11SRichard Henderson break; 3139c482cb11SRichard Henderson case MO_UB: 3140c482cb11SRichard Henderson tcg_gen_ext8u_i64(ret, val); 3141c482cb11SRichard Henderson break; 3142c482cb11SRichard Henderson case MO_SW: 3143c482cb11SRichard Henderson tcg_gen_ext16s_i64(ret, val); 3144c482cb11SRichard Henderson break; 3145c482cb11SRichard Henderson case MO_UW: 3146c482cb11SRichard Henderson tcg_gen_ext16u_i64(ret, val); 3147c482cb11SRichard Henderson break; 3148c482cb11SRichard Henderson case MO_SL: 3149c482cb11SRichard Henderson tcg_gen_ext32s_i64(ret, val); 3150c482cb11SRichard Henderson break; 3151c482cb11SRichard Henderson case MO_UL: 3152c482cb11SRichard Henderson tcg_gen_ext32u_i64(ret, val); 3153c482cb11SRichard Henderson break; 3154c482cb11SRichard Henderson default: 3155c482cb11SRichard Henderson tcg_gen_mov_i64(ret, val); 3156c482cb11SRichard Henderson break; 3157c482cb11SRichard Henderson } 3158c482cb11SRichard Henderson } 3159c482cb11SRichard Henderson 3160c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv, 3161c482cb11SRichard Henderson TCGv_i32, TCGv_i32, TCGv_i32); 3162c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv, 3163c482cb11SRichard Henderson TCGv_i64, TCGv_i64, TCGv_i32); 3164c482cb11SRichard Henderson typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv, 3165c482cb11SRichard Henderson TCGv_i32, TCGv_i32); 3166c482cb11SRichard Henderson typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv, 3167c482cb11SRichard Henderson TCGv_i64, TCGv_i32); 3168c482cb11SRichard Henderson 3169df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64 3170df79b996SRichard Henderson # define WITH_ATOMIC64(X) X, 3171df79b996SRichard Henderson #else 3172df79b996SRichard Henderson # define WITH_ATOMIC64(X) 3173df79b996SRichard Henderson #endif 3174df79b996SRichard Henderson 31754b473e0cSRichard Henderson static void * const table_cmpxchg[(MO_SIZE | MO_BSWAP) + 1] = { 3176c482cb11SRichard Henderson [MO_8] = gen_helper_atomic_cmpxchgb, 3177c482cb11SRichard Henderson [MO_16 | MO_LE] = gen_helper_atomic_cmpxchgw_le, 3178c482cb11SRichard Henderson [MO_16 | MO_BE] = gen_helper_atomic_cmpxchgw_be, 3179c482cb11SRichard Henderson [MO_32 | MO_LE] = gen_helper_atomic_cmpxchgl_le, 3180c482cb11SRichard Henderson [MO_32 | MO_BE] = gen_helper_atomic_cmpxchgl_be, 3181df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_cmpxchgq_le) 3182df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_cmpxchgq_be) 3183c482cb11SRichard Henderson }; 3184c482cb11SRichard Henderson 3185c482cb11SRichard Henderson void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv, 318614776ab5STony Nguyen TCGv_i32 newv, TCGArg idx, MemOp memop) 3187c482cb11SRichard Henderson { 3188c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 3189c482cb11SRichard Henderson 3190b7e4afbdSRichard Henderson if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) { 3191c482cb11SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 3192c482cb11SRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 3193c482cb11SRichard Henderson 3194c482cb11SRichard Henderson tcg_gen_ext_i32(t2, cmpv, memop & MO_SIZE); 3195c482cb11SRichard Henderson 3196c482cb11SRichard Henderson tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN); 3197c482cb11SRichard Henderson tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, t2, newv, t1); 3198c482cb11SRichard Henderson tcg_gen_qemu_st_i32(t2, addr, idx, memop); 3199c482cb11SRichard Henderson tcg_temp_free_i32(t2); 3200c482cb11SRichard Henderson 3201c482cb11SRichard Henderson if (memop & MO_SIGN) { 3202c482cb11SRichard Henderson tcg_gen_ext_i32(retv, t1, memop); 3203c482cb11SRichard Henderson } else { 3204c482cb11SRichard Henderson tcg_gen_mov_i32(retv, t1); 3205c482cb11SRichard Henderson } 3206c482cb11SRichard Henderson tcg_temp_free_i32(t1); 3207c482cb11SRichard Henderson } else { 3208c482cb11SRichard Henderson gen_atomic_cx_i32 gen; 32099002ffcbSRichard Henderson MemOpIdx oi; 3210c482cb11SRichard Henderson 3211c482cb11SRichard Henderson gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; 3212c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3213c482cb11SRichard Henderson 3214e28a8664SRichard Henderson oi = make_memop_idx(memop & ~MO_SIGN, idx); 321511d11d61SRichard Henderson gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); 3216c482cb11SRichard Henderson 3217c482cb11SRichard Henderson if (memop & MO_SIGN) { 3218c482cb11SRichard Henderson tcg_gen_ext_i32(retv, retv, memop); 3219c482cb11SRichard Henderson } 3220c482cb11SRichard Henderson } 3221c482cb11SRichard Henderson } 3222c482cb11SRichard Henderson 3223c482cb11SRichard Henderson void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv, 322414776ab5STony Nguyen TCGv_i64 newv, TCGArg idx, MemOp memop) 3225c482cb11SRichard Henderson { 3226c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 3227c482cb11SRichard Henderson 3228b7e4afbdSRichard Henderson if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) { 3229c482cb11SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 3230c482cb11SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 3231c482cb11SRichard Henderson 3232c482cb11SRichard Henderson tcg_gen_ext_i64(t2, cmpv, memop & MO_SIZE); 3233c482cb11SRichard Henderson 3234c482cb11SRichard Henderson tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN); 3235c482cb11SRichard Henderson tcg_gen_movcond_i64(TCG_COND_EQ, t2, t1, t2, newv, t1); 3236c482cb11SRichard Henderson tcg_gen_qemu_st_i64(t2, addr, idx, memop); 3237c482cb11SRichard Henderson tcg_temp_free_i64(t2); 3238c482cb11SRichard Henderson 3239c482cb11SRichard Henderson if (memop & MO_SIGN) { 3240c482cb11SRichard Henderson tcg_gen_ext_i64(retv, t1, memop); 3241c482cb11SRichard Henderson } else { 3242c482cb11SRichard Henderson tcg_gen_mov_i64(retv, t1); 3243c482cb11SRichard Henderson } 3244c482cb11SRichard Henderson tcg_temp_free_i64(t1); 3245c482cb11SRichard Henderson } else if ((memop & MO_SIZE) == MO_64) { 3246df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64 3247c482cb11SRichard Henderson gen_atomic_cx_i64 gen; 32489002ffcbSRichard Henderson MemOpIdx oi; 3249c482cb11SRichard Henderson 3250c482cb11SRichard Henderson gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; 3251c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3252c482cb11SRichard Henderson 3253e28a8664SRichard Henderson oi = make_memop_idx(memop, idx); 325411d11d61SRichard Henderson gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); 3255df79b996SRichard Henderson #else 32561c2adb95SRichard Henderson gen_helper_exit_atomic(cpu_env); 325779b1af90SRichard Henderson /* Produce a result, so that we have a well-formed opcode stream 325879b1af90SRichard Henderson with respect to uses of the result in the (dead) code following. */ 325979b1af90SRichard Henderson tcg_gen_movi_i64(retv, 0); 3260df79b996SRichard Henderson #endif /* CONFIG_ATOMIC64 */ 3261c482cb11SRichard Henderson } else { 3262c482cb11SRichard Henderson TCGv_i32 c32 = tcg_temp_new_i32(); 3263c482cb11SRichard Henderson TCGv_i32 n32 = tcg_temp_new_i32(); 3264c482cb11SRichard Henderson TCGv_i32 r32 = tcg_temp_new_i32(); 3265c482cb11SRichard Henderson 3266c482cb11SRichard Henderson tcg_gen_extrl_i64_i32(c32, cmpv); 3267c482cb11SRichard Henderson tcg_gen_extrl_i64_i32(n32, newv); 3268c482cb11SRichard Henderson tcg_gen_atomic_cmpxchg_i32(r32, addr, c32, n32, idx, memop & ~MO_SIGN); 3269c482cb11SRichard Henderson tcg_temp_free_i32(c32); 3270c482cb11SRichard Henderson tcg_temp_free_i32(n32); 3271c482cb11SRichard Henderson 3272c482cb11SRichard Henderson tcg_gen_extu_i32_i64(retv, r32); 3273c482cb11SRichard Henderson tcg_temp_free_i32(r32); 3274c482cb11SRichard Henderson 3275c482cb11SRichard Henderson if (memop & MO_SIGN) { 3276c482cb11SRichard Henderson tcg_gen_ext_i64(retv, retv, memop); 3277c482cb11SRichard Henderson } 3278c482cb11SRichard Henderson } 3279c482cb11SRichard Henderson } 3280c482cb11SRichard Henderson 3281c482cb11SRichard Henderson static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, 328214776ab5STony Nguyen TCGArg idx, MemOp memop, bool new_val, 3283c482cb11SRichard Henderson void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32)) 3284c482cb11SRichard Henderson { 3285c482cb11SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 3286c482cb11SRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 3287c482cb11SRichard Henderson 3288c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 3289c482cb11SRichard Henderson 3290852f933eSRichard Henderson tcg_gen_qemu_ld_i32(t1, addr, idx, memop); 3291852f933eSRichard Henderson tcg_gen_ext_i32(t2, val, memop); 3292852f933eSRichard Henderson gen(t2, t1, t2); 3293c482cb11SRichard Henderson tcg_gen_qemu_st_i32(t2, addr, idx, memop); 3294c482cb11SRichard Henderson 3295c482cb11SRichard Henderson tcg_gen_ext_i32(ret, (new_val ? t2 : t1), memop); 3296c482cb11SRichard Henderson tcg_temp_free_i32(t1); 3297c482cb11SRichard Henderson tcg_temp_free_i32(t2); 3298c482cb11SRichard Henderson } 3299c482cb11SRichard Henderson 3300c482cb11SRichard Henderson static void do_atomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, 330114776ab5STony Nguyen TCGArg idx, MemOp memop, void * const table[]) 3302c482cb11SRichard Henderson { 3303c482cb11SRichard Henderson gen_atomic_op_i32 gen; 33049002ffcbSRichard Henderson MemOpIdx oi; 3305c482cb11SRichard Henderson 3306c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 3307c482cb11SRichard Henderson 3308c482cb11SRichard Henderson gen = table[memop & (MO_SIZE | MO_BSWAP)]; 3309c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3310c482cb11SRichard Henderson 3311e28a8664SRichard Henderson oi = make_memop_idx(memop & ~MO_SIGN, idx); 331211d11d61SRichard Henderson gen(ret, cpu_env, addr, val, tcg_constant_i32(oi)); 3313c482cb11SRichard Henderson 3314c482cb11SRichard Henderson if (memop & MO_SIGN) { 3315c482cb11SRichard Henderson tcg_gen_ext_i32(ret, ret, memop); 3316c482cb11SRichard Henderson } 3317c482cb11SRichard Henderson } 3318c482cb11SRichard Henderson 3319c482cb11SRichard Henderson static void do_nonatomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, 332014776ab5STony Nguyen TCGArg idx, MemOp memop, bool new_val, 3321c482cb11SRichard Henderson void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64)) 3322c482cb11SRichard Henderson { 3323c482cb11SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 3324c482cb11SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 3325c482cb11SRichard Henderson 3326c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 3327c482cb11SRichard Henderson 3328852f933eSRichard Henderson tcg_gen_qemu_ld_i64(t1, addr, idx, memop); 3329852f933eSRichard Henderson tcg_gen_ext_i64(t2, val, memop); 3330852f933eSRichard Henderson gen(t2, t1, t2); 3331c482cb11SRichard Henderson tcg_gen_qemu_st_i64(t2, addr, idx, memop); 3332c482cb11SRichard Henderson 3333c482cb11SRichard Henderson tcg_gen_ext_i64(ret, (new_val ? t2 : t1), memop); 3334c482cb11SRichard Henderson tcg_temp_free_i64(t1); 3335c482cb11SRichard Henderson tcg_temp_free_i64(t2); 3336c482cb11SRichard Henderson } 3337c482cb11SRichard Henderson 3338c482cb11SRichard Henderson static void do_atomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, 333914776ab5STony Nguyen TCGArg idx, MemOp memop, void * const table[]) 3340c482cb11SRichard Henderson { 3341c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 3342c482cb11SRichard Henderson 3343c482cb11SRichard Henderson if ((memop & MO_SIZE) == MO_64) { 3344df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64 3345c482cb11SRichard Henderson gen_atomic_op_i64 gen; 33469002ffcbSRichard Henderson MemOpIdx oi; 3347c482cb11SRichard Henderson 3348c482cb11SRichard Henderson gen = table[memop & (MO_SIZE | MO_BSWAP)]; 3349c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3350c482cb11SRichard Henderson 3351e28a8664SRichard Henderson oi = make_memop_idx(memop & ~MO_SIGN, idx); 335211d11d61SRichard Henderson gen(ret, cpu_env, addr, val, tcg_constant_i32(oi)); 3353df79b996SRichard Henderson #else 33541c2adb95SRichard Henderson gen_helper_exit_atomic(cpu_env); 335579b1af90SRichard Henderson /* Produce a result, so that we have a well-formed opcode stream 335679b1af90SRichard Henderson with respect to uses of the result in the (dead) code following. */ 335779b1af90SRichard Henderson tcg_gen_movi_i64(ret, 0); 3358df79b996SRichard Henderson #endif /* CONFIG_ATOMIC64 */ 3359c482cb11SRichard Henderson } else { 3360c482cb11SRichard Henderson TCGv_i32 v32 = tcg_temp_new_i32(); 3361c482cb11SRichard Henderson TCGv_i32 r32 = tcg_temp_new_i32(); 3362c482cb11SRichard Henderson 3363c482cb11SRichard Henderson tcg_gen_extrl_i64_i32(v32, val); 3364c482cb11SRichard Henderson do_atomic_op_i32(r32, addr, v32, idx, memop & ~MO_SIGN, table); 3365c482cb11SRichard Henderson tcg_temp_free_i32(v32); 3366c482cb11SRichard Henderson 3367c482cb11SRichard Henderson tcg_gen_extu_i32_i64(ret, r32); 3368c482cb11SRichard Henderson tcg_temp_free_i32(r32); 3369c482cb11SRichard Henderson 3370c482cb11SRichard Henderson if (memop & MO_SIGN) { 3371c482cb11SRichard Henderson tcg_gen_ext_i64(ret, ret, memop); 3372c482cb11SRichard Henderson } 3373c482cb11SRichard Henderson } 3374c482cb11SRichard Henderson } 3375c482cb11SRichard Henderson 3376c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(NAME, OP, NEW) \ 33774b473e0cSRichard Henderson static void * const table_##NAME[(MO_SIZE | MO_BSWAP) + 1] = { \ 3378c482cb11SRichard Henderson [MO_8] = gen_helper_atomic_##NAME##b, \ 3379c482cb11SRichard Henderson [MO_16 | MO_LE] = gen_helper_atomic_##NAME##w_le, \ 3380c482cb11SRichard Henderson [MO_16 | MO_BE] = gen_helper_atomic_##NAME##w_be, \ 3381c482cb11SRichard Henderson [MO_32 | MO_LE] = gen_helper_atomic_##NAME##l_le, \ 3382c482cb11SRichard Henderson [MO_32 | MO_BE] = gen_helper_atomic_##NAME##l_be, \ 3383df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_##NAME##q_le) \ 3384df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_##NAME##q_be) \ 3385c482cb11SRichard Henderson }; \ 3386c482cb11SRichard Henderson void tcg_gen_atomic_##NAME##_i32 \ 338714776ab5STony Nguyen (TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, MemOp memop) \ 3388c482cb11SRichard Henderson { \ 3389b7e4afbdSRichard Henderson if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) { \ 3390c482cb11SRichard Henderson do_atomic_op_i32(ret, addr, val, idx, memop, table_##NAME); \ 3391c482cb11SRichard Henderson } else { \ 3392c482cb11SRichard Henderson do_nonatomic_op_i32(ret, addr, val, idx, memop, NEW, \ 3393c482cb11SRichard Henderson tcg_gen_##OP##_i32); \ 3394c482cb11SRichard Henderson } \ 3395c482cb11SRichard Henderson } \ 3396c482cb11SRichard Henderson void tcg_gen_atomic_##NAME##_i64 \ 339714776ab5STony Nguyen (TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, MemOp memop) \ 3398c482cb11SRichard Henderson { \ 3399b7e4afbdSRichard Henderson if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) { \ 3400c482cb11SRichard Henderson do_atomic_op_i64(ret, addr, val, idx, memop, table_##NAME); \ 3401c482cb11SRichard Henderson } else { \ 3402c482cb11SRichard Henderson do_nonatomic_op_i64(ret, addr, val, idx, memop, NEW, \ 3403c482cb11SRichard Henderson tcg_gen_##OP##_i64); \ 3404c482cb11SRichard Henderson } \ 3405c482cb11SRichard Henderson } 3406c482cb11SRichard Henderson 3407c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add, add, 0) 3408c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and, and, 0) 3409c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or, or, 0) 3410c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor, xor, 0) 34115507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_smin, smin, 0) 34125507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_umin, umin, 0) 34135507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_smax, smax, 0) 34145507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_umax, umax, 0) 3415c482cb11SRichard Henderson 3416c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch, add, 1) 3417c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch, and, 1) 3418c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch, or, 1) 3419c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch, xor, 1) 34205507c2bfSRichard Henderson GEN_ATOMIC_HELPER(smin_fetch, smin, 1) 34215507c2bfSRichard Henderson GEN_ATOMIC_HELPER(umin_fetch, umin, 1) 34225507c2bfSRichard Henderson GEN_ATOMIC_HELPER(smax_fetch, smax, 1) 34235507c2bfSRichard Henderson GEN_ATOMIC_HELPER(umax_fetch, umax, 1) 3424c482cb11SRichard Henderson 3425c482cb11SRichard Henderson static void tcg_gen_mov2_i32(TCGv_i32 r, TCGv_i32 a, TCGv_i32 b) 3426c482cb11SRichard Henderson { 3427c482cb11SRichard Henderson tcg_gen_mov_i32(r, b); 3428c482cb11SRichard Henderson } 3429c482cb11SRichard Henderson 3430c482cb11SRichard Henderson static void tcg_gen_mov2_i64(TCGv_i64 r, TCGv_i64 a, TCGv_i64 b) 3431c482cb11SRichard Henderson { 3432c482cb11SRichard Henderson tcg_gen_mov_i64(r, b); 3433c482cb11SRichard Henderson } 3434c482cb11SRichard Henderson 3435c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xchg, mov2, 0) 3436c482cb11SRichard Henderson 3437c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 3438