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" 2633c11879SPaolo Bonzini #include "cpu.h" 2763c91552SPaolo Bonzini #include "exec/exec-all.h" 28951c6300SRichard Henderson #include "tcg.h" 29951c6300SRichard Henderson #include "tcg-op.h" 30b32dc337SPranith Kumar #include "tcg-mo.h" 31dcdaadb6SLluís Vilanova #include "trace-tcg.h" 32dcdaadb6SLluís Vilanova #include "trace/mem.h" 33951c6300SRichard Henderson 343a13c3f3SRichard Henderson /* Reduce the number of ifdefs below. This assumes that all uses of 353a13c3f3SRichard Henderson TCGV_HIGH and TCGV_LOW are properly protected by a conditional that 363a13c3f3SRichard Henderson the compiler can eliminate. */ 373a13c3f3SRichard Henderson #if TCG_TARGET_REG_BITS == 64 383a13c3f3SRichard Henderson extern TCGv_i32 TCGV_LOW_link_error(TCGv_i64); 393a13c3f3SRichard Henderson extern TCGv_i32 TCGV_HIGH_link_error(TCGv_i64); 403a13c3f3SRichard Henderson #define TCGV_LOW TCGV_LOW_link_error 413a13c3f3SRichard Henderson #define TCGV_HIGH TCGV_HIGH_link_error 423a13c3f3SRichard Henderson #endif 43951c6300SRichard Henderson 44b7e8b17aSRichard Henderson void tcg_gen_op1(TCGOpcode opc, TCGArg a1) 45951c6300SRichard Henderson { 46b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 4775e8b9b7SRichard Henderson op->args[0] = a1; 48951c6300SRichard Henderson } 49951c6300SRichard Henderson 50b7e8b17aSRichard Henderson void tcg_gen_op2(TCGOpcode opc, TCGArg a1, TCGArg a2) 51951c6300SRichard Henderson { 52b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 5375e8b9b7SRichard Henderson op->args[0] = a1; 5475e8b9b7SRichard Henderson op->args[1] = a2; 55951c6300SRichard Henderson } 56951c6300SRichard Henderson 57b7e8b17aSRichard Henderson void tcg_gen_op3(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3) 58951c6300SRichard Henderson { 59b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 6075e8b9b7SRichard Henderson op->args[0] = a1; 6175e8b9b7SRichard Henderson op->args[1] = a2; 6275e8b9b7SRichard Henderson op->args[2] = a3; 63951c6300SRichard Henderson } 64951c6300SRichard Henderson 65b7e8b17aSRichard Henderson void tcg_gen_op4(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, TCGArg a4) 66951c6300SRichard Henderson { 67b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 6875e8b9b7SRichard Henderson op->args[0] = a1; 6975e8b9b7SRichard Henderson op->args[1] = a2; 7075e8b9b7SRichard Henderson op->args[2] = a3; 7175e8b9b7SRichard Henderson op->args[3] = a4; 72951c6300SRichard Henderson } 73951c6300SRichard Henderson 74b7e8b17aSRichard Henderson void tcg_gen_op5(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, 75b7e8b17aSRichard Henderson TCGArg a4, TCGArg a5) 76951c6300SRichard Henderson { 77b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 7875e8b9b7SRichard Henderson op->args[0] = a1; 7975e8b9b7SRichard Henderson op->args[1] = a2; 8075e8b9b7SRichard Henderson op->args[2] = a3; 8175e8b9b7SRichard Henderson op->args[3] = a4; 8275e8b9b7SRichard Henderson op->args[4] = a5; 83951c6300SRichard Henderson } 84951c6300SRichard Henderson 85b7e8b17aSRichard Henderson void tcg_gen_op6(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, 86b7e8b17aSRichard Henderson TCGArg a4, TCGArg a5, TCGArg a6) 87951c6300SRichard Henderson { 88b7e8b17aSRichard Henderson TCGOp *op = tcg_emit_op(opc); 8975e8b9b7SRichard Henderson op->args[0] = a1; 9075e8b9b7SRichard Henderson op->args[1] = a2; 9175e8b9b7SRichard Henderson op->args[2] = a3; 9275e8b9b7SRichard Henderson op->args[3] = a4; 9375e8b9b7SRichard Henderson op->args[4] = a5; 9475e8b9b7SRichard Henderson op->args[5] = a6; 95951c6300SRichard Henderson } 96951c6300SRichard Henderson 97f65e19bcSPranith Kumar void tcg_gen_mb(TCGBar mb_type) 98f65e19bcSPranith Kumar { 99b1311c4aSEmilio G. Cota if (tcg_ctx->tb_cflags & CF_PARALLEL) { 100b7e8b17aSRichard Henderson tcg_gen_op1(INDEX_op_mb, mb_type); 101f65e19bcSPranith Kumar } 102f65e19bcSPranith Kumar } 103f65e19bcSPranith Kumar 104951c6300SRichard Henderson /* 32 bit ops */ 105951c6300SRichard Henderson 106951c6300SRichard Henderson void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 107951c6300SRichard Henderson { 108951c6300SRichard Henderson /* some cases can be optimized here */ 109951c6300SRichard Henderson if (arg2 == 0) { 110951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 111951c6300SRichard Henderson } else { 112951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 113951c6300SRichard Henderson tcg_gen_add_i32(ret, arg1, t0); 114951c6300SRichard Henderson tcg_temp_free_i32(t0); 115951c6300SRichard Henderson } 116951c6300SRichard Henderson } 117951c6300SRichard Henderson 118951c6300SRichard Henderson void tcg_gen_subfi_i32(TCGv_i32 ret, int32_t arg1, TCGv_i32 arg2) 119951c6300SRichard Henderson { 120951c6300SRichard Henderson if (arg1 == 0 && TCG_TARGET_HAS_neg_i32) { 121951c6300SRichard Henderson /* Don't recurse with tcg_gen_neg_i32. */ 122951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg2); 123951c6300SRichard Henderson } else { 124951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg1); 125951c6300SRichard Henderson tcg_gen_sub_i32(ret, t0, arg2); 126951c6300SRichard Henderson tcg_temp_free_i32(t0); 127951c6300SRichard Henderson } 128951c6300SRichard Henderson } 129951c6300SRichard Henderson 130951c6300SRichard Henderson void tcg_gen_subi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 131951c6300SRichard Henderson { 132951c6300SRichard Henderson /* some cases can be optimized here */ 133951c6300SRichard Henderson if (arg2 == 0) { 134951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 135951c6300SRichard Henderson } else { 136951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 137951c6300SRichard Henderson tcg_gen_sub_i32(ret, arg1, t0); 138951c6300SRichard Henderson tcg_temp_free_i32(t0); 139951c6300SRichard Henderson } 140951c6300SRichard Henderson } 141951c6300SRichard Henderson 142474b2e8fSRichard Henderson void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 143951c6300SRichard Henderson { 144951c6300SRichard Henderson TCGv_i32 t0; 145951c6300SRichard Henderson /* Some cases can be optimized here. */ 146951c6300SRichard Henderson switch (arg2) { 147951c6300SRichard Henderson case 0: 148951c6300SRichard Henderson tcg_gen_movi_i32(ret, 0); 149951c6300SRichard Henderson return; 150474b2e8fSRichard Henderson case -1: 151951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 152951c6300SRichard Henderson return; 153474b2e8fSRichard Henderson case 0xff: 154951c6300SRichard Henderson /* Don't recurse with tcg_gen_ext8u_i32. */ 155951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 156951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg1); 157951c6300SRichard Henderson return; 158951c6300SRichard Henderson } 159951c6300SRichard Henderson break; 160474b2e8fSRichard Henderson case 0xffff: 161951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 162951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg1); 163951c6300SRichard Henderson return; 164951c6300SRichard Henderson } 165951c6300SRichard Henderson break; 166951c6300SRichard Henderson } 167951c6300SRichard Henderson t0 = tcg_const_i32(arg2); 168951c6300SRichard Henderson tcg_gen_and_i32(ret, arg1, t0); 169951c6300SRichard Henderson tcg_temp_free_i32(t0); 170951c6300SRichard Henderson } 171951c6300SRichard Henderson 172951c6300SRichard Henderson void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 173951c6300SRichard Henderson { 174951c6300SRichard Henderson /* Some cases can be optimized here. */ 175951c6300SRichard Henderson if (arg2 == -1) { 176951c6300SRichard Henderson tcg_gen_movi_i32(ret, -1); 177951c6300SRichard Henderson } else if (arg2 == 0) { 178951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 179951c6300SRichard Henderson } else { 180951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 181951c6300SRichard Henderson tcg_gen_or_i32(ret, arg1, t0); 182951c6300SRichard Henderson tcg_temp_free_i32(t0); 183951c6300SRichard Henderson } 184951c6300SRichard Henderson } 185951c6300SRichard Henderson 186951c6300SRichard Henderson void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 187951c6300SRichard Henderson { 188951c6300SRichard Henderson /* Some cases can be optimized here. */ 189951c6300SRichard Henderson if (arg2 == 0) { 190951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 191951c6300SRichard Henderson } else if (arg2 == -1 && TCG_TARGET_HAS_not_i32) { 192951c6300SRichard Henderson /* Don't recurse with tcg_gen_not_i32. */ 193951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg1); 194951c6300SRichard Henderson } else { 195951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 196951c6300SRichard Henderson tcg_gen_xor_i32(ret, arg1, t0); 197951c6300SRichard Henderson tcg_temp_free_i32(t0); 198951c6300SRichard Henderson } 199951c6300SRichard Henderson } 200951c6300SRichard Henderson 201474b2e8fSRichard Henderson void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 202951c6300SRichard Henderson { 203474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 204951c6300SRichard Henderson if (arg2 == 0) { 205951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 206951c6300SRichard Henderson } else { 207951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 208951c6300SRichard Henderson tcg_gen_shl_i32(ret, arg1, t0); 209951c6300SRichard Henderson tcg_temp_free_i32(t0); 210951c6300SRichard Henderson } 211951c6300SRichard Henderson } 212951c6300SRichard Henderson 213474b2e8fSRichard Henderson void tcg_gen_shri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 214951c6300SRichard Henderson { 215474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 216951c6300SRichard Henderson if (arg2 == 0) { 217951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 218951c6300SRichard Henderson } else { 219951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 220951c6300SRichard Henderson tcg_gen_shr_i32(ret, arg1, t0); 221951c6300SRichard Henderson tcg_temp_free_i32(t0); 222951c6300SRichard Henderson } 223951c6300SRichard Henderson } 224951c6300SRichard Henderson 225474b2e8fSRichard Henderson void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 226951c6300SRichard Henderson { 227474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 32); 228951c6300SRichard Henderson if (arg2 == 0) { 229951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 230951c6300SRichard Henderson } else { 231951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 232951c6300SRichard Henderson tcg_gen_sar_i32(ret, arg1, t0); 233951c6300SRichard Henderson tcg_temp_free_i32(t0); 234951c6300SRichard Henderson } 235951c6300SRichard Henderson } 236951c6300SRichard Henderson 23742a268c2SRichard Henderson void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1, TCGv_i32 arg2, TCGLabel *l) 238951c6300SRichard Henderson { 239951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 24042a268c2SRichard Henderson tcg_gen_br(l); 241951c6300SRichard Henderson } else if (cond != TCG_COND_NEVER) { 242d88a117eSRichard Henderson l->refs++; 24342a268c2SRichard Henderson tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_arg(l)); 244951c6300SRichard Henderson } 245951c6300SRichard Henderson } 246951c6300SRichard Henderson 24742a268c2SRichard Henderson void tcg_gen_brcondi_i32(TCGCond cond, TCGv_i32 arg1, int32_t arg2, TCGLabel *l) 248951c6300SRichard Henderson { 24937ed3bf1SRichard Henderson if (cond == TCG_COND_ALWAYS) { 25037ed3bf1SRichard Henderson tcg_gen_br(l); 25137ed3bf1SRichard Henderson } else if (cond != TCG_COND_NEVER) { 252951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 25342a268c2SRichard Henderson tcg_gen_brcond_i32(cond, arg1, t0, l); 254951c6300SRichard Henderson tcg_temp_free_i32(t0); 255951c6300SRichard Henderson } 25637ed3bf1SRichard Henderson } 257951c6300SRichard Henderson 258951c6300SRichard Henderson void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret, 259951c6300SRichard Henderson TCGv_i32 arg1, TCGv_i32 arg2) 260951c6300SRichard Henderson { 261951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 262951c6300SRichard Henderson tcg_gen_movi_i32(ret, 1); 263951c6300SRichard Henderson } else if (cond == TCG_COND_NEVER) { 264951c6300SRichard Henderson tcg_gen_movi_i32(ret, 0); 265951c6300SRichard Henderson } else { 266951c6300SRichard Henderson tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond); 267951c6300SRichard Henderson } 268951c6300SRichard Henderson } 269951c6300SRichard Henderson 270951c6300SRichard Henderson void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret, 271951c6300SRichard Henderson TCGv_i32 arg1, int32_t arg2) 272951c6300SRichard Henderson { 273951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 274951c6300SRichard Henderson tcg_gen_setcond_i32(cond, ret, arg1, t0); 275951c6300SRichard Henderson tcg_temp_free_i32(t0); 276951c6300SRichard Henderson } 277951c6300SRichard Henderson 278951c6300SRichard Henderson void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) 279951c6300SRichard Henderson { 280b2e3ae94SRichard Henderson if (arg2 == 0) { 281b2e3ae94SRichard Henderson tcg_gen_movi_i32(ret, 0); 282b2e3ae94SRichard Henderson } else if (is_power_of_2(arg2)) { 283b2e3ae94SRichard Henderson tcg_gen_shli_i32(ret, arg1, ctz32(arg2)); 284b2e3ae94SRichard Henderson } else { 285951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 286951c6300SRichard Henderson tcg_gen_mul_i32(ret, arg1, t0); 287951c6300SRichard Henderson tcg_temp_free_i32(t0); 288951c6300SRichard Henderson } 289b2e3ae94SRichard Henderson } 290951c6300SRichard Henderson 291951c6300SRichard Henderson void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 292951c6300SRichard Henderson { 293951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i32) { 294951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2); 295951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 296951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 297951c6300SRichard Henderson tcg_gen_sari_i32(t0, arg1, 31); 298951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2); 299951c6300SRichard Henderson tcg_temp_free_i32(t0); 300951c6300SRichard Henderson } else { 301951c6300SRichard Henderson gen_helper_div_i32(ret, arg1, arg2); 302951c6300SRichard Henderson } 303951c6300SRichard Henderson } 304951c6300SRichard Henderson 305951c6300SRichard Henderson void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 306951c6300SRichard Henderson { 307951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i32) { 308951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2); 309951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i32) { 310951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 311951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_div_i32, t0, arg1, arg2); 312951c6300SRichard Henderson tcg_gen_mul_i32(t0, t0, arg2); 313951c6300SRichard Henderson tcg_gen_sub_i32(ret, arg1, t0); 314951c6300SRichard Henderson tcg_temp_free_i32(t0); 315951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 316951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 317951c6300SRichard Henderson tcg_gen_sari_i32(t0, arg1, 31); 318951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2); 319951c6300SRichard Henderson tcg_temp_free_i32(t0); 320951c6300SRichard Henderson } else { 321951c6300SRichard Henderson gen_helper_rem_i32(ret, arg1, arg2); 322951c6300SRichard Henderson } 323951c6300SRichard Henderson } 324951c6300SRichard Henderson 325951c6300SRichard Henderson void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 326951c6300SRichard Henderson { 327951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i32) { 328951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2); 329951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 330951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 331951c6300SRichard Henderson tcg_gen_movi_i32(t0, 0); 332951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2); 333951c6300SRichard Henderson tcg_temp_free_i32(t0); 334951c6300SRichard Henderson } else { 335951c6300SRichard Henderson gen_helper_divu_i32(ret, arg1, arg2); 336951c6300SRichard Henderson } 337951c6300SRichard Henderson } 338951c6300SRichard Henderson 339951c6300SRichard Henderson void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 340951c6300SRichard Henderson { 341951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i32) { 342951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2); 343951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i32) { 344951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 345951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_divu_i32, t0, arg1, arg2); 346951c6300SRichard Henderson tcg_gen_mul_i32(t0, t0, arg2); 347951c6300SRichard Henderson tcg_gen_sub_i32(ret, arg1, t0); 348951c6300SRichard Henderson tcg_temp_free_i32(t0); 349951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i32) { 350951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 351951c6300SRichard Henderson tcg_gen_movi_i32(t0, 0); 352951c6300SRichard Henderson tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2); 353951c6300SRichard Henderson tcg_temp_free_i32(t0); 354951c6300SRichard Henderson } else { 355951c6300SRichard Henderson gen_helper_remu_i32(ret, arg1, arg2); 356951c6300SRichard Henderson } 357951c6300SRichard Henderson } 358951c6300SRichard Henderson 359951c6300SRichard Henderson void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 360951c6300SRichard Henderson { 361951c6300SRichard Henderson if (TCG_TARGET_HAS_andc_i32) { 362951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2); 363951c6300SRichard Henderson } else { 364951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 365951c6300SRichard Henderson tcg_gen_not_i32(t0, arg2); 366951c6300SRichard Henderson tcg_gen_and_i32(ret, arg1, t0); 367951c6300SRichard Henderson tcg_temp_free_i32(t0); 368951c6300SRichard Henderson } 369951c6300SRichard Henderson } 370951c6300SRichard Henderson 371951c6300SRichard Henderson void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 372951c6300SRichard Henderson { 373951c6300SRichard Henderson if (TCG_TARGET_HAS_eqv_i32) { 374951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_eqv_i32, ret, arg1, arg2); 375951c6300SRichard Henderson } else { 376951c6300SRichard Henderson tcg_gen_xor_i32(ret, arg1, arg2); 377951c6300SRichard Henderson tcg_gen_not_i32(ret, ret); 378951c6300SRichard Henderson } 379951c6300SRichard Henderson } 380951c6300SRichard Henderson 381951c6300SRichard Henderson void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 382951c6300SRichard Henderson { 383951c6300SRichard Henderson if (TCG_TARGET_HAS_nand_i32) { 384951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_nand_i32, ret, arg1, arg2); 385951c6300SRichard Henderson } else { 386951c6300SRichard Henderson tcg_gen_and_i32(ret, arg1, arg2); 387951c6300SRichard Henderson tcg_gen_not_i32(ret, ret); 388951c6300SRichard Henderson } 389951c6300SRichard Henderson } 390951c6300SRichard Henderson 391951c6300SRichard Henderson void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 392951c6300SRichard Henderson { 393951c6300SRichard Henderson if (TCG_TARGET_HAS_nor_i32) { 394951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_nor_i32, ret, arg1, arg2); 395951c6300SRichard Henderson } else { 396951c6300SRichard Henderson tcg_gen_or_i32(ret, arg1, arg2); 397951c6300SRichard Henderson tcg_gen_not_i32(ret, ret); 398951c6300SRichard Henderson } 399951c6300SRichard Henderson } 400951c6300SRichard Henderson 401951c6300SRichard Henderson void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 402951c6300SRichard Henderson { 403951c6300SRichard Henderson if (TCG_TARGET_HAS_orc_i32) { 404951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2); 405951c6300SRichard Henderson } else { 406951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 407951c6300SRichard Henderson tcg_gen_not_i32(t0, arg2); 408951c6300SRichard Henderson tcg_gen_or_i32(ret, arg1, t0); 409951c6300SRichard Henderson tcg_temp_free_i32(t0); 410951c6300SRichard Henderson } 411951c6300SRichard Henderson } 412951c6300SRichard Henderson 4130e28d006SRichard Henderson void tcg_gen_clz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 4140e28d006SRichard Henderson { 4150e28d006SRichard Henderson if (TCG_TARGET_HAS_clz_i32) { 4160e28d006SRichard Henderson tcg_gen_op3_i32(INDEX_op_clz_i32, ret, arg1, arg2); 4170e28d006SRichard Henderson } else if (TCG_TARGET_HAS_clz_i64) { 4180e28d006SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 4190e28d006SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 4200e28d006SRichard Henderson tcg_gen_extu_i32_i64(t1, arg1); 4210e28d006SRichard Henderson tcg_gen_extu_i32_i64(t2, arg2); 4220e28d006SRichard Henderson tcg_gen_addi_i64(t2, t2, 32); 4230e28d006SRichard Henderson tcg_gen_clz_i64(t1, t1, t2); 4240e28d006SRichard Henderson tcg_gen_extrl_i64_i32(ret, t1); 4250e28d006SRichard Henderson tcg_temp_free_i64(t1); 4260e28d006SRichard Henderson tcg_temp_free_i64(t2); 4270e28d006SRichard Henderson tcg_gen_subi_i32(ret, ret, 32); 4280e28d006SRichard Henderson } else { 4290e28d006SRichard Henderson gen_helper_clz_i32(ret, arg1, arg2); 4300e28d006SRichard Henderson } 4310e28d006SRichard Henderson } 4320e28d006SRichard Henderson 4330e28d006SRichard Henderson void tcg_gen_clzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) 4340e28d006SRichard Henderson { 4350e28d006SRichard Henderson TCGv_i32 t = tcg_const_i32(arg2); 4360e28d006SRichard Henderson tcg_gen_clz_i32(ret, arg1, t); 4370e28d006SRichard Henderson tcg_temp_free_i32(t); 4380e28d006SRichard Henderson } 4390e28d006SRichard Henderson 4400e28d006SRichard Henderson void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 4410e28d006SRichard Henderson { 4420e28d006SRichard Henderson if (TCG_TARGET_HAS_ctz_i32) { 4430e28d006SRichard Henderson tcg_gen_op3_i32(INDEX_op_ctz_i32, ret, arg1, arg2); 4440e28d006SRichard Henderson } else if (TCG_TARGET_HAS_ctz_i64) { 4450e28d006SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 4460e28d006SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 4470e28d006SRichard Henderson tcg_gen_extu_i32_i64(t1, arg1); 4480e28d006SRichard Henderson tcg_gen_extu_i32_i64(t2, arg2); 4490e28d006SRichard Henderson tcg_gen_ctz_i64(t1, t1, t2); 4500e28d006SRichard Henderson tcg_gen_extrl_i64_i32(ret, t1); 4510e28d006SRichard Henderson tcg_temp_free_i64(t1); 4520e28d006SRichard Henderson tcg_temp_free_i64(t2); 45314e99210SRichard Henderson } else if (TCG_TARGET_HAS_ctpop_i32 45414e99210SRichard Henderson || TCG_TARGET_HAS_ctpop_i64 45514e99210SRichard Henderson || TCG_TARGET_HAS_clz_i32 45614e99210SRichard Henderson || TCG_TARGET_HAS_clz_i64) { 45714e99210SRichard Henderson TCGv_i32 z, t = tcg_temp_new_i32(); 45814e99210SRichard Henderson 45914e99210SRichard Henderson if (TCG_TARGET_HAS_ctpop_i32 || TCG_TARGET_HAS_ctpop_i64) { 46014e99210SRichard Henderson tcg_gen_subi_i32(t, arg1, 1); 46114e99210SRichard Henderson tcg_gen_andc_i32(t, t, arg1); 46214e99210SRichard Henderson tcg_gen_ctpop_i32(t, t); 46314e99210SRichard Henderson } else { 46414e99210SRichard Henderson /* Since all non-x86 hosts have clz(0) == 32, don't fight it. */ 46514e99210SRichard Henderson tcg_gen_neg_i32(t, arg1); 46614e99210SRichard Henderson tcg_gen_and_i32(t, t, arg1); 46714e99210SRichard Henderson tcg_gen_clzi_i32(t, t, 32); 46814e99210SRichard Henderson tcg_gen_xori_i32(t, t, 31); 46914e99210SRichard Henderson } 47014e99210SRichard Henderson z = tcg_const_i32(0); 47114e99210SRichard Henderson tcg_gen_movcond_i32(TCG_COND_EQ, ret, arg1, z, arg2, t); 47214e99210SRichard Henderson tcg_temp_free_i32(t); 47314e99210SRichard Henderson tcg_temp_free_i32(z); 4740e28d006SRichard Henderson } else { 4750e28d006SRichard Henderson gen_helper_ctz_i32(ret, arg1, arg2); 4760e28d006SRichard Henderson } 4770e28d006SRichard Henderson } 4780e28d006SRichard Henderson 4790e28d006SRichard Henderson void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) 4800e28d006SRichard Henderson { 48114e99210SRichard Henderson if (!TCG_TARGET_HAS_ctz_i32 && TCG_TARGET_HAS_ctpop_i32 && arg2 == 32) { 48214e99210SRichard Henderson /* This equivalence has the advantage of not requiring a fixup. */ 48314e99210SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 48414e99210SRichard Henderson tcg_gen_subi_i32(t, arg1, 1); 48514e99210SRichard Henderson tcg_gen_andc_i32(t, t, arg1); 48614e99210SRichard Henderson tcg_gen_ctpop_i32(ret, t); 48714e99210SRichard Henderson tcg_temp_free_i32(t); 48814e99210SRichard Henderson } else { 4890e28d006SRichard Henderson TCGv_i32 t = tcg_const_i32(arg2); 4900e28d006SRichard Henderson tcg_gen_ctz_i32(ret, arg1, t); 4910e28d006SRichard Henderson tcg_temp_free_i32(t); 4920e28d006SRichard Henderson } 49314e99210SRichard Henderson } 4940e28d006SRichard Henderson 495086920c2SRichard Henderson void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg) 496086920c2SRichard Henderson { 497086920c2SRichard Henderson if (TCG_TARGET_HAS_clz_i32) { 498086920c2SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 499086920c2SRichard Henderson tcg_gen_sari_i32(t, arg, 31); 500086920c2SRichard Henderson tcg_gen_xor_i32(t, t, arg); 501086920c2SRichard Henderson tcg_gen_clzi_i32(t, t, 32); 502086920c2SRichard Henderson tcg_gen_subi_i32(ret, t, 1); 503086920c2SRichard Henderson tcg_temp_free_i32(t); 504086920c2SRichard Henderson } else { 505086920c2SRichard Henderson gen_helper_clrsb_i32(ret, arg); 506086920c2SRichard Henderson } 507086920c2SRichard Henderson } 508086920c2SRichard Henderson 509a768e4e9SRichard Henderson void tcg_gen_ctpop_i32(TCGv_i32 ret, TCGv_i32 arg1) 510a768e4e9SRichard Henderson { 511a768e4e9SRichard Henderson if (TCG_TARGET_HAS_ctpop_i32) { 512a768e4e9SRichard Henderson tcg_gen_op2_i32(INDEX_op_ctpop_i32, ret, arg1); 513a768e4e9SRichard Henderson } else if (TCG_TARGET_HAS_ctpop_i64) { 514a768e4e9SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 515a768e4e9SRichard Henderson tcg_gen_extu_i32_i64(t, arg1); 516a768e4e9SRichard Henderson tcg_gen_ctpop_i64(t, t); 517a768e4e9SRichard Henderson tcg_gen_extrl_i64_i32(ret, t); 518a768e4e9SRichard Henderson tcg_temp_free_i64(t); 519a768e4e9SRichard Henderson } else { 520a768e4e9SRichard Henderson gen_helper_ctpop_i32(ret, arg1); 521a768e4e9SRichard Henderson } 522a768e4e9SRichard Henderson } 523a768e4e9SRichard Henderson 524951c6300SRichard Henderson void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 525951c6300SRichard Henderson { 526951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i32) { 527951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2); 528951c6300SRichard Henderson } else { 529951c6300SRichard Henderson TCGv_i32 t0, t1; 530951c6300SRichard Henderson 531951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 532951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 533951c6300SRichard Henderson tcg_gen_shl_i32(t0, arg1, arg2); 534951c6300SRichard Henderson tcg_gen_subfi_i32(t1, 32, arg2); 535951c6300SRichard Henderson tcg_gen_shr_i32(t1, arg1, t1); 536951c6300SRichard Henderson tcg_gen_or_i32(ret, t0, t1); 537951c6300SRichard Henderson tcg_temp_free_i32(t0); 538951c6300SRichard Henderson tcg_temp_free_i32(t1); 539951c6300SRichard Henderson } 540951c6300SRichard Henderson } 541951c6300SRichard Henderson 542951c6300SRichard Henderson void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2) 543951c6300SRichard Henderson { 544951c6300SRichard Henderson tcg_debug_assert(arg2 < 32); 545951c6300SRichard Henderson /* some cases can be optimized here */ 546951c6300SRichard Henderson if (arg2 == 0) { 547951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 548951c6300SRichard Henderson } else if (TCG_TARGET_HAS_rot_i32) { 549951c6300SRichard Henderson TCGv_i32 t0 = tcg_const_i32(arg2); 550951c6300SRichard Henderson tcg_gen_rotl_i32(ret, arg1, t0); 551951c6300SRichard Henderson tcg_temp_free_i32(t0); 552951c6300SRichard Henderson } else { 553951c6300SRichard Henderson TCGv_i32 t0, t1; 554951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 555951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 556951c6300SRichard Henderson tcg_gen_shli_i32(t0, arg1, arg2); 557951c6300SRichard Henderson tcg_gen_shri_i32(t1, arg1, 32 - arg2); 558951c6300SRichard Henderson tcg_gen_or_i32(ret, t0, t1); 559951c6300SRichard Henderson tcg_temp_free_i32(t0); 560951c6300SRichard Henderson tcg_temp_free_i32(t1); 561951c6300SRichard Henderson } 562951c6300SRichard Henderson } 563951c6300SRichard Henderson 564951c6300SRichard Henderson void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 565951c6300SRichard Henderson { 566951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i32) { 567951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2); 568951c6300SRichard Henderson } else { 569951c6300SRichard Henderson TCGv_i32 t0, t1; 570951c6300SRichard Henderson 571951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 572951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 573951c6300SRichard Henderson tcg_gen_shr_i32(t0, arg1, arg2); 574951c6300SRichard Henderson tcg_gen_subfi_i32(t1, 32, arg2); 575951c6300SRichard Henderson tcg_gen_shl_i32(t1, arg1, t1); 576951c6300SRichard Henderson tcg_gen_or_i32(ret, t0, t1); 577951c6300SRichard Henderson tcg_temp_free_i32(t0); 578951c6300SRichard Henderson tcg_temp_free_i32(t1); 579951c6300SRichard Henderson } 580951c6300SRichard Henderson } 581951c6300SRichard Henderson 582951c6300SRichard Henderson void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2) 583951c6300SRichard Henderson { 584951c6300SRichard Henderson tcg_debug_assert(arg2 < 32); 585951c6300SRichard Henderson /* some cases can be optimized here */ 586951c6300SRichard Henderson if (arg2 == 0) { 587951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg1); 588951c6300SRichard Henderson } else { 589951c6300SRichard Henderson tcg_gen_rotli_i32(ret, arg1, 32 - arg2); 590951c6300SRichard Henderson } 591951c6300SRichard Henderson } 592951c6300SRichard Henderson 593951c6300SRichard Henderson void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2, 594951c6300SRichard Henderson unsigned int ofs, unsigned int len) 595951c6300SRichard Henderson { 596951c6300SRichard Henderson uint32_t mask; 597951c6300SRichard Henderson TCGv_i32 t1; 598951c6300SRichard Henderson 599951c6300SRichard Henderson tcg_debug_assert(ofs < 32); 6000d0d309dSRichard Henderson tcg_debug_assert(len > 0); 601951c6300SRichard Henderson tcg_debug_assert(len <= 32); 602951c6300SRichard Henderson tcg_debug_assert(ofs + len <= 32); 603951c6300SRichard Henderson 6040d0d309dSRichard Henderson if (len == 32) { 605951c6300SRichard Henderson tcg_gen_mov_i32(ret, arg2); 606951c6300SRichard Henderson return; 607951c6300SRichard Henderson } 608951c6300SRichard Henderson if (TCG_TARGET_HAS_deposit_i32 && TCG_TARGET_deposit_i32_valid(ofs, len)) { 609951c6300SRichard Henderson tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len); 610951c6300SRichard Henderson return; 611951c6300SRichard Henderson } 612951c6300SRichard Henderson 613951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 614951c6300SRichard Henderson 615b0a60567SRichard Henderson if (TCG_TARGET_HAS_extract2_i32) { 616b0a60567SRichard Henderson if (ofs + len == 32) { 617b0a60567SRichard Henderson tcg_gen_shli_i32(t1, arg1, len); 618b0a60567SRichard Henderson tcg_gen_extract2_i32(ret, t1, arg2, len); 619b0a60567SRichard Henderson goto done; 620b0a60567SRichard Henderson } 621b0a60567SRichard Henderson if (ofs == 0) { 622b0a60567SRichard Henderson tcg_gen_extract2_i32(ret, arg1, arg2, len); 623b0a60567SRichard Henderson tcg_gen_rotli_i32(ret, ret, len); 624b0a60567SRichard Henderson goto done; 625b0a60567SRichard Henderson } 626b0a60567SRichard Henderson } 627b0a60567SRichard Henderson 628b0a60567SRichard Henderson mask = (1u << len) - 1; 629951c6300SRichard Henderson if (ofs + len < 32) { 630951c6300SRichard Henderson tcg_gen_andi_i32(t1, arg2, mask); 631951c6300SRichard Henderson tcg_gen_shli_i32(t1, t1, ofs); 632951c6300SRichard Henderson } else { 633951c6300SRichard Henderson tcg_gen_shli_i32(t1, arg2, ofs); 634951c6300SRichard Henderson } 635951c6300SRichard Henderson tcg_gen_andi_i32(ret, arg1, ~(mask << ofs)); 636951c6300SRichard Henderson tcg_gen_or_i32(ret, ret, t1); 637b0a60567SRichard Henderson done: 638951c6300SRichard Henderson tcg_temp_free_i32(t1); 639951c6300SRichard Henderson } 640951c6300SRichard Henderson 64107cc68d5SRichard Henderson void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg, 64207cc68d5SRichard Henderson unsigned int ofs, unsigned int len) 64307cc68d5SRichard Henderson { 64407cc68d5SRichard Henderson tcg_debug_assert(ofs < 32); 64507cc68d5SRichard Henderson tcg_debug_assert(len > 0); 64607cc68d5SRichard Henderson tcg_debug_assert(len <= 32); 64707cc68d5SRichard Henderson tcg_debug_assert(ofs + len <= 32); 64807cc68d5SRichard Henderson 64907cc68d5SRichard Henderson if (ofs + len == 32) { 65007cc68d5SRichard Henderson tcg_gen_shli_i32(ret, arg, ofs); 65107cc68d5SRichard Henderson } else if (ofs == 0) { 65207cc68d5SRichard Henderson tcg_gen_andi_i32(ret, arg, (1u << len) - 1); 65307cc68d5SRichard Henderson } else if (TCG_TARGET_HAS_deposit_i32 65407cc68d5SRichard Henderson && TCG_TARGET_deposit_i32_valid(ofs, len)) { 65507cc68d5SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 65607cc68d5SRichard Henderson tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, zero, arg, ofs, len); 65707cc68d5SRichard Henderson tcg_temp_free_i32(zero); 65807cc68d5SRichard Henderson } else { 65907cc68d5SRichard Henderson /* To help two-operand hosts we prefer to zero-extend first, 66007cc68d5SRichard Henderson which allows ARG to stay live. */ 66107cc68d5SRichard Henderson switch (len) { 66207cc68d5SRichard Henderson case 16: 66307cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 66407cc68d5SRichard Henderson tcg_gen_ext16u_i32(ret, arg); 66507cc68d5SRichard Henderson tcg_gen_shli_i32(ret, ret, ofs); 66607cc68d5SRichard Henderson return; 66707cc68d5SRichard Henderson } 66807cc68d5SRichard Henderson break; 66907cc68d5SRichard Henderson case 8: 67007cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 67107cc68d5SRichard Henderson tcg_gen_ext8u_i32(ret, arg); 67207cc68d5SRichard Henderson tcg_gen_shli_i32(ret, ret, ofs); 67307cc68d5SRichard Henderson return; 67407cc68d5SRichard Henderson } 67507cc68d5SRichard Henderson break; 67607cc68d5SRichard Henderson } 67707cc68d5SRichard Henderson /* Otherwise prefer zero-extension over AND for code size. */ 67807cc68d5SRichard Henderson switch (ofs + len) { 67907cc68d5SRichard Henderson case 16: 68007cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 68107cc68d5SRichard Henderson tcg_gen_shli_i32(ret, arg, ofs); 68207cc68d5SRichard Henderson tcg_gen_ext16u_i32(ret, ret); 68307cc68d5SRichard Henderson return; 68407cc68d5SRichard Henderson } 68507cc68d5SRichard Henderson break; 68607cc68d5SRichard Henderson case 8: 68707cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 68807cc68d5SRichard Henderson tcg_gen_shli_i32(ret, arg, ofs); 68907cc68d5SRichard Henderson tcg_gen_ext8u_i32(ret, ret); 69007cc68d5SRichard Henderson return; 69107cc68d5SRichard Henderson } 69207cc68d5SRichard Henderson break; 69307cc68d5SRichard Henderson } 69407cc68d5SRichard Henderson tcg_gen_andi_i32(ret, arg, (1u << len) - 1); 69507cc68d5SRichard Henderson tcg_gen_shli_i32(ret, ret, ofs); 69607cc68d5SRichard Henderson } 69707cc68d5SRichard Henderson } 69807cc68d5SRichard Henderson 6997ec8bab3SRichard Henderson void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg, 7007ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 7017ec8bab3SRichard Henderson { 7027ec8bab3SRichard Henderson tcg_debug_assert(ofs < 32); 7037ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 7047ec8bab3SRichard Henderson tcg_debug_assert(len <= 32); 7057ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 32); 7067ec8bab3SRichard Henderson 7077ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if extract is supported. */ 7087ec8bab3SRichard Henderson if (ofs + len == 32) { 7097ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, 32 - len); 7107ec8bab3SRichard Henderson return; 7117ec8bab3SRichard Henderson } 7127ec8bab3SRichard Henderson if (ofs == 0) { 7137ec8bab3SRichard Henderson tcg_gen_andi_i32(ret, arg, (1u << len) - 1); 7147ec8bab3SRichard Henderson return; 7157ec8bab3SRichard Henderson } 7167ec8bab3SRichard Henderson 7177ec8bab3SRichard Henderson if (TCG_TARGET_HAS_extract_i32 7187ec8bab3SRichard Henderson && TCG_TARGET_extract_i32_valid(ofs, len)) { 7197ec8bab3SRichard Henderson tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, ofs, len); 7207ec8bab3SRichard Henderson return; 7217ec8bab3SRichard Henderson } 7227ec8bab3SRichard Henderson 7237ec8bab3SRichard Henderson /* Assume that zero-extension, if available, is cheaper than a shift. */ 7247ec8bab3SRichard Henderson switch (ofs + len) { 7257ec8bab3SRichard Henderson case 16: 7267ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 7277ec8bab3SRichard Henderson tcg_gen_ext16u_i32(ret, arg); 7287ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, ret, ofs); 7297ec8bab3SRichard Henderson return; 7307ec8bab3SRichard Henderson } 7317ec8bab3SRichard Henderson break; 7327ec8bab3SRichard Henderson case 8: 7337ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 7347ec8bab3SRichard Henderson tcg_gen_ext8u_i32(ret, arg); 7357ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, ret, ofs); 7367ec8bab3SRichard Henderson return; 7377ec8bab3SRichard Henderson } 7387ec8bab3SRichard Henderson break; 7397ec8bab3SRichard Henderson } 7407ec8bab3SRichard Henderson 7417ec8bab3SRichard Henderson /* ??? Ideally we'd know what values are available for immediate AND. 7427ec8bab3SRichard Henderson Assume that 8 bits are available, plus the special case of 16, 7437ec8bab3SRichard Henderson so that we get ext8u, ext16u. */ 7447ec8bab3SRichard Henderson switch (len) { 7457ec8bab3SRichard Henderson case 1 ... 8: case 16: 7467ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, ofs); 7477ec8bab3SRichard Henderson tcg_gen_andi_i32(ret, ret, (1u << len) - 1); 7487ec8bab3SRichard Henderson break; 7497ec8bab3SRichard Henderson default: 7507ec8bab3SRichard Henderson tcg_gen_shli_i32(ret, arg, 32 - len - ofs); 7517ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, ret, 32 - len); 7527ec8bab3SRichard Henderson break; 7537ec8bab3SRichard Henderson } 7547ec8bab3SRichard Henderson } 7557ec8bab3SRichard Henderson 7567ec8bab3SRichard Henderson void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg, 7577ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 7587ec8bab3SRichard Henderson { 7597ec8bab3SRichard Henderson tcg_debug_assert(ofs < 32); 7607ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 7617ec8bab3SRichard Henderson tcg_debug_assert(len <= 32); 7627ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 32); 7637ec8bab3SRichard Henderson 7647ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if extract is supported. */ 7657ec8bab3SRichard Henderson if (ofs + len == 32) { 7667ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, arg, 32 - len); 7677ec8bab3SRichard Henderson return; 7687ec8bab3SRichard Henderson } 7697ec8bab3SRichard Henderson if (ofs == 0) { 7707ec8bab3SRichard Henderson switch (len) { 7717ec8bab3SRichard Henderson case 16: 7727ec8bab3SRichard Henderson tcg_gen_ext16s_i32(ret, arg); 7737ec8bab3SRichard Henderson return; 7747ec8bab3SRichard Henderson case 8: 7757ec8bab3SRichard Henderson tcg_gen_ext8s_i32(ret, arg); 7767ec8bab3SRichard Henderson return; 7777ec8bab3SRichard Henderson } 7787ec8bab3SRichard Henderson } 7797ec8bab3SRichard Henderson 7807ec8bab3SRichard Henderson if (TCG_TARGET_HAS_sextract_i32 7817ec8bab3SRichard Henderson && TCG_TARGET_extract_i32_valid(ofs, len)) { 7827ec8bab3SRichard Henderson tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, ofs, len); 7837ec8bab3SRichard Henderson return; 7847ec8bab3SRichard Henderson } 7857ec8bab3SRichard Henderson 7867ec8bab3SRichard Henderson /* Assume that sign-extension, if available, is cheaper than a shift. */ 7877ec8bab3SRichard Henderson switch (ofs + len) { 7887ec8bab3SRichard Henderson case 16: 7897ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i32) { 7907ec8bab3SRichard Henderson tcg_gen_ext16s_i32(ret, arg); 7917ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, ret, ofs); 7927ec8bab3SRichard Henderson return; 7937ec8bab3SRichard Henderson } 7947ec8bab3SRichard Henderson break; 7957ec8bab3SRichard Henderson case 8: 7967ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i32) { 7977ec8bab3SRichard Henderson tcg_gen_ext8s_i32(ret, arg); 7987ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, ret, ofs); 7997ec8bab3SRichard Henderson return; 8007ec8bab3SRichard Henderson } 8017ec8bab3SRichard Henderson break; 8027ec8bab3SRichard Henderson } 8037ec8bab3SRichard Henderson switch (len) { 8047ec8bab3SRichard Henderson case 16: 8057ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i32) { 8067ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, ofs); 8077ec8bab3SRichard Henderson tcg_gen_ext16s_i32(ret, ret); 8087ec8bab3SRichard Henderson return; 8097ec8bab3SRichard Henderson } 8107ec8bab3SRichard Henderson break; 8117ec8bab3SRichard Henderson case 8: 8127ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i32) { 8137ec8bab3SRichard Henderson tcg_gen_shri_i32(ret, arg, ofs); 8147ec8bab3SRichard Henderson tcg_gen_ext8s_i32(ret, ret); 8157ec8bab3SRichard Henderson return; 8167ec8bab3SRichard Henderson } 8177ec8bab3SRichard Henderson break; 8187ec8bab3SRichard Henderson } 8197ec8bab3SRichard Henderson 8207ec8bab3SRichard Henderson tcg_gen_shli_i32(ret, arg, 32 - len - ofs); 8217ec8bab3SRichard Henderson tcg_gen_sari_i32(ret, ret, 32 - len); 8227ec8bab3SRichard Henderson } 8237ec8bab3SRichard Henderson 8242089fcc9SDavid Hildenbrand /* 8252089fcc9SDavid Hildenbrand * Extract 32-bits from a 64-bit input, ah:al, starting from ofs. 8262089fcc9SDavid Hildenbrand * Unlike tcg_gen_extract_i32 above, len is fixed at 32. 8272089fcc9SDavid Hildenbrand */ 8282089fcc9SDavid Hildenbrand void tcg_gen_extract2_i32(TCGv_i32 ret, TCGv_i32 al, TCGv_i32 ah, 8292089fcc9SDavid Hildenbrand unsigned int ofs) 8302089fcc9SDavid Hildenbrand { 8312089fcc9SDavid Hildenbrand tcg_debug_assert(ofs <= 32); 8322089fcc9SDavid Hildenbrand if (ofs == 0) { 8332089fcc9SDavid Hildenbrand tcg_gen_mov_i32(ret, al); 8342089fcc9SDavid Hildenbrand } else if (ofs == 32) { 8352089fcc9SDavid Hildenbrand tcg_gen_mov_i32(ret, ah); 8362089fcc9SDavid Hildenbrand } else if (al == ah) { 8372089fcc9SDavid Hildenbrand tcg_gen_rotri_i32(ret, al, ofs); 838fce1296fSRichard Henderson } else if (TCG_TARGET_HAS_extract2_i32) { 839fce1296fSRichard Henderson tcg_gen_op4i_i32(INDEX_op_extract2_i32, ret, al, ah, ofs); 8402089fcc9SDavid Hildenbrand } else { 8412089fcc9SDavid Hildenbrand TCGv_i32 t0 = tcg_temp_new_i32(); 8422089fcc9SDavid Hildenbrand tcg_gen_shri_i32(t0, al, ofs); 8432089fcc9SDavid Hildenbrand tcg_gen_deposit_i32(ret, t0, ah, 32 - ofs, ofs); 8442089fcc9SDavid Hildenbrand tcg_temp_free_i32(t0); 8452089fcc9SDavid Hildenbrand } 8462089fcc9SDavid Hildenbrand } 8472089fcc9SDavid Hildenbrand 848951c6300SRichard Henderson void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1, 849951c6300SRichard Henderson TCGv_i32 c2, TCGv_i32 v1, TCGv_i32 v2) 850951c6300SRichard Henderson { 85137ed3bf1SRichard Henderson if (cond == TCG_COND_ALWAYS) { 85237ed3bf1SRichard Henderson tcg_gen_mov_i32(ret, v1); 85337ed3bf1SRichard Henderson } else if (cond == TCG_COND_NEVER) { 85437ed3bf1SRichard Henderson tcg_gen_mov_i32(ret, v2); 85537ed3bf1SRichard Henderson } else if (TCG_TARGET_HAS_movcond_i32) { 856951c6300SRichard Henderson tcg_gen_op6i_i32(INDEX_op_movcond_i32, ret, c1, c2, v1, v2, cond); 857951c6300SRichard Henderson } else { 858951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 859951c6300SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 860951c6300SRichard Henderson tcg_gen_setcond_i32(cond, t0, c1, c2); 861951c6300SRichard Henderson tcg_gen_neg_i32(t0, t0); 862951c6300SRichard Henderson tcg_gen_and_i32(t1, v1, t0); 863951c6300SRichard Henderson tcg_gen_andc_i32(ret, v2, t0); 864951c6300SRichard Henderson tcg_gen_or_i32(ret, ret, t1); 865951c6300SRichard Henderson tcg_temp_free_i32(t0); 866951c6300SRichard Henderson tcg_temp_free_i32(t1); 867951c6300SRichard Henderson } 868951c6300SRichard Henderson } 869951c6300SRichard Henderson 870951c6300SRichard Henderson void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, 871951c6300SRichard Henderson TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) 872951c6300SRichard Henderson { 873951c6300SRichard Henderson if (TCG_TARGET_HAS_add2_i32) { 874951c6300SRichard Henderson tcg_gen_op6_i32(INDEX_op_add2_i32, rl, rh, al, ah, bl, bh); 875951c6300SRichard Henderson } else { 876951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 877951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 878951c6300SRichard Henderson tcg_gen_concat_i32_i64(t0, al, ah); 879951c6300SRichard Henderson tcg_gen_concat_i32_i64(t1, bl, bh); 880951c6300SRichard Henderson tcg_gen_add_i64(t0, t0, t1); 881951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 882951c6300SRichard Henderson tcg_temp_free_i64(t0); 883951c6300SRichard Henderson tcg_temp_free_i64(t1); 884951c6300SRichard Henderson } 885951c6300SRichard Henderson } 886951c6300SRichard Henderson 887951c6300SRichard Henderson void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, 888951c6300SRichard Henderson TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) 889951c6300SRichard Henderson { 890951c6300SRichard Henderson if (TCG_TARGET_HAS_sub2_i32) { 891951c6300SRichard Henderson tcg_gen_op6_i32(INDEX_op_sub2_i32, rl, rh, al, ah, bl, bh); 892951c6300SRichard Henderson } else { 893951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 894951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 895951c6300SRichard Henderson tcg_gen_concat_i32_i64(t0, al, ah); 896951c6300SRichard Henderson tcg_gen_concat_i32_i64(t1, bl, bh); 897951c6300SRichard Henderson tcg_gen_sub_i64(t0, t0, t1); 898951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 899951c6300SRichard Henderson tcg_temp_free_i64(t0); 900951c6300SRichard Henderson tcg_temp_free_i64(t1); 901951c6300SRichard Henderson } 902951c6300SRichard Henderson } 903951c6300SRichard Henderson 904951c6300SRichard Henderson void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) 905951c6300SRichard Henderson { 906951c6300SRichard Henderson if (TCG_TARGET_HAS_mulu2_i32) { 907951c6300SRichard Henderson tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2); 908951c6300SRichard Henderson } else if (TCG_TARGET_HAS_muluh_i32) { 909951c6300SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 910951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2); 911951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_muluh_i32, rh, arg1, arg2); 912951c6300SRichard Henderson tcg_gen_mov_i32(rl, t); 913951c6300SRichard Henderson tcg_temp_free_i32(t); 914951c6300SRichard Henderson } else { 915951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 916951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 917951c6300SRichard Henderson tcg_gen_extu_i32_i64(t0, arg1); 918951c6300SRichard Henderson tcg_gen_extu_i32_i64(t1, arg2); 919951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, t1); 920951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 921951c6300SRichard Henderson tcg_temp_free_i64(t0); 922951c6300SRichard Henderson tcg_temp_free_i64(t1); 923951c6300SRichard Henderson } 924951c6300SRichard Henderson } 925951c6300SRichard Henderson 926951c6300SRichard Henderson void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) 927951c6300SRichard Henderson { 928951c6300SRichard Henderson if (TCG_TARGET_HAS_muls2_i32) { 929951c6300SRichard Henderson tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2); 930951c6300SRichard Henderson } else if (TCG_TARGET_HAS_mulsh_i32) { 931951c6300SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 932951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2); 933951c6300SRichard Henderson tcg_gen_op3_i32(INDEX_op_mulsh_i32, rh, arg1, arg2); 934951c6300SRichard Henderson tcg_gen_mov_i32(rl, t); 935951c6300SRichard Henderson tcg_temp_free_i32(t); 936951c6300SRichard Henderson } else if (TCG_TARGET_REG_BITS == 32) { 937951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 938951c6300SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 939951c6300SRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 940951c6300SRichard Henderson TCGv_i32 t3 = tcg_temp_new_i32(); 941951c6300SRichard Henderson tcg_gen_mulu2_i32(t0, t1, arg1, arg2); 942951c6300SRichard Henderson /* Adjust for negative inputs. */ 943951c6300SRichard Henderson tcg_gen_sari_i32(t2, arg1, 31); 944951c6300SRichard Henderson tcg_gen_sari_i32(t3, arg2, 31); 945951c6300SRichard Henderson tcg_gen_and_i32(t2, t2, arg2); 946951c6300SRichard Henderson tcg_gen_and_i32(t3, t3, arg1); 947951c6300SRichard Henderson tcg_gen_sub_i32(rh, t1, t2); 948951c6300SRichard Henderson tcg_gen_sub_i32(rh, rh, t3); 949951c6300SRichard Henderson tcg_gen_mov_i32(rl, t0); 950951c6300SRichard Henderson tcg_temp_free_i32(t0); 951951c6300SRichard Henderson tcg_temp_free_i32(t1); 952951c6300SRichard Henderson tcg_temp_free_i32(t2); 953951c6300SRichard Henderson tcg_temp_free_i32(t3); 954951c6300SRichard Henderson } else { 955951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 956951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 957951c6300SRichard Henderson tcg_gen_ext_i32_i64(t0, arg1); 958951c6300SRichard Henderson tcg_gen_ext_i32_i64(t1, arg2); 959951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, t1); 960951c6300SRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 961951c6300SRichard Henderson tcg_temp_free_i64(t0); 962951c6300SRichard Henderson tcg_temp_free_i64(t1); 963951c6300SRichard Henderson } 964951c6300SRichard Henderson } 965951c6300SRichard Henderson 9665087abfbSRichard Henderson void tcg_gen_mulsu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) 9675087abfbSRichard Henderson { 9685087abfbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 9695087abfbSRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 9705087abfbSRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 9715087abfbSRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 9725087abfbSRichard Henderson tcg_gen_mulu2_i32(t0, t1, arg1, arg2); 9735087abfbSRichard Henderson /* Adjust for negative input for the signed arg1. */ 9745087abfbSRichard Henderson tcg_gen_sari_i32(t2, arg1, 31); 9755087abfbSRichard Henderson tcg_gen_and_i32(t2, t2, arg2); 9765087abfbSRichard Henderson tcg_gen_sub_i32(rh, t1, t2); 9775087abfbSRichard Henderson tcg_gen_mov_i32(rl, t0); 9785087abfbSRichard Henderson tcg_temp_free_i32(t0); 9795087abfbSRichard Henderson tcg_temp_free_i32(t1); 9805087abfbSRichard Henderson tcg_temp_free_i32(t2); 9815087abfbSRichard Henderson } else { 9825087abfbSRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 9835087abfbSRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 9845087abfbSRichard Henderson tcg_gen_ext_i32_i64(t0, arg1); 9855087abfbSRichard Henderson tcg_gen_extu_i32_i64(t1, arg2); 9865087abfbSRichard Henderson tcg_gen_mul_i64(t0, t0, t1); 9875087abfbSRichard Henderson tcg_gen_extr_i64_i32(rl, rh, t0); 9885087abfbSRichard Henderson tcg_temp_free_i64(t0); 9895087abfbSRichard Henderson tcg_temp_free_i64(t1); 9905087abfbSRichard Henderson } 9915087abfbSRichard Henderson } 9925087abfbSRichard Henderson 993951c6300SRichard Henderson void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg) 994951c6300SRichard Henderson { 995951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8s_i32) { 996951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg); 997951c6300SRichard Henderson } else { 998951c6300SRichard Henderson tcg_gen_shli_i32(ret, arg, 24); 999951c6300SRichard Henderson tcg_gen_sari_i32(ret, ret, 24); 1000951c6300SRichard Henderson } 1001951c6300SRichard Henderson } 1002951c6300SRichard Henderson 1003951c6300SRichard Henderson void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg) 1004951c6300SRichard Henderson { 1005951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16s_i32) { 1006951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg); 1007951c6300SRichard Henderson } else { 1008951c6300SRichard Henderson tcg_gen_shli_i32(ret, arg, 16); 1009951c6300SRichard Henderson tcg_gen_sari_i32(ret, ret, 16); 1010951c6300SRichard Henderson } 1011951c6300SRichard Henderson } 1012951c6300SRichard Henderson 1013951c6300SRichard Henderson void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg) 1014951c6300SRichard Henderson { 1015951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8u_i32) { 1016951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg); 1017951c6300SRichard Henderson } else { 1018951c6300SRichard Henderson tcg_gen_andi_i32(ret, arg, 0xffu); 1019951c6300SRichard Henderson } 1020951c6300SRichard Henderson } 1021951c6300SRichard Henderson 1022951c6300SRichard Henderson void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg) 1023951c6300SRichard Henderson { 1024951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16u_i32) { 1025951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg); 1026951c6300SRichard Henderson } else { 1027951c6300SRichard Henderson tcg_gen_andi_i32(ret, arg, 0xffffu); 1028951c6300SRichard Henderson } 1029951c6300SRichard Henderson } 1030951c6300SRichard Henderson 1031951c6300SRichard Henderson /* Note: we assume the two high bytes are set to zero */ 1032951c6300SRichard Henderson void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg) 1033951c6300SRichard Henderson { 1034951c6300SRichard Henderson if (TCG_TARGET_HAS_bswap16_i32) { 1035951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg); 1036951c6300SRichard Henderson } else { 1037951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 1038951c6300SRichard Henderson 1039951c6300SRichard Henderson tcg_gen_ext8u_i32(t0, arg); 1040951c6300SRichard Henderson tcg_gen_shli_i32(t0, t0, 8); 1041951c6300SRichard Henderson tcg_gen_shri_i32(ret, arg, 8); 1042951c6300SRichard Henderson tcg_gen_or_i32(ret, ret, t0); 1043951c6300SRichard Henderson tcg_temp_free_i32(t0); 1044951c6300SRichard Henderson } 1045951c6300SRichard Henderson } 1046951c6300SRichard Henderson 1047951c6300SRichard Henderson void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) 1048951c6300SRichard Henderson { 1049951c6300SRichard Henderson if (TCG_TARGET_HAS_bswap32_i32) { 1050951c6300SRichard Henderson tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg); 1051951c6300SRichard Henderson } else { 1052a686dc71SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 1053a686dc71SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 1054a686dc71SRichard Henderson TCGv_i32 t2 = tcg_const_i32(0x00ff00ff); 1055951c6300SRichard Henderson 1056a686dc71SRichard Henderson /* arg = abcd */ 1057a686dc71SRichard Henderson tcg_gen_shri_i32(t0, arg, 8); /* t0 = .abc */ 1058a686dc71SRichard Henderson tcg_gen_and_i32(t1, arg, t2); /* t1 = .b.d */ 1059a686dc71SRichard Henderson tcg_gen_and_i32(t0, t0, t2); /* t0 = .a.c */ 1060a686dc71SRichard Henderson tcg_gen_shli_i32(t1, t1, 8); /* t1 = b.d. */ 1061a686dc71SRichard Henderson tcg_gen_or_i32(ret, t0, t1); /* ret = badc */ 1062951c6300SRichard Henderson 1063a686dc71SRichard Henderson tcg_gen_shri_i32(t0, ret, 16); /* t0 = ..ba */ 1064a686dc71SRichard Henderson tcg_gen_shli_i32(t1, ret, 16); /* t1 = dc.. */ 1065a686dc71SRichard Henderson tcg_gen_or_i32(ret, t0, t1); /* ret = dcba */ 1066951c6300SRichard Henderson 1067951c6300SRichard Henderson tcg_temp_free_i32(t0); 1068951c6300SRichard Henderson tcg_temp_free_i32(t1); 1069a686dc71SRichard Henderson tcg_temp_free_i32(t2); 1070951c6300SRichard Henderson } 1071951c6300SRichard Henderson } 1072951c6300SRichard Henderson 1073b87fb8cdSRichard Henderson void tcg_gen_smin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1074b87fb8cdSRichard Henderson { 1075b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, a, b); 1076b87fb8cdSRichard Henderson } 1077b87fb8cdSRichard Henderson 1078b87fb8cdSRichard Henderson void tcg_gen_umin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1079b87fb8cdSRichard Henderson { 1080b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, a, b); 1081b87fb8cdSRichard Henderson } 1082b87fb8cdSRichard Henderson 1083b87fb8cdSRichard Henderson void tcg_gen_smax_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1084b87fb8cdSRichard Henderson { 1085b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, b, a); 1086b87fb8cdSRichard Henderson } 1087b87fb8cdSRichard Henderson 1088b87fb8cdSRichard Henderson void tcg_gen_umax_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) 1089b87fb8cdSRichard Henderson { 1090b87fb8cdSRichard Henderson tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, b, a); 1091b87fb8cdSRichard Henderson } 1092b87fb8cdSRichard Henderson 1093ff1f11f7SRichard Henderson void tcg_gen_abs_i32(TCGv_i32 ret, TCGv_i32 a) 1094ff1f11f7SRichard Henderson { 1095ff1f11f7SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 1096ff1f11f7SRichard Henderson 1097ff1f11f7SRichard Henderson tcg_gen_sari_i32(t, a, 31); 1098ff1f11f7SRichard Henderson tcg_gen_xor_i32(ret, a, t); 1099ff1f11f7SRichard Henderson tcg_gen_sub_i32(ret, ret, t); 1100ff1f11f7SRichard Henderson tcg_temp_free_i32(t); 1101ff1f11f7SRichard Henderson } 1102ff1f11f7SRichard Henderson 1103951c6300SRichard Henderson /* 64-bit ops */ 1104951c6300SRichard Henderson 1105951c6300SRichard Henderson #if TCG_TARGET_REG_BITS == 32 1106951c6300SRichard Henderson /* These are all inline for TCG_TARGET_REG_BITS == 64. */ 1107951c6300SRichard Henderson 1108951c6300SRichard Henderson void tcg_gen_discard_i64(TCGv_i64 arg) 1109951c6300SRichard Henderson { 1110951c6300SRichard Henderson tcg_gen_discard_i32(TCGV_LOW(arg)); 1111951c6300SRichard Henderson tcg_gen_discard_i32(TCGV_HIGH(arg)); 1112951c6300SRichard Henderson } 1113951c6300SRichard Henderson 1114951c6300SRichard Henderson void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg) 1115951c6300SRichard Henderson { 1116951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1117951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); 1118951c6300SRichard Henderson } 1119951c6300SRichard Henderson 1120951c6300SRichard Henderson void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg) 1121951c6300SRichard Henderson { 1122951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_LOW(ret), arg); 1123951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32); 1124951c6300SRichard Henderson } 1125951c6300SRichard Henderson 1126951c6300SRichard Henderson void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1127951c6300SRichard Henderson { 1128951c6300SRichard Henderson tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset); 1129951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1130951c6300SRichard Henderson } 1131951c6300SRichard Henderson 1132951c6300SRichard Henderson void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1133951c6300SRichard Henderson { 1134951c6300SRichard Henderson tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset); 11353ff91d7eSJoseph Myers tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 1136951c6300SRichard Henderson } 1137951c6300SRichard Henderson 1138951c6300SRichard Henderson void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1139951c6300SRichard Henderson { 1140951c6300SRichard Henderson tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset); 1141951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1142951c6300SRichard Henderson } 1143951c6300SRichard Henderson 1144951c6300SRichard Henderson void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1145951c6300SRichard Henderson { 1146951c6300SRichard Henderson tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset); 1147951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 1148951c6300SRichard Henderson } 1149951c6300SRichard Henderson 1150951c6300SRichard Henderson void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1151951c6300SRichard Henderson { 1152951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); 1153951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1154951c6300SRichard Henderson } 1155951c6300SRichard Henderson 1156951c6300SRichard Henderson void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1157951c6300SRichard Henderson { 1158951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); 1159951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 1160951c6300SRichard Henderson } 1161951c6300SRichard Henderson 1162951c6300SRichard Henderson void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) 1163951c6300SRichard Henderson { 1164951c6300SRichard Henderson /* Since arg2 and ret have different types, 1165951c6300SRichard Henderson they cannot be the same temporary */ 1166cf811fffSPeter Maydell #ifdef HOST_WORDS_BIGENDIAN 1167951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset); 1168951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4); 1169951c6300SRichard Henderson #else 1170951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); 1171951c6300SRichard Henderson tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4); 1172951c6300SRichard Henderson #endif 1173951c6300SRichard Henderson } 1174951c6300SRichard Henderson 1175951c6300SRichard Henderson void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) 1176951c6300SRichard Henderson { 1177cf811fffSPeter Maydell #ifdef HOST_WORDS_BIGENDIAN 1178951c6300SRichard Henderson tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset); 1179951c6300SRichard Henderson tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4); 1180951c6300SRichard Henderson #else 1181951c6300SRichard Henderson tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); 1182951c6300SRichard Henderson tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4); 1183951c6300SRichard Henderson #endif 1184951c6300SRichard Henderson } 1185951c6300SRichard Henderson 1186951c6300SRichard Henderson void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1187951c6300SRichard Henderson { 1188951c6300SRichard Henderson tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 1189951c6300SRichard Henderson tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 1190951c6300SRichard Henderson } 1191951c6300SRichard Henderson 1192951c6300SRichard Henderson void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1193951c6300SRichard Henderson { 1194951c6300SRichard Henderson tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 1195951c6300SRichard Henderson tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 1196951c6300SRichard Henderson } 1197951c6300SRichard Henderson 1198951c6300SRichard Henderson void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1199951c6300SRichard Henderson { 1200951c6300SRichard Henderson tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 1201951c6300SRichard Henderson tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 1202951c6300SRichard Henderson } 1203951c6300SRichard Henderson 1204951c6300SRichard Henderson void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1205951c6300SRichard Henderson { 1206951c6300SRichard Henderson gen_helper_shl_i64(ret, arg1, arg2); 1207951c6300SRichard Henderson } 1208951c6300SRichard Henderson 1209951c6300SRichard Henderson void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1210951c6300SRichard Henderson { 1211951c6300SRichard Henderson gen_helper_shr_i64(ret, arg1, arg2); 1212951c6300SRichard Henderson } 1213951c6300SRichard Henderson 1214951c6300SRichard Henderson void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1215951c6300SRichard Henderson { 1216951c6300SRichard Henderson gen_helper_sar_i64(ret, arg1, arg2); 1217951c6300SRichard Henderson } 1218951c6300SRichard Henderson 1219951c6300SRichard Henderson void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1220951c6300SRichard Henderson { 1221951c6300SRichard Henderson TCGv_i64 t0; 1222951c6300SRichard Henderson TCGv_i32 t1; 1223951c6300SRichard Henderson 1224951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 1225951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 1226951c6300SRichard Henderson 1227951c6300SRichard Henderson tcg_gen_mulu2_i32(TCGV_LOW(t0), TCGV_HIGH(t0), 1228951c6300SRichard Henderson TCGV_LOW(arg1), TCGV_LOW(arg2)); 1229951c6300SRichard Henderson 1230951c6300SRichard Henderson tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2)); 1231951c6300SRichard Henderson tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); 1232951c6300SRichard Henderson tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), TCGV_LOW(arg2)); 1233951c6300SRichard Henderson tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); 1234951c6300SRichard Henderson 1235951c6300SRichard Henderson tcg_gen_mov_i64(ret, t0); 1236951c6300SRichard Henderson tcg_temp_free_i64(t0); 1237951c6300SRichard Henderson tcg_temp_free_i32(t1); 1238951c6300SRichard Henderson } 1239951c6300SRichard Henderson #endif /* TCG_TARGET_REG_SIZE == 32 */ 1240951c6300SRichard Henderson 1241951c6300SRichard Henderson void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1242951c6300SRichard Henderson { 1243951c6300SRichard Henderson /* some cases can be optimized here */ 1244951c6300SRichard Henderson if (arg2 == 0) { 1245951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1246951c6300SRichard Henderson } else { 1247951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1248951c6300SRichard Henderson tcg_gen_add_i64(ret, arg1, t0); 1249951c6300SRichard Henderson tcg_temp_free_i64(t0); 1250951c6300SRichard Henderson } 1251951c6300SRichard Henderson } 1252951c6300SRichard Henderson 1253951c6300SRichard Henderson void tcg_gen_subfi_i64(TCGv_i64 ret, int64_t arg1, TCGv_i64 arg2) 1254951c6300SRichard Henderson { 1255951c6300SRichard Henderson if (arg1 == 0 && TCG_TARGET_HAS_neg_i64) { 1256951c6300SRichard Henderson /* Don't recurse with tcg_gen_neg_i64. */ 1257951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg2); 1258951c6300SRichard Henderson } else { 1259951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg1); 1260951c6300SRichard Henderson tcg_gen_sub_i64(ret, t0, arg2); 1261951c6300SRichard Henderson tcg_temp_free_i64(t0); 1262951c6300SRichard Henderson } 1263951c6300SRichard Henderson } 1264951c6300SRichard Henderson 1265951c6300SRichard Henderson void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1266951c6300SRichard Henderson { 1267951c6300SRichard Henderson /* some cases can be optimized here */ 1268951c6300SRichard Henderson if (arg2 == 0) { 1269951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1270951c6300SRichard Henderson } else { 1271951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1272951c6300SRichard Henderson tcg_gen_sub_i64(ret, arg1, t0); 1273951c6300SRichard Henderson tcg_temp_free_i64(t0); 1274951c6300SRichard Henderson } 1275951c6300SRichard Henderson } 1276951c6300SRichard Henderson 1277474b2e8fSRichard Henderson void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1278951c6300SRichard Henderson { 12793a13c3f3SRichard Henderson TCGv_i64 t0; 12803a13c3f3SRichard Henderson 12813a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1282951c6300SRichard Henderson tcg_gen_andi_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); 1283951c6300SRichard Henderson tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); 12843a13c3f3SRichard Henderson return; 12853a13c3f3SRichard Henderson } 12863a13c3f3SRichard Henderson 1287951c6300SRichard Henderson /* Some cases can be optimized here. */ 1288951c6300SRichard Henderson switch (arg2) { 1289951c6300SRichard Henderson case 0: 1290951c6300SRichard Henderson tcg_gen_movi_i64(ret, 0); 1291951c6300SRichard Henderson return; 1292474b2e8fSRichard Henderson case -1: 1293951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1294951c6300SRichard Henderson return; 1295474b2e8fSRichard Henderson case 0xff: 1296951c6300SRichard Henderson /* Don't recurse with tcg_gen_ext8u_i64. */ 1297951c6300SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 1298951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg1); 1299951c6300SRichard Henderson return; 1300951c6300SRichard Henderson } 1301951c6300SRichard Henderson break; 1302474b2e8fSRichard Henderson case 0xffff: 1303951c6300SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 1304951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg1); 1305951c6300SRichard Henderson return; 1306951c6300SRichard Henderson } 1307951c6300SRichard Henderson break; 1308474b2e8fSRichard Henderson case 0xffffffffu: 1309951c6300SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 1310951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg1); 1311951c6300SRichard Henderson return; 1312951c6300SRichard Henderson } 1313951c6300SRichard Henderson break; 1314951c6300SRichard Henderson } 1315951c6300SRichard Henderson t0 = tcg_const_i64(arg2); 1316951c6300SRichard Henderson tcg_gen_and_i64(ret, arg1, t0); 1317951c6300SRichard Henderson tcg_temp_free_i64(t0); 1318951c6300SRichard Henderson } 1319951c6300SRichard Henderson 1320951c6300SRichard Henderson void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1321951c6300SRichard Henderson { 13223a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1323951c6300SRichard Henderson tcg_gen_ori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); 1324951c6300SRichard Henderson tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); 13253a13c3f3SRichard Henderson return; 13263a13c3f3SRichard Henderson } 1327951c6300SRichard Henderson /* Some cases can be optimized here. */ 1328951c6300SRichard Henderson if (arg2 == -1) { 1329951c6300SRichard Henderson tcg_gen_movi_i64(ret, -1); 1330951c6300SRichard Henderson } else if (arg2 == 0) { 1331951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1332951c6300SRichard Henderson } else { 1333951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1334951c6300SRichard Henderson tcg_gen_or_i64(ret, arg1, t0); 1335951c6300SRichard Henderson tcg_temp_free_i64(t0); 1336951c6300SRichard Henderson } 1337951c6300SRichard Henderson } 1338951c6300SRichard Henderson 1339951c6300SRichard Henderson void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1340951c6300SRichard Henderson { 13413a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1342951c6300SRichard Henderson tcg_gen_xori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2); 1343951c6300SRichard Henderson tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32); 13443a13c3f3SRichard Henderson return; 13453a13c3f3SRichard Henderson } 1346951c6300SRichard Henderson /* Some cases can be optimized here. */ 1347951c6300SRichard Henderson if (arg2 == 0) { 1348951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1349951c6300SRichard Henderson } else if (arg2 == -1 && TCG_TARGET_HAS_not_i64) { 1350951c6300SRichard Henderson /* Don't recurse with tcg_gen_not_i64. */ 1351951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg1); 1352951c6300SRichard Henderson } else { 1353951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1354951c6300SRichard Henderson tcg_gen_xor_i64(ret, arg1, t0); 1355951c6300SRichard Henderson tcg_temp_free_i64(t0); 1356951c6300SRichard Henderson } 1357951c6300SRichard Henderson } 1358951c6300SRichard Henderson 1359951c6300SRichard Henderson static inline void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, 1360951c6300SRichard Henderson unsigned c, bool right, bool arith) 1361951c6300SRichard Henderson { 1362951c6300SRichard Henderson tcg_debug_assert(c < 64); 1363951c6300SRichard Henderson if (c == 0) { 1364951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); 1365951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 1366951c6300SRichard Henderson } else if (c >= 32) { 1367951c6300SRichard Henderson c -= 32; 1368951c6300SRichard Henderson if (right) { 1369951c6300SRichard Henderson if (arith) { 1370951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); 1371951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); 1372951c6300SRichard Henderson } else { 1373951c6300SRichard Henderson tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); 1374951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1375951c6300SRichard Henderson } 1376951c6300SRichard Henderson } else { 1377951c6300SRichard Henderson tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c); 1378951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_LOW(ret), 0); 1379951c6300SRichard Henderson } 138002616badSRichard Henderson } else if (right) { 138102616badSRichard Henderson if (TCG_TARGET_HAS_extract2_i32) { 138202616badSRichard Henderson tcg_gen_extract2_i32(TCGV_LOW(ret), 138302616badSRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), c); 1384951c6300SRichard Henderson } else { 1385951c6300SRichard Henderson tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); 138602616badSRichard Henderson tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(ret), 138702616badSRichard Henderson TCGV_HIGH(arg1), 32 - c, c); 1388951c6300SRichard Henderson } 138902616badSRichard Henderson if (arith) { 139002616badSRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); 139102616badSRichard Henderson } else { 139202616badSRichard Henderson tcg_gen_shri_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); 139302616badSRichard Henderson } 139402616badSRichard Henderson } else { 139502616badSRichard Henderson if (TCG_TARGET_HAS_extract2_i32) { 139602616badSRichard Henderson tcg_gen_extract2_i32(TCGV_HIGH(ret), 139702616badSRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 32 - c); 139802616badSRichard Henderson } else { 139902616badSRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 140002616badSRichard Henderson tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c); 140102616badSRichard Henderson tcg_gen_deposit_i32(TCGV_HIGH(ret), t0, 140202616badSRichard Henderson TCGV_HIGH(arg1), c, 32 - c); 1403951c6300SRichard Henderson tcg_temp_free_i32(t0); 140402616badSRichard Henderson } 140502616badSRichard Henderson tcg_gen_shli_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); 1406951c6300SRichard Henderson } 1407951c6300SRichard Henderson } 1408951c6300SRichard Henderson 1409474b2e8fSRichard Henderson void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1410951c6300SRichard Henderson { 1411474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 14123a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 14133a13c3f3SRichard Henderson tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0); 14143a13c3f3SRichard Henderson } else if (arg2 == 0) { 1415951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1416951c6300SRichard Henderson } else { 1417951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1418951c6300SRichard Henderson tcg_gen_shl_i64(ret, arg1, t0); 1419951c6300SRichard Henderson tcg_temp_free_i64(t0); 1420951c6300SRichard Henderson } 1421951c6300SRichard Henderson } 1422951c6300SRichard Henderson 1423474b2e8fSRichard Henderson void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1424951c6300SRichard Henderson { 1425474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 14263a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 14273a13c3f3SRichard Henderson tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0); 14283a13c3f3SRichard Henderson } else if (arg2 == 0) { 1429951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1430951c6300SRichard Henderson } else { 1431951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1432951c6300SRichard Henderson tcg_gen_shr_i64(ret, arg1, t0); 1433951c6300SRichard Henderson tcg_temp_free_i64(t0); 1434951c6300SRichard Henderson } 1435951c6300SRichard Henderson } 1436951c6300SRichard Henderson 1437474b2e8fSRichard Henderson void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1438951c6300SRichard Henderson { 1439474b2e8fSRichard Henderson tcg_debug_assert(arg2 >= 0 && arg2 < 64); 14403a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 14413a13c3f3SRichard Henderson tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1); 14423a13c3f3SRichard Henderson } else if (arg2 == 0) { 1443951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1444951c6300SRichard Henderson } else { 1445951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1446951c6300SRichard Henderson tcg_gen_sar_i64(ret, arg1, t0); 1447951c6300SRichard Henderson tcg_temp_free_i64(t0); 1448951c6300SRichard Henderson } 1449951c6300SRichard Henderson } 1450951c6300SRichard Henderson 145142a268c2SRichard Henderson void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, TCGLabel *l) 1452951c6300SRichard Henderson { 1453951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 145442a268c2SRichard Henderson tcg_gen_br(l); 1455951c6300SRichard Henderson } else if (cond != TCG_COND_NEVER) { 1456d88a117eSRichard Henderson l->refs++; 14573a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1458951c6300SRichard Henderson tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, TCGV_LOW(arg1), 1459951c6300SRichard Henderson TCGV_HIGH(arg1), TCGV_LOW(arg2), 146042a268c2SRichard Henderson TCGV_HIGH(arg2), cond, label_arg(l)); 14613a13c3f3SRichard Henderson } else { 146242a268c2SRichard Henderson tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, 146342a268c2SRichard Henderson label_arg(l)); 14643a13c3f3SRichard Henderson } 1465951c6300SRichard Henderson } 1466951c6300SRichard Henderson } 1467951c6300SRichard Henderson 146842a268c2SRichard Henderson void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1, int64_t arg2, TCGLabel *l) 1469951c6300SRichard Henderson { 1470951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 147142a268c2SRichard Henderson tcg_gen_br(l); 1472951c6300SRichard Henderson } else if (cond != TCG_COND_NEVER) { 1473951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 147442a268c2SRichard Henderson tcg_gen_brcond_i64(cond, arg1, t0, l); 1475951c6300SRichard Henderson tcg_temp_free_i64(t0); 1476951c6300SRichard Henderson } 1477951c6300SRichard Henderson } 1478951c6300SRichard Henderson 1479951c6300SRichard Henderson void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret, 1480951c6300SRichard Henderson TCGv_i64 arg1, TCGv_i64 arg2) 1481951c6300SRichard Henderson { 1482951c6300SRichard Henderson if (cond == TCG_COND_ALWAYS) { 1483951c6300SRichard Henderson tcg_gen_movi_i64(ret, 1); 1484951c6300SRichard Henderson } else if (cond == TCG_COND_NEVER) { 1485951c6300SRichard Henderson tcg_gen_movi_i64(ret, 0); 1486951c6300SRichard Henderson } else { 14873a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1488951c6300SRichard Henderson tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), 1489951c6300SRichard Henderson TCGV_LOW(arg1), TCGV_HIGH(arg1), 1490951c6300SRichard Henderson TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); 1491951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 14923a13c3f3SRichard Henderson } else { 1493951c6300SRichard Henderson tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond); 14943a13c3f3SRichard Henderson } 1495951c6300SRichard Henderson } 1496951c6300SRichard Henderson } 1497951c6300SRichard Henderson 1498951c6300SRichard Henderson void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret, 1499951c6300SRichard Henderson TCGv_i64 arg1, int64_t arg2) 1500951c6300SRichard Henderson { 1501951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1502951c6300SRichard Henderson tcg_gen_setcond_i64(cond, ret, arg1, t0); 1503951c6300SRichard Henderson tcg_temp_free_i64(t0); 1504951c6300SRichard Henderson } 1505951c6300SRichard Henderson 1506951c6300SRichard Henderson void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) 1507951c6300SRichard Henderson { 1508b2e3ae94SRichard Henderson if (arg2 == 0) { 1509b2e3ae94SRichard Henderson tcg_gen_movi_i64(ret, 0); 1510b2e3ae94SRichard Henderson } else if (is_power_of_2(arg2)) { 1511b2e3ae94SRichard Henderson tcg_gen_shli_i64(ret, arg1, ctz64(arg2)); 1512b2e3ae94SRichard Henderson } else { 1513951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1514951c6300SRichard Henderson tcg_gen_mul_i64(ret, arg1, t0); 1515951c6300SRichard Henderson tcg_temp_free_i64(t0); 1516951c6300SRichard Henderson } 1517b2e3ae94SRichard Henderson } 1518951c6300SRichard Henderson 1519951c6300SRichard Henderson void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1520951c6300SRichard Henderson { 1521951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i64) { 1522951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2); 1523951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1524951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1525951c6300SRichard Henderson tcg_gen_sari_i64(t0, arg1, 63); 1526951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2); 1527951c6300SRichard Henderson tcg_temp_free_i64(t0); 1528951c6300SRichard Henderson } else { 1529951c6300SRichard Henderson gen_helper_div_i64(ret, arg1, arg2); 1530951c6300SRichard Henderson } 1531951c6300SRichard Henderson } 1532951c6300SRichard Henderson 1533951c6300SRichard Henderson void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1534951c6300SRichard Henderson { 1535951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i64) { 1536951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2); 1537951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i64) { 1538951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1539951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_div_i64, t0, arg1, arg2); 1540951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, arg2); 1541951c6300SRichard Henderson tcg_gen_sub_i64(ret, arg1, t0); 1542951c6300SRichard Henderson tcg_temp_free_i64(t0); 1543951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1544951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1545951c6300SRichard Henderson tcg_gen_sari_i64(t0, arg1, 63); 1546951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2); 1547951c6300SRichard Henderson tcg_temp_free_i64(t0); 1548951c6300SRichard Henderson } else { 1549951c6300SRichard Henderson gen_helper_rem_i64(ret, arg1, arg2); 1550951c6300SRichard Henderson } 1551951c6300SRichard Henderson } 1552951c6300SRichard Henderson 1553951c6300SRichard Henderson void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1554951c6300SRichard Henderson { 1555951c6300SRichard Henderson if (TCG_TARGET_HAS_div_i64) { 1556951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2); 1557951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1558951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1559951c6300SRichard Henderson tcg_gen_movi_i64(t0, 0); 1560951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2); 1561951c6300SRichard Henderson tcg_temp_free_i64(t0); 1562951c6300SRichard Henderson } else { 1563951c6300SRichard Henderson gen_helper_divu_i64(ret, arg1, arg2); 1564951c6300SRichard Henderson } 1565951c6300SRichard Henderson } 1566951c6300SRichard Henderson 1567951c6300SRichard Henderson void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1568951c6300SRichard Henderson { 1569951c6300SRichard Henderson if (TCG_TARGET_HAS_rem_i64) { 1570951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2); 1571951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div_i64) { 1572951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1573951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_divu_i64, t0, arg1, arg2); 1574951c6300SRichard Henderson tcg_gen_mul_i64(t0, t0, arg2); 1575951c6300SRichard Henderson tcg_gen_sub_i64(ret, arg1, t0); 1576951c6300SRichard Henderson tcg_temp_free_i64(t0); 1577951c6300SRichard Henderson } else if (TCG_TARGET_HAS_div2_i64) { 1578951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1579951c6300SRichard Henderson tcg_gen_movi_i64(t0, 0); 1580951c6300SRichard Henderson tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2); 1581951c6300SRichard Henderson tcg_temp_free_i64(t0); 1582951c6300SRichard Henderson } else { 1583951c6300SRichard Henderson gen_helper_remu_i64(ret, arg1, arg2); 1584951c6300SRichard Henderson } 1585951c6300SRichard Henderson } 1586951c6300SRichard Henderson 1587951c6300SRichard Henderson void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg) 1588951c6300SRichard Henderson { 15893a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1590951c6300SRichard Henderson tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1591951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 15923a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext8s_i64) { 1593951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg); 1594951c6300SRichard Henderson } else { 1595951c6300SRichard Henderson tcg_gen_shli_i64(ret, arg, 56); 1596951c6300SRichard Henderson tcg_gen_sari_i64(ret, ret, 56); 1597951c6300SRichard Henderson } 1598951c6300SRichard Henderson } 1599951c6300SRichard Henderson 1600951c6300SRichard Henderson void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg) 1601951c6300SRichard Henderson { 16023a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1603951c6300SRichard Henderson tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1604951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 16053a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext16s_i64) { 1606951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg); 1607951c6300SRichard Henderson } else { 1608951c6300SRichard Henderson tcg_gen_shli_i64(ret, arg, 48); 1609951c6300SRichard Henderson tcg_gen_sari_i64(ret, ret, 48); 1610951c6300SRichard Henderson } 1611951c6300SRichard Henderson } 1612951c6300SRichard Henderson 1613951c6300SRichard Henderson void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg) 1614951c6300SRichard Henderson { 16153a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1616951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1617951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 16183a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext32s_i64) { 1619951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg); 1620951c6300SRichard Henderson } else { 1621951c6300SRichard Henderson tcg_gen_shli_i64(ret, arg, 32); 1622951c6300SRichard Henderson tcg_gen_sari_i64(ret, ret, 32); 1623951c6300SRichard Henderson } 1624951c6300SRichard Henderson } 1625951c6300SRichard Henderson 1626951c6300SRichard Henderson void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg) 1627951c6300SRichard Henderson { 16283a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1629951c6300SRichard Henderson tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1630951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16313a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext8u_i64) { 1632951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg); 1633951c6300SRichard Henderson } else { 1634951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg, 0xffu); 1635951c6300SRichard Henderson } 1636951c6300SRichard Henderson } 1637951c6300SRichard Henderson 1638951c6300SRichard Henderson void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg) 1639951c6300SRichard Henderson { 16403a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1641951c6300SRichard Henderson tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1642951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16433a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext16u_i64) { 1644951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg); 1645951c6300SRichard Henderson } else { 1646951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg, 0xffffu); 1647951c6300SRichard Henderson } 1648951c6300SRichard Henderson } 1649951c6300SRichard Henderson 1650951c6300SRichard Henderson void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg) 1651951c6300SRichard Henderson { 16523a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1653951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1654951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16553a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_ext32u_i64) { 1656951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg); 1657951c6300SRichard Henderson } else { 1658951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg, 0xffffffffu); 1659951c6300SRichard Henderson } 1660951c6300SRichard Henderson } 1661951c6300SRichard Henderson 1662951c6300SRichard Henderson /* Note: we assume the six high bytes are set to zero */ 1663951c6300SRichard Henderson void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg) 1664951c6300SRichard Henderson { 16653a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1666951c6300SRichard Henderson tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1667951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16683a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_bswap16_i64) { 1669951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg); 1670951c6300SRichard Henderson } else { 1671951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1672951c6300SRichard Henderson 1673951c6300SRichard Henderson tcg_gen_ext8u_i64(t0, arg); 1674951c6300SRichard Henderson tcg_gen_shli_i64(t0, t0, 8); 1675951c6300SRichard Henderson tcg_gen_shri_i64(ret, arg, 8); 1676951c6300SRichard Henderson tcg_gen_or_i64(ret, ret, t0); 1677951c6300SRichard Henderson tcg_temp_free_i64(t0); 1678951c6300SRichard Henderson } 1679951c6300SRichard Henderson } 1680951c6300SRichard Henderson 1681951c6300SRichard Henderson /* Note: we assume the four high bytes are set to zero */ 1682951c6300SRichard Henderson void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg) 1683951c6300SRichard Henderson { 16843a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1685951c6300SRichard Henderson tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 1686951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 16873a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_bswap32_i64) { 1688951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg); 1689951c6300SRichard Henderson } else { 1690a686dc71SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1691a686dc71SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 1692a686dc71SRichard Henderson TCGv_i64 t2 = tcg_const_i64(0x00ff00ff); 1693951c6300SRichard Henderson 1694a686dc71SRichard Henderson /* arg = ....abcd */ 1695a686dc71SRichard Henderson tcg_gen_shri_i64(t0, arg, 8); /* t0 = .....abc */ 1696a686dc71SRichard Henderson tcg_gen_and_i64(t1, arg, t2); /* t1 = .....b.d */ 1697a686dc71SRichard Henderson tcg_gen_and_i64(t0, t0, t2); /* t0 = .....a.c */ 1698a686dc71SRichard Henderson tcg_gen_shli_i64(t1, t1, 8); /* t1 = ....b.d. */ 1699a686dc71SRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = ....badc */ 1700951c6300SRichard Henderson 1701a686dc71SRichard Henderson tcg_gen_shli_i64(t1, ret, 48); /* t1 = dc...... */ 1702a686dc71SRichard Henderson tcg_gen_shri_i64(t0, ret, 16); /* t0 = ......ba */ 1703a686dc71SRichard Henderson tcg_gen_shri_i64(t1, t1, 32); /* t1 = ....dc.. */ 1704a686dc71SRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = ....dcba */ 1705951c6300SRichard Henderson 1706951c6300SRichard Henderson tcg_temp_free_i64(t0); 1707951c6300SRichard Henderson tcg_temp_free_i64(t1); 1708a686dc71SRichard Henderson tcg_temp_free_i64(t2); 1709951c6300SRichard Henderson } 1710951c6300SRichard Henderson } 1711951c6300SRichard Henderson 1712951c6300SRichard Henderson void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) 1713951c6300SRichard Henderson { 17143a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 1715951c6300SRichard Henderson TCGv_i32 t0, t1; 1716951c6300SRichard Henderson t0 = tcg_temp_new_i32(); 1717951c6300SRichard Henderson t1 = tcg_temp_new_i32(); 1718951c6300SRichard Henderson 1719951c6300SRichard Henderson tcg_gen_bswap32_i32(t0, TCGV_LOW(arg)); 1720951c6300SRichard Henderson tcg_gen_bswap32_i32(t1, TCGV_HIGH(arg)); 1721951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), t1); 1722951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), t0); 1723951c6300SRichard Henderson tcg_temp_free_i32(t0); 1724951c6300SRichard Henderson tcg_temp_free_i32(t1); 17253a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_bswap64_i64) { 1726951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg); 1727951c6300SRichard Henderson } else { 1728951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1729951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 17309e821eabSRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 1731951c6300SRichard Henderson 17329e821eabSRichard Henderson /* arg = abcdefgh */ 17339e821eabSRichard Henderson tcg_gen_movi_i64(t2, 0x00ff00ff00ff00ffull); 17349e821eabSRichard Henderson tcg_gen_shri_i64(t0, arg, 8); /* t0 = .abcdefg */ 17359e821eabSRichard Henderson tcg_gen_and_i64(t1, arg, t2); /* t1 = .b.d.f.h */ 17369e821eabSRichard Henderson tcg_gen_and_i64(t0, t0, t2); /* t0 = .a.c.e.g */ 17379e821eabSRichard Henderson tcg_gen_shli_i64(t1, t1, 8); /* t1 = b.d.f.h. */ 17389e821eabSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = badcfehg */ 1739951c6300SRichard Henderson 17409e821eabSRichard Henderson tcg_gen_movi_i64(t2, 0x0000ffff0000ffffull); 17419e821eabSRichard Henderson tcg_gen_shri_i64(t0, ret, 16); /* t0 = ..badcfe */ 17429e821eabSRichard Henderson tcg_gen_and_i64(t1, ret, t2); /* t1 = ..dc..hg */ 17439e821eabSRichard Henderson tcg_gen_and_i64(t0, t0, t2); /* t0 = ..ba..fe */ 17449e821eabSRichard Henderson tcg_gen_shli_i64(t1, t1, 16); /* t1 = dc..hg.. */ 17459e821eabSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = dcbahgfe */ 1746951c6300SRichard Henderson 17479e821eabSRichard Henderson tcg_gen_shri_i64(t0, ret, 32); /* t0 = ....dcba */ 17489e821eabSRichard Henderson tcg_gen_shli_i64(t1, ret, 32); /* t1 = hgfe.... */ 17499e821eabSRichard Henderson tcg_gen_or_i64(ret, t0, t1); /* ret = hgfedcba */ 1750951c6300SRichard Henderson 1751951c6300SRichard Henderson tcg_temp_free_i64(t0); 1752951c6300SRichard Henderson tcg_temp_free_i64(t1); 17539e821eabSRichard Henderson tcg_temp_free_i64(t2); 1754951c6300SRichard Henderson } 1755951c6300SRichard Henderson } 1756951c6300SRichard Henderson 1757951c6300SRichard Henderson void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) 1758951c6300SRichard Henderson { 17593a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 17603a13c3f3SRichard Henderson tcg_gen_not_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 17613a13c3f3SRichard Henderson tcg_gen_not_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); 17623a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_not_i64) { 1763951c6300SRichard Henderson tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg); 1764951c6300SRichard Henderson } else { 1765951c6300SRichard Henderson tcg_gen_xori_i64(ret, arg, -1); 1766951c6300SRichard Henderson } 1767951c6300SRichard Henderson } 1768951c6300SRichard Henderson 1769951c6300SRichard Henderson void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1770951c6300SRichard Henderson { 17713a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 17723a13c3f3SRichard Henderson tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 17733a13c3f3SRichard Henderson tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 17743a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_andc_i64) { 1775951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2); 1776951c6300SRichard Henderson } else { 1777951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1778951c6300SRichard Henderson tcg_gen_not_i64(t0, arg2); 1779951c6300SRichard Henderson tcg_gen_and_i64(ret, arg1, t0); 1780951c6300SRichard Henderson tcg_temp_free_i64(t0); 1781951c6300SRichard Henderson } 1782951c6300SRichard Henderson } 1783951c6300SRichard Henderson 1784951c6300SRichard Henderson void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1785951c6300SRichard Henderson { 17863a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 17873a13c3f3SRichard Henderson tcg_gen_eqv_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 17883a13c3f3SRichard Henderson tcg_gen_eqv_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 17893a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_eqv_i64) { 1790951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2); 1791951c6300SRichard Henderson } else { 1792951c6300SRichard Henderson tcg_gen_xor_i64(ret, arg1, arg2); 1793951c6300SRichard Henderson tcg_gen_not_i64(ret, ret); 1794951c6300SRichard Henderson } 1795951c6300SRichard Henderson } 1796951c6300SRichard Henderson 1797951c6300SRichard Henderson void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1798951c6300SRichard Henderson { 17993a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18003a13c3f3SRichard Henderson tcg_gen_nand_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18013a13c3f3SRichard Henderson tcg_gen_nand_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18023a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_nand_i64) { 1803951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2); 1804951c6300SRichard Henderson } else { 1805951c6300SRichard Henderson tcg_gen_and_i64(ret, arg1, arg2); 1806951c6300SRichard Henderson tcg_gen_not_i64(ret, ret); 1807951c6300SRichard Henderson } 1808951c6300SRichard Henderson } 1809951c6300SRichard Henderson 1810951c6300SRichard Henderson void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1811951c6300SRichard Henderson { 18123a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18133a13c3f3SRichard Henderson tcg_gen_nor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18143a13c3f3SRichard Henderson tcg_gen_nor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18153a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_nor_i64) { 1816951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2); 1817951c6300SRichard Henderson } else { 1818951c6300SRichard Henderson tcg_gen_or_i64(ret, arg1, arg2); 1819951c6300SRichard Henderson tcg_gen_not_i64(ret, ret); 1820951c6300SRichard Henderson } 1821951c6300SRichard Henderson } 1822951c6300SRichard Henderson 1823951c6300SRichard Henderson void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1824951c6300SRichard Henderson { 18253a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 18263a13c3f3SRichard Henderson tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); 18273a13c3f3SRichard Henderson tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); 18283a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_orc_i64) { 1829951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2); 1830951c6300SRichard Henderson } else { 1831951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 1832951c6300SRichard Henderson tcg_gen_not_i64(t0, arg2); 1833951c6300SRichard Henderson tcg_gen_or_i64(ret, arg1, t0); 1834951c6300SRichard Henderson tcg_temp_free_i64(t0); 1835951c6300SRichard Henderson } 1836951c6300SRichard Henderson } 1837951c6300SRichard Henderson 18380e28d006SRichard Henderson void tcg_gen_clz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 18390e28d006SRichard Henderson { 18400e28d006SRichard Henderson if (TCG_TARGET_HAS_clz_i64) { 18410e28d006SRichard Henderson tcg_gen_op3_i64(INDEX_op_clz_i64, ret, arg1, arg2); 18420e28d006SRichard Henderson } else { 18430e28d006SRichard Henderson gen_helper_clz_i64(ret, arg1, arg2); 18440e28d006SRichard Henderson } 18450e28d006SRichard Henderson } 18460e28d006SRichard Henderson 18470e28d006SRichard Henderson void tcg_gen_clzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) 18480e28d006SRichard Henderson { 18490e28d006SRichard Henderson if (TCG_TARGET_REG_BITS == 32 18500e28d006SRichard Henderson && TCG_TARGET_HAS_clz_i32 18510e28d006SRichard Henderson && arg2 <= 0xffffffffu) { 18520e28d006SRichard Henderson TCGv_i32 t = tcg_const_i32((uint32_t)arg2 - 32); 18530e28d006SRichard Henderson tcg_gen_clz_i32(t, TCGV_LOW(arg1), t); 18540e28d006SRichard Henderson tcg_gen_addi_i32(t, t, 32); 18550e28d006SRichard Henderson tcg_gen_clz_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), t); 18560e28d006SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 18570e28d006SRichard Henderson tcg_temp_free_i32(t); 18580e28d006SRichard Henderson } else { 18590e28d006SRichard Henderson TCGv_i64 t = tcg_const_i64(arg2); 18600e28d006SRichard Henderson tcg_gen_clz_i64(ret, arg1, t); 18610e28d006SRichard Henderson tcg_temp_free_i64(t); 18620e28d006SRichard Henderson } 18630e28d006SRichard Henderson } 18640e28d006SRichard Henderson 18650e28d006SRichard Henderson void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 18660e28d006SRichard Henderson { 18670e28d006SRichard Henderson if (TCG_TARGET_HAS_ctz_i64) { 18680e28d006SRichard Henderson tcg_gen_op3_i64(INDEX_op_ctz_i64, ret, arg1, arg2); 186914e99210SRichard Henderson } else if (TCG_TARGET_HAS_ctpop_i64 || TCG_TARGET_HAS_clz_i64) { 187014e99210SRichard Henderson TCGv_i64 z, t = tcg_temp_new_i64(); 187114e99210SRichard Henderson 187214e99210SRichard Henderson if (TCG_TARGET_HAS_ctpop_i64) { 187314e99210SRichard Henderson tcg_gen_subi_i64(t, arg1, 1); 187414e99210SRichard Henderson tcg_gen_andc_i64(t, t, arg1); 187514e99210SRichard Henderson tcg_gen_ctpop_i64(t, t); 187614e99210SRichard Henderson } else { 187714e99210SRichard Henderson /* Since all non-x86 hosts have clz(0) == 64, don't fight it. */ 187814e99210SRichard Henderson tcg_gen_neg_i64(t, arg1); 187914e99210SRichard Henderson tcg_gen_and_i64(t, t, arg1); 188014e99210SRichard Henderson tcg_gen_clzi_i64(t, t, 64); 188114e99210SRichard Henderson tcg_gen_xori_i64(t, t, 63); 188214e99210SRichard Henderson } 188314e99210SRichard Henderson z = tcg_const_i64(0); 188414e99210SRichard Henderson tcg_gen_movcond_i64(TCG_COND_EQ, ret, arg1, z, arg2, t); 188514e99210SRichard Henderson tcg_temp_free_i64(t); 188614e99210SRichard Henderson tcg_temp_free_i64(z); 18870e28d006SRichard Henderson } else { 18880e28d006SRichard Henderson gen_helper_ctz_i64(ret, arg1, arg2); 18890e28d006SRichard Henderson } 18900e28d006SRichard Henderson } 18910e28d006SRichard Henderson 18920e28d006SRichard Henderson void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) 18930e28d006SRichard Henderson { 18940e28d006SRichard Henderson if (TCG_TARGET_REG_BITS == 32 18950e28d006SRichard Henderson && TCG_TARGET_HAS_ctz_i32 18960e28d006SRichard Henderson && arg2 <= 0xffffffffu) { 18970e28d006SRichard Henderson TCGv_i32 t32 = tcg_const_i32((uint32_t)arg2 - 32); 18980e28d006SRichard Henderson tcg_gen_ctz_i32(t32, TCGV_HIGH(arg1), t32); 18990e28d006SRichard Henderson tcg_gen_addi_i32(t32, t32, 32); 19000e28d006SRichard Henderson tcg_gen_ctz_i32(TCGV_LOW(ret), TCGV_LOW(arg1), t32); 19010e28d006SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 19020e28d006SRichard Henderson tcg_temp_free_i32(t32); 190314e99210SRichard Henderson } else if (!TCG_TARGET_HAS_ctz_i64 190414e99210SRichard Henderson && TCG_TARGET_HAS_ctpop_i64 190514e99210SRichard Henderson && arg2 == 64) { 190614e99210SRichard Henderson /* This equivalence has the advantage of not requiring a fixup. */ 190714e99210SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 190814e99210SRichard Henderson tcg_gen_subi_i64(t, arg1, 1); 190914e99210SRichard Henderson tcg_gen_andc_i64(t, t, arg1); 191014e99210SRichard Henderson tcg_gen_ctpop_i64(ret, t); 191114e99210SRichard Henderson tcg_temp_free_i64(t); 19120e28d006SRichard Henderson } else { 19130e28d006SRichard Henderson TCGv_i64 t64 = tcg_const_i64(arg2); 19140e28d006SRichard Henderson tcg_gen_ctz_i64(ret, arg1, t64); 19150e28d006SRichard Henderson tcg_temp_free_i64(t64); 19160e28d006SRichard Henderson } 19170e28d006SRichard Henderson } 19180e28d006SRichard Henderson 1919086920c2SRichard Henderson void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg) 1920086920c2SRichard Henderson { 1921086920c2SRichard Henderson if (TCG_TARGET_HAS_clz_i64 || TCG_TARGET_HAS_clz_i32) { 1922086920c2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 1923086920c2SRichard Henderson tcg_gen_sari_i64(t, arg, 63); 1924086920c2SRichard Henderson tcg_gen_xor_i64(t, t, arg); 1925086920c2SRichard Henderson tcg_gen_clzi_i64(t, t, 64); 1926086920c2SRichard Henderson tcg_gen_subi_i64(ret, t, 1); 1927086920c2SRichard Henderson tcg_temp_free_i64(t); 1928086920c2SRichard Henderson } else { 1929086920c2SRichard Henderson gen_helper_clrsb_i64(ret, arg); 1930086920c2SRichard Henderson } 1931086920c2SRichard Henderson } 1932086920c2SRichard Henderson 1933a768e4e9SRichard Henderson void tcg_gen_ctpop_i64(TCGv_i64 ret, TCGv_i64 arg1) 1934a768e4e9SRichard Henderson { 1935a768e4e9SRichard Henderson if (TCG_TARGET_HAS_ctpop_i64) { 1936a768e4e9SRichard Henderson tcg_gen_op2_i64(INDEX_op_ctpop_i64, ret, arg1); 1937a768e4e9SRichard Henderson } else if (TCG_TARGET_REG_BITS == 32 && TCG_TARGET_HAS_ctpop_i32) { 1938a768e4e9SRichard Henderson tcg_gen_ctpop_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 1939a768e4e9SRichard Henderson tcg_gen_ctpop_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); 1940a768e4e9SRichard Henderson tcg_gen_add_i32(TCGV_LOW(ret), TCGV_LOW(ret), TCGV_HIGH(ret)); 1941a768e4e9SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 1942a768e4e9SRichard Henderson } else { 1943a768e4e9SRichard Henderson gen_helper_ctpop_i64(ret, arg1); 1944a768e4e9SRichard Henderson } 1945a768e4e9SRichard Henderson } 1946a768e4e9SRichard Henderson 1947951c6300SRichard Henderson void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1948951c6300SRichard Henderson { 1949951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i64) { 1950951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2); 1951951c6300SRichard Henderson } else { 1952951c6300SRichard Henderson TCGv_i64 t0, t1; 1953951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 1954951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 1955951c6300SRichard Henderson tcg_gen_shl_i64(t0, arg1, arg2); 1956951c6300SRichard Henderson tcg_gen_subfi_i64(t1, 64, arg2); 1957951c6300SRichard Henderson tcg_gen_shr_i64(t1, arg1, t1); 1958951c6300SRichard Henderson tcg_gen_or_i64(ret, t0, t1); 1959951c6300SRichard Henderson tcg_temp_free_i64(t0); 1960951c6300SRichard Henderson tcg_temp_free_i64(t1); 1961951c6300SRichard Henderson } 1962951c6300SRichard Henderson } 1963951c6300SRichard Henderson 1964951c6300SRichard Henderson void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2) 1965951c6300SRichard Henderson { 1966951c6300SRichard Henderson tcg_debug_assert(arg2 < 64); 1967951c6300SRichard Henderson /* some cases can be optimized here */ 1968951c6300SRichard Henderson if (arg2 == 0) { 1969951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 1970951c6300SRichard Henderson } else if (TCG_TARGET_HAS_rot_i64) { 1971951c6300SRichard Henderson TCGv_i64 t0 = tcg_const_i64(arg2); 1972951c6300SRichard Henderson tcg_gen_rotl_i64(ret, arg1, t0); 1973951c6300SRichard Henderson tcg_temp_free_i64(t0); 1974951c6300SRichard Henderson } else { 1975951c6300SRichard Henderson TCGv_i64 t0, t1; 1976951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 1977951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 1978951c6300SRichard Henderson tcg_gen_shli_i64(t0, arg1, arg2); 1979951c6300SRichard Henderson tcg_gen_shri_i64(t1, arg1, 64 - arg2); 1980951c6300SRichard Henderson tcg_gen_or_i64(ret, t0, t1); 1981951c6300SRichard Henderson tcg_temp_free_i64(t0); 1982951c6300SRichard Henderson tcg_temp_free_i64(t1); 1983951c6300SRichard Henderson } 1984951c6300SRichard Henderson } 1985951c6300SRichard Henderson 1986951c6300SRichard Henderson void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1987951c6300SRichard Henderson { 1988951c6300SRichard Henderson if (TCG_TARGET_HAS_rot_i64) { 1989951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2); 1990951c6300SRichard Henderson } else { 1991951c6300SRichard Henderson TCGv_i64 t0, t1; 1992951c6300SRichard Henderson t0 = tcg_temp_new_i64(); 1993951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 1994951c6300SRichard Henderson tcg_gen_shr_i64(t0, arg1, arg2); 1995951c6300SRichard Henderson tcg_gen_subfi_i64(t1, 64, arg2); 1996951c6300SRichard Henderson tcg_gen_shl_i64(t1, arg1, t1); 1997951c6300SRichard Henderson tcg_gen_or_i64(ret, t0, t1); 1998951c6300SRichard Henderson tcg_temp_free_i64(t0); 1999951c6300SRichard Henderson tcg_temp_free_i64(t1); 2000951c6300SRichard Henderson } 2001951c6300SRichard Henderson } 2002951c6300SRichard Henderson 2003951c6300SRichard Henderson void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2) 2004951c6300SRichard Henderson { 2005951c6300SRichard Henderson tcg_debug_assert(arg2 < 64); 2006951c6300SRichard Henderson /* some cases can be optimized here */ 2007951c6300SRichard Henderson if (arg2 == 0) { 2008951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg1); 2009951c6300SRichard Henderson } else { 2010951c6300SRichard Henderson tcg_gen_rotli_i64(ret, arg1, 64 - arg2); 2011951c6300SRichard Henderson } 2012951c6300SRichard Henderson } 2013951c6300SRichard Henderson 2014951c6300SRichard Henderson void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2, 2015951c6300SRichard Henderson unsigned int ofs, unsigned int len) 2016951c6300SRichard Henderson { 2017951c6300SRichard Henderson uint64_t mask; 2018951c6300SRichard Henderson TCGv_i64 t1; 2019951c6300SRichard Henderson 2020951c6300SRichard Henderson tcg_debug_assert(ofs < 64); 20210d0d309dSRichard Henderson tcg_debug_assert(len > 0); 2022951c6300SRichard Henderson tcg_debug_assert(len <= 64); 2023951c6300SRichard Henderson tcg_debug_assert(ofs + len <= 64); 2024951c6300SRichard Henderson 20250d0d309dSRichard Henderson if (len == 64) { 2026951c6300SRichard Henderson tcg_gen_mov_i64(ret, arg2); 2027951c6300SRichard Henderson return; 2028951c6300SRichard Henderson } 2029951c6300SRichard Henderson if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(ofs, len)) { 2030951c6300SRichard Henderson tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len); 2031951c6300SRichard Henderson return; 2032951c6300SRichard Henderson } 2033951c6300SRichard Henderson 20343a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2035951c6300SRichard Henderson if (ofs >= 32) { 2036951c6300SRichard Henderson tcg_gen_deposit_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 2037951c6300SRichard Henderson TCGV_LOW(arg2), ofs - 32, len); 2038951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); 2039951c6300SRichard Henderson return; 2040951c6300SRichard Henderson } 2041951c6300SRichard Henderson if (ofs + len <= 32) { 2042951c6300SRichard Henderson tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(arg1), 2043951c6300SRichard Henderson TCGV_LOW(arg2), ofs, len); 2044951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 2045951c6300SRichard Henderson return; 2046951c6300SRichard Henderson } 20473a13c3f3SRichard Henderson } 2048951c6300SRichard Henderson 2049951c6300SRichard Henderson t1 = tcg_temp_new_i64(); 2050951c6300SRichard Henderson 2051b0a60567SRichard Henderson if (TCG_TARGET_HAS_extract2_i64) { 2052b0a60567SRichard Henderson if (ofs + len == 64) { 2053b0a60567SRichard Henderson tcg_gen_shli_i64(t1, arg1, len); 2054b0a60567SRichard Henderson tcg_gen_extract2_i64(ret, t1, arg2, len); 2055b0a60567SRichard Henderson goto done; 2056b0a60567SRichard Henderson } 2057b0a60567SRichard Henderson if (ofs == 0) { 2058b0a60567SRichard Henderson tcg_gen_extract2_i64(ret, arg1, arg2, len); 2059b0a60567SRichard Henderson tcg_gen_rotli_i64(ret, ret, len); 2060b0a60567SRichard Henderson goto done; 2061b0a60567SRichard Henderson } 2062b0a60567SRichard Henderson } 2063b0a60567SRichard Henderson 2064b0a60567SRichard Henderson mask = (1ull << len) - 1; 2065951c6300SRichard Henderson if (ofs + len < 64) { 2066951c6300SRichard Henderson tcg_gen_andi_i64(t1, arg2, mask); 2067951c6300SRichard Henderson tcg_gen_shli_i64(t1, t1, ofs); 2068951c6300SRichard Henderson } else { 2069951c6300SRichard Henderson tcg_gen_shli_i64(t1, arg2, ofs); 2070951c6300SRichard Henderson } 2071951c6300SRichard Henderson tcg_gen_andi_i64(ret, arg1, ~(mask << ofs)); 2072951c6300SRichard Henderson tcg_gen_or_i64(ret, ret, t1); 2073b0a60567SRichard Henderson done: 2074951c6300SRichard Henderson tcg_temp_free_i64(t1); 2075951c6300SRichard Henderson } 2076951c6300SRichard Henderson 207707cc68d5SRichard Henderson void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg, 207807cc68d5SRichard Henderson unsigned int ofs, unsigned int len) 207907cc68d5SRichard Henderson { 208007cc68d5SRichard Henderson tcg_debug_assert(ofs < 64); 208107cc68d5SRichard Henderson tcg_debug_assert(len > 0); 208207cc68d5SRichard Henderson tcg_debug_assert(len <= 64); 208307cc68d5SRichard Henderson tcg_debug_assert(ofs + len <= 64); 208407cc68d5SRichard Henderson 208507cc68d5SRichard Henderson if (ofs + len == 64) { 208607cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 208707cc68d5SRichard Henderson } else if (ofs == 0) { 208807cc68d5SRichard Henderson tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); 208907cc68d5SRichard Henderson } else if (TCG_TARGET_HAS_deposit_i64 209007cc68d5SRichard Henderson && TCG_TARGET_deposit_i64_valid(ofs, len)) { 209107cc68d5SRichard Henderson TCGv_i64 zero = tcg_const_i64(0); 209207cc68d5SRichard Henderson tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, zero, arg, ofs, len); 209307cc68d5SRichard Henderson tcg_temp_free_i64(zero); 209407cc68d5SRichard Henderson } else { 209507cc68d5SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 209607cc68d5SRichard Henderson if (ofs >= 32) { 209707cc68d5SRichard Henderson tcg_gen_deposit_z_i32(TCGV_HIGH(ret), TCGV_LOW(arg), 209807cc68d5SRichard Henderson ofs - 32, len); 209907cc68d5SRichard Henderson tcg_gen_movi_i32(TCGV_LOW(ret), 0); 210007cc68d5SRichard Henderson return; 210107cc68d5SRichard Henderson } 210207cc68d5SRichard Henderson if (ofs + len <= 32) { 210307cc68d5SRichard Henderson tcg_gen_deposit_z_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len); 210407cc68d5SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 210507cc68d5SRichard Henderson return; 210607cc68d5SRichard Henderson } 210707cc68d5SRichard Henderson } 210807cc68d5SRichard Henderson /* To help two-operand hosts we prefer to zero-extend first, 210907cc68d5SRichard Henderson which allows ARG to stay live. */ 211007cc68d5SRichard Henderson switch (len) { 211107cc68d5SRichard Henderson case 32: 211207cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 211307cc68d5SRichard Henderson tcg_gen_ext32u_i64(ret, arg); 211407cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 211507cc68d5SRichard Henderson return; 211607cc68d5SRichard Henderson } 211707cc68d5SRichard Henderson break; 211807cc68d5SRichard Henderson case 16: 211907cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 212007cc68d5SRichard Henderson tcg_gen_ext16u_i64(ret, arg); 212107cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 212207cc68d5SRichard Henderson return; 212307cc68d5SRichard Henderson } 212407cc68d5SRichard Henderson break; 212507cc68d5SRichard Henderson case 8: 212607cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 212707cc68d5SRichard Henderson tcg_gen_ext8u_i64(ret, arg); 212807cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 212907cc68d5SRichard Henderson return; 213007cc68d5SRichard Henderson } 213107cc68d5SRichard Henderson break; 213207cc68d5SRichard Henderson } 213307cc68d5SRichard Henderson /* Otherwise prefer zero-extension over AND for code size. */ 213407cc68d5SRichard Henderson switch (ofs + len) { 213507cc68d5SRichard Henderson case 32: 213607cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 213707cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 213807cc68d5SRichard Henderson tcg_gen_ext32u_i64(ret, ret); 213907cc68d5SRichard Henderson return; 214007cc68d5SRichard Henderson } 214107cc68d5SRichard Henderson break; 214207cc68d5SRichard Henderson case 16: 214307cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 214407cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 214507cc68d5SRichard Henderson tcg_gen_ext16u_i64(ret, ret); 214607cc68d5SRichard Henderson return; 214707cc68d5SRichard Henderson } 214807cc68d5SRichard Henderson break; 214907cc68d5SRichard Henderson case 8: 215007cc68d5SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 215107cc68d5SRichard Henderson tcg_gen_shli_i64(ret, arg, ofs); 215207cc68d5SRichard Henderson tcg_gen_ext8u_i64(ret, ret); 215307cc68d5SRichard Henderson return; 215407cc68d5SRichard Henderson } 215507cc68d5SRichard Henderson break; 215607cc68d5SRichard Henderson } 215707cc68d5SRichard Henderson tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); 215807cc68d5SRichard Henderson tcg_gen_shli_i64(ret, ret, ofs); 215907cc68d5SRichard Henderson } 216007cc68d5SRichard Henderson } 216107cc68d5SRichard Henderson 21627ec8bab3SRichard Henderson void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg, 21637ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 21647ec8bab3SRichard Henderson { 21657ec8bab3SRichard Henderson tcg_debug_assert(ofs < 64); 21667ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 21677ec8bab3SRichard Henderson tcg_debug_assert(len <= 64); 21687ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 64); 21697ec8bab3SRichard Henderson 21707ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if extract is supported. */ 21717ec8bab3SRichard Henderson if (ofs + len == 64) { 21727ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, 64 - len); 21737ec8bab3SRichard Henderson return; 21747ec8bab3SRichard Henderson } 21757ec8bab3SRichard Henderson if (ofs == 0) { 21767ec8bab3SRichard Henderson tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); 21777ec8bab3SRichard Henderson return; 21787ec8bab3SRichard Henderson } 21797ec8bab3SRichard Henderson 21807ec8bab3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 21817ec8bab3SRichard Henderson /* Look for a 32-bit extract within one of the two words. */ 21827ec8bab3SRichard Henderson if (ofs >= 32) { 21837ec8bab3SRichard Henderson tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len); 21847ec8bab3SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 21857ec8bab3SRichard Henderson return; 21867ec8bab3SRichard Henderson } 21877ec8bab3SRichard Henderson if (ofs + len <= 32) { 21887ec8bab3SRichard Henderson tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len); 21897ec8bab3SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 21907ec8bab3SRichard Henderson return; 21917ec8bab3SRichard Henderson } 21927ec8bab3SRichard Henderson /* The field is split across two words. One double-word 21937ec8bab3SRichard Henderson shift is better than two double-word shifts. */ 21947ec8bab3SRichard Henderson goto do_shift_and; 21957ec8bab3SRichard Henderson } 21967ec8bab3SRichard Henderson 21977ec8bab3SRichard Henderson if (TCG_TARGET_HAS_extract_i64 21987ec8bab3SRichard Henderson && TCG_TARGET_extract_i64_valid(ofs, len)) { 21997ec8bab3SRichard Henderson tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, ofs, len); 22007ec8bab3SRichard Henderson return; 22017ec8bab3SRichard Henderson } 22027ec8bab3SRichard Henderson 22037ec8bab3SRichard Henderson /* Assume that zero-extension, if available, is cheaper than a shift. */ 22047ec8bab3SRichard Henderson switch (ofs + len) { 22057ec8bab3SRichard Henderson case 32: 22067ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext32u_i64) { 22077ec8bab3SRichard Henderson tcg_gen_ext32u_i64(ret, arg); 22087ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, ofs); 22097ec8bab3SRichard Henderson return; 22107ec8bab3SRichard Henderson } 22117ec8bab3SRichard Henderson break; 22127ec8bab3SRichard Henderson case 16: 22137ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16u_i64) { 22147ec8bab3SRichard Henderson tcg_gen_ext16u_i64(ret, arg); 22157ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, ofs); 22167ec8bab3SRichard Henderson return; 22177ec8bab3SRichard Henderson } 22187ec8bab3SRichard Henderson break; 22197ec8bab3SRichard Henderson case 8: 22207ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8u_i64) { 22217ec8bab3SRichard Henderson tcg_gen_ext8u_i64(ret, arg); 22227ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, ofs); 22237ec8bab3SRichard Henderson return; 22247ec8bab3SRichard Henderson } 22257ec8bab3SRichard Henderson break; 22267ec8bab3SRichard Henderson } 22277ec8bab3SRichard Henderson 22287ec8bab3SRichard Henderson /* ??? Ideally we'd know what values are available for immediate AND. 22297ec8bab3SRichard Henderson Assume that 8 bits are available, plus the special cases of 16 and 32, 22307ec8bab3SRichard Henderson so that we get ext8u, ext16u, and ext32u. */ 22317ec8bab3SRichard Henderson switch (len) { 22327ec8bab3SRichard Henderson case 1 ... 8: case 16: case 32: 22337ec8bab3SRichard Henderson do_shift_and: 22347ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 22357ec8bab3SRichard Henderson tcg_gen_andi_i64(ret, ret, (1ull << len) - 1); 22367ec8bab3SRichard Henderson break; 22377ec8bab3SRichard Henderson default: 22387ec8bab3SRichard Henderson tcg_gen_shli_i64(ret, arg, 64 - len - ofs); 22397ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, ret, 64 - len); 22407ec8bab3SRichard Henderson break; 22417ec8bab3SRichard Henderson } 22427ec8bab3SRichard Henderson } 22437ec8bab3SRichard Henderson 22447ec8bab3SRichard Henderson void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg, 22457ec8bab3SRichard Henderson unsigned int ofs, unsigned int len) 22467ec8bab3SRichard Henderson { 22477ec8bab3SRichard Henderson tcg_debug_assert(ofs < 64); 22487ec8bab3SRichard Henderson tcg_debug_assert(len > 0); 22497ec8bab3SRichard Henderson tcg_debug_assert(len <= 64); 22507ec8bab3SRichard Henderson tcg_debug_assert(ofs + len <= 64); 22517ec8bab3SRichard Henderson 22527ec8bab3SRichard Henderson /* Canonicalize certain special cases, even if sextract is supported. */ 22537ec8bab3SRichard Henderson if (ofs + len == 64) { 22547ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, arg, 64 - len); 22557ec8bab3SRichard Henderson return; 22567ec8bab3SRichard Henderson } 22577ec8bab3SRichard Henderson if (ofs == 0) { 22587ec8bab3SRichard Henderson switch (len) { 22597ec8bab3SRichard Henderson case 32: 22607ec8bab3SRichard Henderson tcg_gen_ext32s_i64(ret, arg); 22617ec8bab3SRichard Henderson return; 22627ec8bab3SRichard Henderson case 16: 22637ec8bab3SRichard Henderson tcg_gen_ext16s_i64(ret, arg); 22647ec8bab3SRichard Henderson return; 22657ec8bab3SRichard Henderson case 8: 22667ec8bab3SRichard Henderson tcg_gen_ext8s_i64(ret, arg); 22677ec8bab3SRichard Henderson return; 22687ec8bab3SRichard Henderson } 22697ec8bab3SRichard Henderson } 22707ec8bab3SRichard Henderson 22717ec8bab3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 22727ec8bab3SRichard Henderson /* Look for a 32-bit extract within one of the two words. */ 22737ec8bab3SRichard Henderson if (ofs >= 32) { 22747ec8bab3SRichard Henderson tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len); 22757ec8bab3SRichard Henderson } else if (ofs + len <= 32) { 22767ec8bab3SRichard Henderson tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len); 22777ec8bab3SRichard Henderson } else if (ofs == 0) { 22787ec8bab3SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); 22797ec8bab3SRichard Henderson tcg_gen_sextract_i32(TCGV_HIGH(ret), TCGV_HIGH(arg), 0, len - 32); 22807ec8bab3SRichard Henderson return; 22817ec8bab3SRichard Henderson } else if (len > 32) { 22827ec8bab3SRichard Henderson TCGv_i32 t = tcg_temp_new_i32(); 22837ec8bab3SRichard Henderson /* Extract the bits for the high word normally. */ 22847ec8bab3SRichard Henderson tcg_gen_sextract_i32(t, TCGV_HIGH(arg), ofs + 32, len - 32); 22857ec8bab3SRichard Henderson /* Shift the field down for the low part. */ 22867ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 22877ec8bab3SRichard Henderson /* Overwrite the shift into the high part. */ 22887ec8bab3SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(ret), t); 22897ec8bab3SRichard Henderson tcg_temp_free_i32(t); 22907ec8bab3SRichard Henderson return; 22917ec8bab3SRichard Henderson } else { 22927ec8bab3SRichard Henderson /* Shift the field down for the low part, such that the 22937ec8bab3SRichard Henderson field sits at the MSB. */ 22947ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs + len - 32); 22957ec8bab3SRichard Henderson /* Shift the field down from the MSB, sign extending. */ 22967ec8bab3SRichard Henderson tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_LOW(ret), 32 - len); 22977ec8bab3SRichard Henderson } 22987ec8bab3SRichard Henderson /* Sign-extend the field from 32 bits. */ 22997ec8bab3SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 23007ec8bab3SRichard Henderson return; 23017ec8bab3SRichard Henderson } 23027ec8bab3SRichard Henderson 23037ec8bab3SRichard Henderson if (TCG_TARGET_HAS_sextract_i64 23047ec8bab3SRichard Henderson && TCG_TARGET_extract_i64_valid(ofs, len)) { 23057ec8bab3SRichard Henderson tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, ofs, len); 23067ec8bab3SRichard Henderson return; 23077ec8bab3SRichard Henderson } 23087ec8bab3SRichard Henderson 23097ec8bab3SRichard Henderson /* Assume that sign-extension, if available, is cheaper than a shift. */ 23107ec8bab3SRichard Henderson switch (ofs + len) { 23117ec8bab3SRichard Henderson case 32: 23127ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext32s_i64) { 23137ec8bab3SRichard Henderson tcg_gen_ext32s_i64(ret, arg); 23147ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, ofs); 23157ec8bab3SRichard Henderson return; 23167ec8bab3SRichard Henderson } 23177ec8bab3SRichard Henderson break; 23187ec8bab3SRichard Henderson case 16: 23197ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i64) { 23207ec8bab3SRichard Henderson tcg_gen_ext16s_i64(ret, arg); 23217ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, ofs); 23227ec8bab3SRichard Henderson return; 23237ec8bab3SRichard Henderson } 23247ec8bab3SRichard Henderson break; 23257ec8bab3SRichard Henderson case 8: 23267ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i64) { 23277ec8bab3SRichard Henderson tcg_gen_ext8s_i64(ret, arg); 23287ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, ofs); 23297ec8bab3SRichard Henderson return; 23307ec8bab3SRichard Henderson } 23317ec8bab3SRichard Henderson break; 23327ec8bab3SRichard Henderson } 23337ec8bab3SRichard Henderson switch (len) { 23347ec8bab3SRichard Henderson case 32: 23357ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext32s_i64) { 23367ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 23377ec8bab3SRichard Henderson tcg_gen_ext32s_i64(ret, ret); 23387ec8bab3SRichard Henderson return; 23397ec8bab3SRichard Henderson } 23407ec8bab3SRichard Henderson break; 23417ec8bab3SRichard Henderson case 16: 23427ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext16s_i64) { 23437ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 23447ec8bab3SRichard Henderson tcg_gen_ext16s_i64(ret, ret); 23457ec8bab3SRichard Henderson return; 23467ec8bab3SRichard Henderson } 23477ec8bab3SRichard Henderson break; 23487ec8bab3SRichard Henderson case 8: 23497ec8bab3SRichard Henderson if (TCG_TARGET_HAS_ext8s_i64) { 23507ec8bab3SRichard Henderson tcg_gen_shri_i64(ret, arg, ofs); 23517ec8bab3SRichard Henderson tcg_gen_ext8s_i64(ret, ret); 23527ec8bab3SRichard Henderson return; 23537ec8bab3SRichard Henderson } 23547ec8bab3SRichard Henderson break; 23557ec8bab3SRichard Henderson } 23567ec8bab3SRichard Henderson tcg_gen_shli_i64(ret, arg, 64 - len - ofs); 23577ec8bab3SRichard Henderson tcg_gen_sari_i64(ret, ret, 64 - len); 23587ec8bab3SRichard Henderson } 23597ec8bab3SRichard Henderson 23602089fcc9SDavid Hildenbrand /* 23612089fcc9SDavid Hildenbrand * Extract 64 bits from a 128-bit input, ah:al, starting from ofs. 23622089fcc9SDavid Hildenbrand * Unlike tcg_gen_extract_i64 above, len is fixed at 64. 23632089fcc9SDavid Hildenbrand */ 23642089fcc9SDavid Hildenbrand void tcg_gen_extract2_i64(TCGv_i64 ret, TCGv_i64 al, TCGv_i64 ah, 23652089fcc9SDavid Hildenbrand unsigned int ofs) 23662089fcc9SDavid Hildenbrand { 23672089fcc9SDavid Hildenbrand tcg_debug_assert(ofs <= 64); 23682089fcc9SDavid Hildenbrand if (ofs == 0) { 23692089fcc9SDavid Hildenbrand tcg_gen_mov_i64(ret, al); 23702089fcc9SDavid Hildenbrand } else if (ofs == 64) { 23712089fcc9SDavid Hildenbrand tcg_gen_mov_i64(ret, ah); 23722089fcc9SDavid Hildenbrand } else if (al == ah) { 23732089fcc9SDavid Hildenbrand tcg_gen_rotri_i64(ret, al, ofs); 2374fce1296fSRichard Henderson } else if (TCG_TARGET_HAS_extract2_i64) { 2375fce1296fSRichard Henderson tcg_gen_op4i_i64(INDEX_op_extract2_i64, ret, al, ah, ofs); 23762089fcc9SDavid Hildenbrand } else { 23772089fcc9SDavid Hildenbrand TCGv_i64 t0 = tcg_temp_new_i64(); 23782089fcc9SDavid Hildenbrand tcg_gen_shri_i64(t0, al, ofs); 23792089fcc9SDavid Hildenbrand tcg_gen_deposit_i64(ret, t0, ah, 64 - ofs, ofs); 23802089fcc9SDavid Hildenbrand tcg_temp_free_i64(t0); 23812089fcc9SDavid Hildenbrand } 23822089fcc9SDavid Hildenbrand } 23832089fcc9SDavid Hildenbrand 2384951c6300SRichard Henderson void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1, 2385951c6300SRichard Henderson TCGv_i64 c2, TCGv_i64 v1, TCGv_i64 v2) 2386951c6300SRichard Henderson { 238737ed3bf1SRichard Henderson if (cond == TCG_COND_ALWAYS) { 238837ed3bf1SRichard Henderson tcg_gen_mov_i64(ret, v1); 238937ed3bf1SRichard Henderson } else if (cond == TCG_COND_NEVER) { 239037ed3bf1SRichard Henderson tcg_gen_mov_i64(ret, v2); 239137ed3bf1SRichard Henderson } else if (TCG_TARGET_REG_BITS == 32) { 2392951c6300SRichard Henderson TCGv_i32 t0 = tcg_temp_new_i32(); 2393951c6300SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 2394951c6300SRichard Henderson tcg_gen_op6i_i32(INDEX_op_setcond2_i32, t0, 2395951c6300SRichard Henderson TCGV_LOW(c1), TCGV_HIGH(c1), 2396951c6300SRichard Henderson TCGV_LOW(c2), TCGV_HIGH(c2), cond); 2397951c6300SRichard Henderson 2398951c6300SRichard Henderson if (TCG_TARGET_HAS_movcond_i32) { 2399951c6300SRichard Henderson tcg_gen_movi_i32(t1, 0); 2400951c6300SRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, TCGV_LOW(ret), t0, t1, 2401951c6300SRichard Henderson TCGV_LOW(v1), TCGV_LOW(v2)); 2402951c6300SRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, TCGV_HIGH(ret), t0, t1, 2403951c6300SRichard Henderson TCGV_HIGH(v1), TCGV_HIGH(v2)); 2404951c6300SRichard Henderson } else { 2405951c6300SRichard Henderson tcg_gen_neg_i32(t0, t0); 2406951c6300SRichard Henderson 2407951c6300SRichard Henderson tcg_gen_and_i32(t1, TCGV_LOW(v1), t0); 2408951c6300SRichard Henderson tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(v2), t0); 2409951c6300SRichard Henderson tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t1); 2410951c6300SRichard Henderson 2411951c6300SRichard Henderson tcg_gen_and_i32(t1, TCGV_HIGH(v1), t0); 2412951c6300SRichard Henderson tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(v2), t0); 2413951c6300SRichard Henderson tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t1); 2414951c6300SRichard Henderson } 2415951c6300SRichard Henderson tcg_temp_free_i32(t0); 2416951c6300SRichard Henderson tcg_temp_free_i32(t1); 24173a13c3f3SRichard Henderson } else if (TCG_TARGET_HAS_movcond_i64) { 2418951c6300SRichard Henderson tcg_gen_op6i_i64(INDEX_op_movcond_i64, ret, c1, c2, v1, v2, cond); 2419951c6300SRichard Henderson } else { 2420951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2421951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2422951c6300SRichard Henderson tcg_gen_setcond_i64(cond, t0, c1, c2); 2423951c6300SRichard Henderson tcg_gen_neg_i64(t0, t0); 2424951c6300SRichard Henderson tcg_gen_and_i64(t1, v1, t0); 2425951c6300SRichard Henderson tcg_gen_andc_i64(ret, v2, t0); 2426951c6300SRichard Henderson tcg_gen_or_i64(ret, ret, t1); 2427951c6300SRichard Henderson tcg_temp_free_i64(t0); 2428951c6300SRichard Henderson tcg_temp_free_i64(t1); 2429951c6300SRichard Henderson } 2430951c6300SRichard Henderson } 2431951c6300SRichard Henderson 2432951c6300SRichard Henderson void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, 2433951c6300SRichard Henderson TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) 2434951c6300SRichard Henderson { 2435951c6300SRichard Henderson if (TCG_TARGET_HAS_add2_i64) { 2436951c6300SRichard Henderson tcg_gen_op6_i64(INDEX_op_add2_i64, rl, rh, al, ah, bl, bh); 2437951c6300SRichard Henderson } else { 2438951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2439951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2440951c6300SRichard Henderson tcg_gen_add_i64(t0, al, bl); 2441951c6300SRichard Henderson tcg_gen_setcond_i64(TCG_COND_LTU, t1, t0, al); 2442951c6300SRichard Henderson tcg_gen_add_i64(rh, ah, bh); 2443951c6300SRichard Henderson tcg_gen_add_i64(rh, rh, t1); 2444951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2445951c6300SRichard Henderson tcg_temp_free_i64(t0); 2446951c6300SRichard Henderson tcg_temp_free_i64(t1); 2447951c6300SRichard Henderson } 2448951c6300SRichard Henderson } 2449951c6300SRichard Henderson 2450951c6300SRichard Henderson void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, 2451951c6300SRichard Henderson TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) 2452951c6300SRichard Henderson { 2453951c6300SRichard Henderson if (TCG_TARGET_HAS_sub2_i64) { 2454951c6300SRichard Henderson tcg_gen_op6_i64(INDEX_op_sub2_i64, rl, rh, al, ah, bl, bh); 2455951c6300SRichard Henderson } else { 2456951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2457951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2458951c6300SRichard Henderson tcg_gen_sub_i64(t0, al, bl); 2459951c6300SRichard Henderson tcg_gen_setcond_i64(TCG_COND_LTU, t1, al, bl); 2460951c6300SRichard Henderson tcg_gen_sub_i64(rh, ah, bh); 2461951c6300SRichard Henderson tcg_gen_sub_i64(rh, rh, t1); 2462951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2463951c6300SRichard Henderson tcg_temp_free_i64(t0); 2464951c6300SRichard Henderson tcg_temp_free_i64(t1); 2465951c6300SRichard Henderson } 2466951c6300SRichard Henderson } 2467951c6300SRichard Henderson 2468951c6300SRichard Henderson void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) 2469951c6300SRichard Henderson { 2470951c6300SRichard Henderson if (TCG_TARGET_HAS_mulu2_i64) { 2471951c6300SRichard Henderson tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2); 2472951c6300SRichard Henderson } else if (TCG_TARGET_HAS_muluh_i64) { 2473951c6300SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2474951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2); 2475951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_muluh_i64, rh, arg1, arg2); 2476951c6300SRichard Henderson tcg_gen_mov_i64(rl, t); 2477951c6300SRichard Henderson tcg_temp_free_i64(t); 2478951c6300SRichard Henderson } else { 2479951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2480951c6300SRichard Henderson tcg_gen_mul_i64(t0, arg1, arg2); 2481951c6300SRichard Henderson gen_helper_muluh_i64(rh, arg1, arg2); 2482951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2483951c6300SRichard Henderson tcg_temp_free_i64(t0); 2484951c6300SRichard Henderson } 2485951c6300SRichard Henderson } 2486951c6300SRichard Henderson 2487951c6300SRichard Henderson void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) 2488951c6300SRichard Henderson { 2489951c6300SRichard Henderson if (TCG_TARGET_HAS_muls2_i64) { 2490951c6300SRichard Henderson tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2); 2491951c6300SRichard Henderson } else if (TCG_TARGET_HAS_mulsh_i64) { 2492951c6300SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2493951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2); 2494951c6300SRichard Henderson tcg_gen_op3_i64(INDEX_op_mulsh_i64, rh, arg1, arg2); 2495951c6300SRichard Henderson tcg_gen_mov_i64(rl, t); 2496951c6300SRichard Henderson tcg_temp_free_i64(t); 2497951c6300SRichard Henderson } else if (TCG_TARGET_HAS_mulu2_i64 || TCG_TARGET_HAS_muluh_i64) { 2498951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2499951c6300SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 2500951c6300SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 2501951c6300SRichard Henderson TCGv_i64 t3 = tcg_temp_new_i64(); 2502951c6300SRichard Henderson tcg_gen_mulu2_i64(t0, t1, arg1, arg2); 2503951c6300SRichard Henderson /* Adjust for negative inputs. */ 2504951c6300SRichard Henderson tcg_gen_sari_i64(t2, arg1, 63); 2505951c6300SRichard Henderson tcg_gen_sari_i64(t3, arg2, 63); 2506951c6300SRichard Henderson tcg_gen_and_i64(t2, t2, arg2); 2507951c6300SRichard Henderson tcg_gen_and_i64(t3, t3, arg1); 2508951c6300SRichard Henderson tcg_gen_sub_i64(rh, t1, t2); 2509951c6300SRichard Henderson tcg_gen_sub_i64(rh, rh, t3); 2510951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2511951c6300SRichard Henderson tcg_temp_free_i64(t0); 2512951c6300SRichard Henderson tcg_temp_free_i64(t1); 2513951c6300SRichard Henderson tcg_temp_free_i64(t2); 2514951c6300SRichard Henderson tcg_temp_free_i64(t3); 2515951c6300SRichard Henderson } else { 2516951c6300SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 2517951c6300SRichard Henderson tcg_gen_mul_i64(t0, arg1, arg2); 2518951c6300SRichard Henderson gen_helper_mulsh_i64(rh, arg1, arg2); 2519951c6300SRichard Henderson tcg_gen_mov_i64(rl, t0); 2520951c6300SRichard Henderson tcg_temp_free_i64(t0); 2521951c6300SRichard Henderson } 2522951c6300SRichard Henderson } 2523951c6300SRichard Henderson 25245087abfbSRichard Henderson void tcg_gen_mulsu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) 25255087abfbSRichard Henderson { 25265087abfbSRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 25275087abfbSRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 25285087abfbSRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 25295087abfbSRichard Henderson tcg_gen_mulu2_i64(t0, t1, arg1, arg2); 25305087abfbSRichard Henderson /* Adjust for negative input for the signed arg1. */ 25315087abfbSRichard Henderson tcg_gen_sari_i64(t2, arg1, 63); 25325087abfbSRichard Henderson tcg_gen_and_i64(t2, t2, arg2); 25335087abfbSRichard Henderson tcg_gen_sub_i64(rh, t1, t2); 25345087abfbSRichard Henderson tcg_gen_mov_i64(rl, t0); 25355087abfbSRichard Henderson tcg_temp_free_i64(t0); 25365087abfbSRichard Henderson tcg_temp_free_i64(t1); 25375087abfbSRichard Henderson tcg_temp_free_i64(t2); 25385087abfbSRichard Henderson } 25395087abfbSRichard Henderson 2540b87fb8cdSRichard Henderson void tcg_gen_smin_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2541b87fb8cdSRichard Henderson { 2542b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LT, ret, a, b, a, b); 2543b87fb8cdSRichard Henderson } 2544b87fb8cdSRichard Henderson 2545b87fb8cdSRichard Henderson void tcg_gen_umin_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2546b87fb8cdSRichard Henderson { 2547b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, a, b); 2548b87fb8cdSRichard Henderson } 2549b87fb8cdSRichard Henderson 2550b87fb8cdSRichard Henderson void tcg_gen_smax_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2551b87fb8cdSRichard Henderson { 2552b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LT, ret, a, b, b, a); 2553b87fb8cdSRichard Henderson } 2554b87fb8cdSRichard Henderson 2555b87fb8cdSRichard Henderson void tcg_gen_umax_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 2556b87fb8cdSRichard Henderson { 2557b87fb8cdSRichard Henderson tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, b, a); 2558b87fb8cdSRichard Henderson } 2559b87fb8cdSRichard Henderson 2560ff1f11f7SRichard Henderson void tcg_gen_abs_i64(TCGv_i64 ret, TCGv_i64 a) 2561ff1f11f7SRichard Henderson { 2562ff1f11f7SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2563ff1f11f7SRichard Henderson 2564ff1f11f7SRichard Henderson tcg_gen_sari_i64(t, a, 63); 2565ff1f11f7SRichard Henderson tcg_gen_xor_i64(ret, a, t); 2566ff1f11f7SRichard Henderson tcg_gen_sub_i64(ret, ret, t); 2567ff1f11f7SRichard Henderson tcg_temp_free_i64(t); 2568ff1f11f7SRichard Henderson } 2569ff1f11f7SRichard Henderson 2570951c6300SRichard Henderson /* Size changing operations. */ 2571951c6300SRichard Henderson 2572609ad705SRichard Henderson void tcg_gen_extrl_i64_i32(TCGv_i32 ret, TCGv_i64 arg) 2573951c6300SRichard Henderson { 25743a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2575951c6300SRichard Henderson tcg_gen_mov_i32(ret, TCGV_LOW(arg)); 2576609ad705SRichard Henderson } else if (TCG_TARGET_HAS_extrl_i64_i32) { 2577b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_extrl_i64_i32, 2578ae8b75dcSRichard Henderson tcgv_i32_arg(ret), tcgv_i64_arg(arg)); 2579951c6300SRichard Henderson } else { 2580dc41aa7dSRichard Henderson tcg_gen_mov_i32(ret, (TCGv_i32)arg); 2581609ad705SRichard Henderson } 2582609ad705SRichard Henderson } 2583609ad705SRichard Henderson 2584609ad705SRichard Henderson void tcg_gen_extrh_i64_i32(TCGv_i32 ret, TCGv_i64 arg) 2585609ad705SRichard Henderson { 2586609ad705SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2587609ad705SRichard Henderson tcg_gen_mov_i32(ret, TCGV_HIGH(arg)); 2588609ad705SRichard Henderson } else if (TCG_TARGET_HAS_extrh_i64_i32) { 2589b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_extrh_i64_i32, 2590ae8b75dcSRichard Henderson tcgv_i32_arg(ret), tcgv_i64_arg(arg)); 2591951c6300SRichard Henderson } else { 2592951c6300SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2593609ad705SRichard Henderson tcg_gen_shri_i64(t, arg, 32); 2594dc41aa7dSRichard Henderson tcg_gen_mov_i32(ret, (TCGv_i32)t); 2595951c6300SRichard Henderson tcg_temp_free_i64(t); 2596951c6300SRichard Henderson } 2597951c6300SRichard Henderson } 2598951c6300SRichard Henderson 2599951c6300SRichard Henderson void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg) 2600951c6300SRichard Henderson { 26013a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2602951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), arg); 2603951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 26043a13c3f3SRichard Henderson } else { 2605b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_extu_i32_i64, 2606ae8b75dcSRichard Henderson tcgv_i64_arg(ret), tcgv_i32_arg(arg)); 26073a13c3f3SRichard Henderson } 2608951c6300SRichard Henderson } 2609951c6300SRichard Henderson 2610951c6300SRichard Henderson void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg) 2611951c6300SRichard Henderson { 26123a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2613951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(ret), arg); 2614951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); 26153a13c3f3SRichard Henderson } else { 2616b7e8b17aSRichard Henderson tcg_gen_op2(INDEX_op_ext_i32_i64, 2617ae8b75dcSRichard Henderson tcgv_i64_arg(ret), tcgv_i32_arg(arg)); 26183a13c3f3SRichard Henderson } 2619951c6300SRichard Henderson } 2620951c6300SRichard Henderson 2621951c6300SRichard Henderson void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high) 2622951c6300SRichard Henderson { 26233a13c3f3SRichard Henderson TCGv_i64 tmp; 26243a13c3f3SRichard Henderson 26253a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2626951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_LOW(dest), low); 2627951c6300SRichard Henderson tcg_gen_mov_i32(TCGV_HIGH(dest), high); 26283a13c3f3SRichard Henderson return; 26293a13c3f3SRichard Henderson } 26303a13c3f3SRichard Henderson 26313a13c3f3SRichard Henderson tmp = tcg_temp_new_i64(); 2632951c6300SRichard Henderson /* These extensions are only needed for type correctness. 2633951c6300SRichard Henderson We may be able to do better given target specific information. */ 2634951c6300SRichard Henderson tcg_gen_extu_i32_i64(tmp, high); 2635951c6300SRichard Henderson tcg_gen_extu_i32_i64(dest, low); 2636951c6300SRichard Henderson /* If deposit is available, use it. Otherwise use the extra 2637951c6300SRichard Henderson knowledge that we have of the zero-extensions above. */ 2638951c6300SRichard Henderson if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(32, 32)) { 2639951c6300SRichard Henderson tcg_gen_deposit_i64(dest, dest, tmp, 32, 32); 2640951c6300SRichard Henderson } else { 2641951c6300SRichard Henderson tcg_gen_shli_i64(tmp, tmp, 32); 2642951c6300SRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 2643951c6300SRichard Henderson } 2644951c6300SRichard Henderson tcg_temp_free_i64(tmp); 2645951c6300SRichard Henderson } 2646951c6300SRichard Henderson 2647951c6300SRichard Henderson void tcg_gen_extr_i64_i32(TCGv_i32 lo, TCGv_i32 hi, TCGv_i64 arg) 2648951c6300SRichard Henderson { 26493a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 2650951c6300SRichard Henderson tcg_gen_mov_i32(lo, TCGV_LOW(arg)); 2651951c6300SRichard Henderson tcg_gen_mov_i32(hi, TCGV_HIGH(arg)); 26523a13c3f3SRichard Henderson } else { 2653609ad705SRichard Henderson tcg_gen_extrl_i64_i32(lo, arg); 2654609ad705SRichard Henderson tcg_gen_extrh_i64_i32(hi, arg); 26553a13c3f3SRichard Henderson } 2656951c6300SRichard Henderson } 2657951c6300SRichard Henderson 2658951c6300SRichard Henderson void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg) 2659951c6300SRichard Henderson { 2660951c6300SRichard Henderson tcg_gen_ext32u_i64(lo, arg); 2661951c6300SRichard Henderson tcg_gen_shri_i64(hi, arg, 32); 2662951c6300SRichard Henderson } 2663951c6300SRichard Henderson 2664951c6300SRichard Henderson /* QEMU specific operations. */ 2665951c6300SRichard Henderson 266607ea28b4SRichard Henderson void tcg_gen_exit_tb(TranslationBlock *tb, unsigned idx) 266707ea28b4SRichard Henderson { 266807ea28b4SRichard Henderson uintptr_t val = (uintptr_t)tb + idx; 266907ea28b4SRichard Henderson 267007ea28b4SRichard Henderson if (tb == NULL) { 267107ea28b4SRichard Henderson tcg_debug_assert(idx == 0); 267207ea28b4SRichard Henderson } else if (idx <= TB_EXIT_IDXMAX) { 267307ea28b4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 267407ea28b4SRichard Henderson /* This is an exit following a goto_tb. Verify that we have 267507ea28b4SRichard Henderson seen this numbered exit before, via tcg_gen_goto_tb. */ 267607ea28b4SRichard Henderson tcg_debug_assert(tcg_ctx->goto_tb_issue_mask & (1 << idx)); 267707ea28b4SRichard Henderson #endif 2678d7f425fdSRichard Henderson /* When not chaining, exit without indicating a link. */ 2679d7f425fdSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { 2680d7f425fdSRichard Henderson val = 0; 2681d7f425fdSRichard Henderson } 268207ea28b4SRichard Henderson } else { 268307ea28b4SRichard Henderson /* This is an exit via the exitreq label. */ 268407ea28b4SRichard Henderson tcg_debug_assert(idx == TB_EXIT_REQUESTED); 268507ea28b4SRichard Henderson } 268607ea28b4SRichard Henderson 268707ea28b4SRichard Henderson tcg_gen_op1i(INDEX_op_exit_tb, val); 268807ea28b4SRichard Henderson } 268907ea28b4SRichard Henderson 2690951c6300SRichard Henderson void tcg_gen_goto_tb(unsigned idx) 2691951c6300SRichard Henderson { 2692951c6300SRichard Henderson /* We only support two chained exits. */ 269307ea28b4SRichard Henderson tcg_debug_assert(idx <= TB_EXIT_IDXMAX); 2694951c6300SRichard Henderson #ifdef CONFIG_DEBUG_TCG 2695951c6300SRichard Henderson /* Verify that we havn't seen this numbered exit before. */ 2696b1311c4aSEmilio G. Cota tcg_debug_assert((tcg_ctx->goto_tb_issue_mask & (1 << idx)) == 0); 2697b1311c4aSEmilio G. Cota tcg_ctx->goto_tb_issue_mask |= 1 << idx; 2698951c6300SRichard Henderson #endif 2699d7f425fdSRichard Henderson /* When not chaining, we simply fall through to the "fallback" exit. */ 2700d7f425fdSRichard Henderson if (!qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { 2701951c6300SRichard Henderson tcg_gen_op1i(INDEX_op_goto_tb, idx); 2702951c6300SRichard Henderson } 2703d7f425fdSRichard Henderson } 2704951c6300SRichard Henderson 27057f11636dSEmilio G. Cota void tcg_gen_lookup_and_goto_ptr(void) 2706cedbcb01SEmilio G. Cota { 2707cedbcb01SEmilio G. Cota if (TCG_TARGET_HAS_goto_ptr && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { 2708cedbcb01SEmilio G. Cota TCGv_ptr ptr = tcg_temp_new_ptr(); 27091c2adb95SRichard Henderson gen_helper_lookup_tb_ptr(ptr, cpu_env); 2710ae8b75dcSRichard Henderson tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr)); 2711cedbcb01SEmilio G. Cota tcg_temp_free_ptr(ptr); 2712cedbcb01SEmilio G. Cota } else { 271307ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 2714cedbcb01SEmilio G. Cota } 2715cedbcb01SEmilio G. Cota } 2716cedbcb01SEmilio G. Cota 2717*14776ab5STony Nguyen static inline MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st) 2718951c6300SRichard Henderson { 27191f00b27fSSergey Sorokin /* Trigger the asserts within as early as possible. */ 27201f00b27fSSergey Sorokin (void)get_alignment_bits(op); 27211f00b27fSSergey Sorokin 2722951c6300SRichard Henderson switch (op & MO_SIZE) { 2723951c6300SRichard Henderson case MO_8: 2724951c6300SRichard Henderson op &= ~MO_BSWAP; 2725951c6300SRichard Henderson break; 2726951c6300SRichard Henderson case MO_16: 2727951c6300SRichard Henderson break; 2728951c6300SRichard Henderson case MO_32: 2729951c6300SRichard Henderson if (!is64) { 2730951c6300SRichard Henderson op &= ~MO_SIGN; 2731951c6300SRichard Henderson } 2732951c6300SRichard Henderson break; 2733951c6300SRichard Henderson case MO_64: 2734951c6300SRichard Henderson if (!is64) { 2735951c6300SRichard Henderson tcg_abort(); 2736951c6300SRichard Henderson } 2737951c6300SRichard Henderson break; 2738951c6300SRichard Henderson } 2739951c6300SRichard Henderson if (st) { 2740951c6300SRichard Henderson op &= ~MO_SIGN; 2741951c6300SRichard Henderson } 2742951c6300SRichard Henderson return op; 2743951c6300SRichard Henderson } 2744951c6300SRichard Henderson 2745c45cb8bbSRichard Henderson static void gen_ldst_i32(TCGOpcode opc, TCGv_i32 val, TCGv addr, 2746*14776ab5STony Nguyen MemOp memop, TCGArg idx) 2747951c6300SRichard Henderson { 274859227d5dSRichard Henderson TCGMemOpIdx oi = make_memop_idx(memop, idx); 2749951c6300SRichard Henderson #if TARGET_LONG_BITS == 32 275059227d5dSRichard Henderson tcg_gen_op3i_i32(opc, val, addr, oi); 2751951c6300SRichard Henderson #else 2752c45cb8bbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 275359227d5dSRichard Henderson tcg_gen_op4i_i32(opc, val, TCGV_LOW(addr), TCGV_HIGH(addr), oi); 2754c45cb8bbSRichard Henderson } else { 2755ae8b75dcSRichard Henderson tcg_gen_op3(opc, tcgv_i32_arg(val), tcgv_i64_arg(addr), oi); 2756c45cb8bbSRichard Henderson } 2757951c6300SRichard Henderson #endif 2758c45cb8bbSRichard Henderson } 2759c45cb8bbSRichard Henderson 2760c45cb8bbSRichard Henderson static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 val, TCGv addr, 2761*14776ab5STony Nguyen MemOp memop, TCGArg idx) 2762c45cb8bbSRichard Henderson { 276359227d5dSRichard Henderson TCGMemOpIdx oi = make_memop_idx(memop, idx); 2764c45cb8bbSRichard Henderson #if TARGET_LONG_BITS == 32 2765c45cb8bbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 276659227d5dSRichard Henderson tcg_gen_op4i_i32(opc, TCGV_LOW(val), TCGV_HIGH(val), addr, oi); 2767c45cb8bbSRichard Henderson } else { 2768ae8b75dcSRichard Henderson tcg_gen_op3(opc, tcgv_i64_arg(val), tcgv_i32_arg(addr), oi); 2769c45cb8bbSRichard Henderson } 2770c45cb8bbSRichard Henderson #else 2771c45cb8bbSRichard Henderson if (TCG_TARGET_REG_BITS == 32) { 277259227d5dSRichard Henderson tcg_gen_op5i_i32(opc, TCGV_LOW(val), TCGV_HIGH(val), 277359227d5dSRichard Henderson TCGV_LOW(addr), TCGV_HIGH(addr), oi); 2774c45cb8bbSRichard Henderson } else { 277559227d5dSRichard Henderson tcg_gen_op3i_i64(opc, val, addr, oi); 2776c45cb8bbSRichard Henderson } 2777c45cb8bbSRichard Henderson #endif 2778c45cb8bbSRichard Henderson } 2779951c6300SRichard Henderson 2780b32dc337SPranith Kumar static void tcg_gen_req_mo(TCGBar type) 2781b32dc337SPranith Kumar { 2782b32dc337SPranith Kumar #ifdef TCG_GUEST_DEFAULT_MO 2783b32dc337SPranith Kumar type &= TCG_GUEST_DEFAULT_MO; 2784b32dc337SPranith Kumar #endif 2785b32dc337SPranith Kumar type &= ~TCG_TARGET_DEFAULT_MO; 2786b32dc337SPranith Kumar if (type) { 2787b32dc337SPranith Kumar tcg_gen_mb(type | TCG_BAR_SC); 2788b32dc337SPranith Kumar } 2789b32dc337SPranith Kumar } 2790b32dc337SPranith Kumar 2791*14776ab5STony Nguyen void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) 2792951c6300SRichard Henderson { 2793*14776ab5STony Nguyen MemOp orig_memop; 2794e1dcf352SRichard Henderson 2795b32dc337SPranith Kumar tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 2796951c6300SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 27971c2adb95SRichard Henderson trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, 2798dcdaadb6SLluís Vilanova addr, trace_mem_get_info(memop, 0)); 2799e1dcf352SRichard Henderson 2800e1dcf352SRichard Henderson orig_memop = memop; 2801e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 2802e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 2803e1dcf352SRichard Henderson /* The bswap primitive requires zero-extended input. */ 2804e1dcf352SRichard Henderson if ((memop & MO_SSIZE) == MO_SW) { 2805e1dcf352SRichard Henderson memop &= ~MO_SIGN; 2806e1dcf352SRichard Henderson } 2807e1dcf352SRichard Henderson } 2808e1dcf352SRichard Henderson 2809c45cb8bbSRichard Henderson gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx); 2810e1dcf352SRichard Henderson 2811e1dcf352SRichard Henderson if ((orig_memop ^ memop) & MO_BSWAP) { 2812e1dcf352SRichard Henderson switch (orig_memop & MO_SIZE) { 2813e1dcf352SRichard Henderson case MO_16: 2814e1dcf352SRichard Henderson tcg_gen_bswap16_i32(val, val); 2815e1dcf352SRichard Henderson if (orig_memop & MO_SIGN) { 2816e1dcf352SRichard Henderson tcg_gen_ext16s_i32(val, val); 2817e1dcf352SRichard Henderson } 2818e1dcf352SRichard Henderson break; 2819e1dcf352SRichard Henderson case MO_32: 2820e1dcf352SRichard Henderson tcg_gen_bswap32_i32(val, val); 2821e1dcf352SRichard Henderson break; 2822e1dcf352SRichard Henderson default: 2823e1dcf352SRichard Henderson g_assert_not_reached(); 2824e1dcf352SRichard Henderson } 2825e1dcf352SRichard Henderson } 2826951c6300SRichard Henderson } 2827951c6300SRichard Henderson 2828*14776ab5STony Nguyen void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) 2829951c6300SRichard Henderson { 2830e1dcf352SRichard Henderson TCGv_i32 swap = NULL; 2831e1dcf352SRichard Henderson 2832b32dc337SPranith Kumar tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 2833951c6300SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 1); 28341c2adb95SRichard Henderson trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, 2835dcdaadb6SLluís Vilanova addr, trace_mem_get_info(memop, 1)); 2836e1dcf352SRichard Henderson 2837e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 2838e1dcf352SRichard Henderson swap = tcg_temp_new_i32(); 2839e1dcf352SRichard Henderson switch (memop & MO_SIZE) { 2840e1dcf352SRichard Henderson case MO_16: 2841e1dcf352SRichard Henderson tcg_gen_ext16u_i32(swap, val); 2842e1dcf352SRichard Henderson tcg_gen_bswap16_i32(swap, swap); 2843e1dcf352SRichard Henderson break; 2844e1dcf352SRichard Henderson case MO_32: 2845e1dcf352SRichard Henderson tcg_gen_bswap32_i32(swap, val); 2846e1dcf352SRichard Henderson break; 2847e1dcf352SRichard Henderson default: 2848e1dcf352SRichard Henderson g_assert_not_reached(); 2849e1dcf352SRichard Henderson } 2850e1dcf352SRichard Henderson val = swap; 2851e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 2852e1dcf352SRichard Henderson } 2853e1dcf352SRichard Henderson 2854c45cb8bbSRichard Henderson gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx); 2855e1dcf352SRichard Henderson 2856e1dcf352SRichard Henderson if (swap) { 2857e1dcf352SRichard Henderson tcg_temp_free_i32(swap); 2858e1dcf352SRichard Henderson } 2859951c6300SRichard Henderson } 2860951c6300SRichard Henderson 2861*14776ab5STony Nguyen void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) 2862951c6300SRichard Henderson { 2863*14776ab5STony Nguyen MemOp orig_memop; 2864e1dcf352SRichard Henderson 28653a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) { 2866951c6300SRichard Henderson tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop); 2867951c6300SRichard Henderson if (memop & MO_SIGN) { 2868951c6300SRichard Henderson tcg_gen_sari_i32(TCGV_HIGH(val), TCGV_LOW(val), 31); 2869951c6300SRichard Henderson } else { 2870951c6300SRichard Henderson tcg_gen_movi_i32(TCGV_HIGH(val), 0); 2871951c6300SRichard Henderson } 2872951c6300SRichard Henderson return; 2873951c6300SRichard Henderson } 2874951c6300SRichard Henderson 2875e1dcf352SRichard Henderson tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 2876c45cb8bbSRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 28771c2adb95SRichard Henderson trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, 2878dcdaadb6SLluís Vilanova addr, trace_mem_get_info(memop, 0)); 2879e1dcf352SRichard Henderson 2880e1dcf352SRichard Henderson orig_memop = memop; 2881e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 2882e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 2883e1dcf352SRichard Henderson /* The bswap primitive requires zero-extended input. */ 2884e1dcf352SRichard Henderson if ((memop & MO_SIGN) && (memop & MO_SIZE) < MO_64) { 2885e1dcf352SRichard Henderson memop &= ~MO_SIGN; 2886e1dcf352SRichard Henderson } 2887e1dcf352SRichard Henderson } 2888e1dcf352SRichard Henderson 2889c45cb8bbSRichard Henderson gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx); 2890e1dcf352SRichard Henderson 2891e1dcf352SRichard Henderson if ((orig_memop ^ memop) & MO_BSWAP) { 2892e1dcf352SRichard Henderson switch (orig_memop & MO_SIZE) { 2893e1dcf352SRichard Henderson case MO_16: 2894e1dcf352SRichard Henderson tcg_gen_bswap16_i64(val, val); 2895e1dcf352SRichard Henderson if (orig_memop & MO_SIGN) { 2896e1dcf352SRichard Henderson tcg_gen_ext16s_i64(val, val); 2897e1dcf352SRichard Henderson } 2898e1dcf352SRichard Henderson break; 2899e1dcf352SRichard Henderson case MO_32: 2900e1dcf352SRichard Henderson tcg_gen_bswap32_i64(val, val); 2901e1dcf352SRichard Henderson if (orig_memop & MO_SIGN) { 2902e1dcf352SRichard Henderson tcg_gen_ext32s_i64(val, val); 2903e1dcf352SRichard Henderson } 2904e1dcf352SRichard Henderson break; 2905e1dcf352SRichard Henderson case MO_64: 2906e1dcf352SRichard Henderson tcg_gen_bswap64_i64(val, val); 2907e1dcf352SRichard Henderson break; 2908e1dcf352SRichard Henderson default: 2909e1dcf352SRichard Henderson g_assert_not_reached(); 2910e1dcf352SRichard Henderson } 2911e1dcf352SRichard Henderson } 2912951c6300SRichard Henderson } 2913951c6300SRichard Henderson 2914*14776ab5STony Nguyen void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) 2915951c6300SRichard Henderson { 2916e1dcf352SRichard Henderson TCGv_i64 swap = NULL; 2917e1dcf352SRichard Henderson 29183a13c3f3SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) { 2919951c6300SRichard Henderson tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop); 2920951c6300SRichard Henderson return; 2921951c6300SRichard Henderson } 2922951c6300SRichard Henderson 2923e1dcf352SRichard Henderson tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 2924c45cb8bbSRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 1); 29251c2adb95SRichard Henderson trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, 2926dcdaadb6SLluís Vilanova addr, trace_mem_get_info(memop, 1)); 2927e1dcf352SRichard Henderson 2928e1dcf352SRichard Henderson if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) { 2929e1dcf352SRichard Henderson swap = tcg_temp_new_i64(); 2930e1dcf352SRichard Henderson switch (memop & MO_SIZE) { 2931e1dcf352SRichard Henderson case MO_16: 2932e1dcf352SRichard Henderson tcg_gen_ext16u_i64(swap, val); 2933e1dcf352SRichard Henderson tcg_gen_bswap16_i64(swap, swap); 2934e1dcf352SRichard Henderson break; 2935e1dcf352SRichard Henderson case MO_32: 2936e1dcf352SRichard Henderson tcg_gen_ext32u_i64(swap, val); 2937e1dcf352SRichard Henderson tcg_gen_bswap32_i64(swap, swap); 2938e1dcf352SRichard Henderson break; 2939e1dcf352SRichard Henderson case MO_64: 2940e1dcf352SRichard Henderson tcg_gen_bswap64_i64(swap, val); 2941e1dcf352SRichard Henderson break; 2942e1dcf352SRichard Henderson default: 2943e1dcf352SRichard Henderson g_assert_not_reached(); 2944e1dcf352SRichard Henderson } 2945e1dcf352SRichard Henderson val = swap; 2946e1dcf352SRichard Henderson memop &= ~MO_BSWAP; 2947e1dcf352SRichard Henderson } 2948e1dcf352SRichard Henderson 2949c45cb8bbSRichard Henderson gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx); 2950e1dcf352SRichard Henderson 2951e1dcf352SRichard Henderson if (swap) { 2952e1dcf352SRichard Henderson tcg_temp_free_i64(swap); 2953e1dcf352SRichard Henderson } 2954951c6300SRichard Henderson } 2955c482cb11SRichard Henderson 2956*14776ab5STony Nguyen static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc) 2957c482cb11SRichard Henderson { 2958c482cb11SRichard Henderson switch (opc & MO_SSIZE) { 2959c482cb11SRichard Henderson case MO_SB: 2960c482cb11SRichard Henderson tcg_gen_ext8s_i32(ret, val); 2961c482cb11SRichard Henderson break; 2962c482cb11SRichard Henderson case MO_UB: 2963c482cb11SRichard Henderson tcg_gen_ext8u_i32(ret, val); 2964c482cb11SRichard Henderson break; 2965c482cb11SRichard Henderson case MO_SW: 2966c482cb11SRichard Henderson tcg_gen_ext16s_i32(ret, val); 2967c482cb11SRichard Henderson break; 2968c482cb11SRichard Henderson case MO_UW: 2969c482cb11SRichard Henderson tcg_gen_ext16u_i32(ret, val); 2970c482cb11SRichard Henderson break; 2971c482cb11SRichard Henderson default: 2972c482cb11SRichard Henderson tcg_gen_mov_i32(ret, val); 2973c482cb11SRichard Henderson break; 2974c482cb11SRichard Henderson } 2975c482cb11SRichard Henderson } 2976c482cb11SRichard Henderson 2977*14776ab5STony Nguyen static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc) 2978c482cb11SRichard Henderson { 2979c482cb11SRichard Henderson switch (opc & MO_SSIZE) { 2980c482cb11SRichard Henderson case MO_SB: 2981c482cb11SRichard Henderson tcg_gen_ext8s_i64(ret, val); 2982c482cb11SRichard Henderson break; 2983c482cb11SRichard Henderson case MO_UB: 2984c482cb11SRichard Henderson tcg_gen_ext8u_i64(ret, val); 2985c482cb11SRichard Henderson break; 2986c482cb11SRichard Henderson case MO_SW: 2987c482cb11SRichard Henderson tcg_gen_ext16s_i64(ret, val); 2988c482cb11SRichard Henderson break; 2989c482cb11SRichard Henderson case MO_UW: 2990c482cb11SRichard Henderson tcg_gen_ext16u_i64(ret, val); 2991c482cb11SRichard Henderson break; 2992c482cb11SRichard Henderson case MO_SL: 2993c482cb11SRichard Henderson tcg_gen_ext32s_i64(ret, val); 2994c482cb11SRichard Henderson break; 2995c482cb11SRichard Henderson case MO_UL: 2996c482cb11SRichard Henderson tcg_gen_ext32u_i64(ret, val); 2997c482cb11SRichard Henderson break; 2998c482cb11SRichard Henderson default: 2999c482cb11SRichard Henderson tcg_gen_mov_i64(ret, val); 3000c482cb11SRichard Henderson break; 3001c482cb11SRichard Henderson } 3002c482cb11SRichard Henderson } 3003c482cb11SRichard Henderson 3004c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU 3005c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv, 3006c482cb11SRichard Henderson TCGv_i32, TCGv_i32, TCGv_i32); 3007c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv, 3008c482cb11SRichard Henderson TCGv_i64, TCGv_i64, TCGv_i32); 3009c482cb11SRichard Henderson typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv, 3010c482cb11SRichard Henderson TCGv_i32, TCGv_i32); 3011c482cb11SRichard Henderson typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv, 3012c482cb11SRichard Henderson TCGv_i64, TCGv_i32); 3013c482cb11SRichard Henderson #else 3014c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32, TCGv_i32); 3015c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv, TCGv_i64, TCGv_i64); 3016c482cb11SRichard Henderson typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32); 3017c482cb11SRichard Henderson typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv, TCGv_i64); 3018c482cb11SRichard Henderson #endif 3019c482cb11SRichard Henderson 3020df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64 3021df79b996SRichard Henderson # define WITH_ATOMIC64(X) X, 3022df79b996SRichard Henderson #else 3023df79b996SRichard Henderson # define WITH_ATOMIC64(X) 3024df79b996SRichard Henderson #endif 3025df79b996SRichard Henderson 3026c482cb11SRichard Henderson static void * const table_cmpxchg[16] = { 3027c482cb11SRichard Henderson [MO_8] = gen_helper_atomic_cmpxchgb, 3028c482cb11SRichard Henderson [MO_16 | MO_LE] = gen_helper_atomic_cmpxchgw_le, 3029c482cb11SRichard Henderson [MO_16 | MO_BE] = gen_helper_atomic_cmpxchgw_be, 3030c482cb11SRichard Henderson [MO_32 | MO_LE] = gen_helper_atomic_cmpxchgl_le, 3031c482cb11SRichard Henderson [MO_32 | MO_BE] = gen_helper_atomic_cmpxchgl_be, 3032df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_cmpxchgq_le) 3033df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_cmpxchgq_be) 3034c482cb11SRichard Henderson }; 3035c482cb11SRichard Henderson 3036c482cb11SRichard Henderson void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv, 3037*14776ab5STony Nguyen TCGv_i32 newv, TCGArg idx, MemOp memop) 3038c482cb11SRichard Henderson { 3039c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 3040c482cb11SRichard Henderson 3041b1311c4aSEmilio G. Cota if (!(tcg_ctx->tb_cflags & CF_PARALLEL)) { 3042c482cb11SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 3043c482cb11SRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 3044c482cb11SRichard Henderson 3045c482cb11SRichard Henderson tcg_gen_ext_i32(t2, cmpv, memop & MO_SIZE); 3046c482cb11SRichard Henderson 3047c482cb11SRichard Henderson tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN); 3048c482cb11SRichard Henderson tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, t2, newv, t1); 3049c482cb11SRichard Henderson tcg_gen_qemu_st_i32(t2, addr, idx, memop); 3050c482cb11SRichard Henderson tcg_temp_free_i32(t2); 3051c482cb11SRichard Henderson 3052c482cb11SRichard Henderson if (memop & MO_SIGN) { 3053c482cb11SRichard Henderson tcg_gen_ext_i32(retv, t1, memop); 3054c482cb11SRichard Henderson } else { 3055c482cb11SRichard Henderson tcg_gen_mov_i32(retv, t1); 3056c482cb11SRichard Henderson } 3057c482cb11SRichard Henderson tcg_temp_free_i32(t1); 3058c482cb11SRichard Henderson } else { 3059c482cb11SRichard Henderson gen_atomic_cx_i32 gen; 3060c482cb11SRichard Henderson 3061c482cb11SRichard Henderson gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; 3062c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3063c482cb11SRichard Henderson 3064c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU 3065c482cb11SRichard Henderson { 3066c482cb11SRichard Henderson TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop & ~MO_SIGN, idx)); 30671c2adb95SRichard Henderson gen(retv, cpu_env, addr, cmpv, newv, oi); 3068c482cb11SRichard Henderson tcg_temp_free_i32(oi); 3069c482cb11SRichard Henderson } 3070c482cb11SRichard Henderson #else 30711c2adb95SRichard Henderson gen(retv, cpu_env, addr, cmpv, newv); 3072c482cb11SRichard Henderson #endif 3073c482cb11SRichard Henderson 3074c482cb11SRichard Henderson if (memop & MO_SIGN) { 3075c482cb11SRichard Henderson tcg_gen_ext_i32(retv, retv, memop); 3076c482cb11SRichard Henderson } 3077c482cb11SRichard Henderson } 3078c482cb11SRichard Henderson } 3079c482cb11SRichard Henderson 3080c482cb11SRichard Henderson void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv, 3081*14776ab5STony Nguyen TCGv_i64 newv, TCGArg idx, MemOp memop) 3082c482cb11SRichard Henderson { 3083c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 3084c482cb11SRichard Henderson 3085b1311c4aSEmilio G. Cota if (!(tcg_ctx->tb_cflags & CF_PARALLEL)) { 3086c482cb11SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 3087c482cb11SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 3088c482cb11SRichard Henderson 3089c482cb11SRichard Henderson tcg_gen_ext_i64(t2, cmpv, memop & MO_SIZE); 3090c482cb11SRichard Henderson 3091c482cb11SRichard Henderson tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN); 3092c482cb11SRichard Henderson tcg_gen_movcond_i64(TCG_COND_EQ, t2, t1, t2, newv, t1); 3093c482cb11SRichard Henderson tcg_gen_qemu_st_i64(t2, addr, idx, memop); 3094c482cb11SRichard Henderson tcg_temp_free_i64(t2); 3095c482cb11SRichard Henderson 3096c482cb11SRichard Henderson if (memop & MO_SIGN) { 3097c482cb11SRichard Henderson tcg_gen_ext_i64(retv, t1, memop); 3098c482cb11SRichard Henderson } else { 3099c482cb11SRichard Henderson tcg_gen_mov_i64(retv, t1); 3100c482cb11SRichard Henderson } 3101c482cb11SRichard Henderson tcg_temp_free_i64(t1); 3102c482cb11SRichard Henderson } else if ((memop & MO_SIZE) == MO_64) { 3103df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64 3104c482cb11SRichard Henderson gen_atomic_cx_i64 gen; 3105c482cb11SRichard Henderson 3106c482cb11SRichard Henderson gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; 3107c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3108c482cb11SRichard Henderson 3109c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU 3110c482cb11SRichard Henderson { 3111c482cb11SRichard Henderson TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop, idx)); 31121c2adb95SRichard Henderson gen(retv, cpu_env, addr, cmpv, newv, oi); 3113c482cb11SRichard Henderson tcg_temp_free_i32(oi); 3114c482cb11SRichard Henderson } 3115c482cb11SRichard Henderson #else 31161c2adb95SRichard Henderson gen(retv, cpu_env, addr, cmpv, newv); 3117c482cb11SRichard Henderson #endif 3118df79b996SRichard Henderson #else 31191c2adb95SRichard Henderson gen_helper_exit_atomic(cpu_env); 312079b1af90SRichard Henderson /* Produce a result, so that we have a well-formed opcode stream 312179b1af90SRichard Henderson with respect to uses of the result in the (dead) code following. */ 312279b1af90SRichard Henderson tcg_gen_movi_i64(retv, 0); 3123df79b996SRichard Henderson #endif /* CONFIG_ATOMIC64 */ 3124c482cb11SRichard Henderson } else { 3125c482cb11SRichard Henderson TCGv_i32 c32 = tcg_temp_new_i32(); 3126c482cb11SRichard Henderson TCGv_i32 n32 = tcg_temp_new_i32(); 3127c482cb11SRichard Henderson TCGv_i32 r32 = tcg_temp_new_i32(); 3128c482cb11SRichard Henderson 3129c482cb11SRichard Henderson tcg_gen_extrl_i64_i32(c32, cmpv); 3130c482cb11SRichard Henderson tcg_gen_extrl_i64_i32(n32, newv); 3131c482cb11SRichard Henderson tcg_gen_atomic_cmpxchg_i32(r32, addr, c32, n32, idx, memop & ~MO_SIGN); 3132c482cb11SRichard Henderson tcg_temp_free_i32(c32); 3133c482cb11SRichard Henderson tcg_temp_free_i32(n32); 3134c482cb11SRichard Henderson 3135c482cb11SRichard Henderson tcg_gen_extu_i32_i64(retv, r32); 3136c482cb11SRichard Henderson tcg_temp_free_i32(r32); 3137c482cb11SRichard Henderson 3138c482cb11SRichard Henderson if (memop & MO_SIGN) { 3139c482cb11SRichard Henderson tcg_gen_ext_i64(retv, retv, memop); 3140c482cb11SRichard Henderson } 3141c482cb11SRichard Henderson } 3142c482cb11SRichard Henderson } 3143c482cb11SRichard Henderson 3144c482cb11SRichard Henderson static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, 3145*14776ab5STony Nguyen TCGArg idx, MemOp memop, bool new_val, 3146c482cb11SRichard Henderson void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32)) 3147c482cb11SRichard Henderson { 3148c482cb11SRichard Henderson TCGv_i32 t1 = tcg_temp_new_i32(); 3149c482cb11SRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 3150c482cb11SRichard Henderson 3151c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 3152c482cb11SRichard Henderson 3153c482cb11SRichard Henderson tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN); 3154c482cb11SRichard Henderson gen(t2, t1, val); 3155c482cb11SRichard Henderson tcg_gen_qemu_st_i32(t2, addr, idx, memop); 3156c482cb11SRichard Henderson 3157c482cb11SRichard Henderson tcg_gen_ext_i32(ret, (new_val ? t2 : t1), memop); 3158c482cb11SRichard Henderson tcg_temp_free_i32(t1); 3159c482cb11SRichard Henderson tcg_temp_free_i32(t2); 3160c482cb11SRichard Henderson } 3161c482cb11SRichard Henderson 3162c482cb11SRichard Henderson static void do_atomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, 3163*14776ab5STony Nguyen TCGArg idx, MemOp memop, void * const table[]) 3164c482cb11SRichard Henderson { 3165c482cb11SRichard Henderson gen_atomic_op_i32 gen; 3166c482cb11SRichard Henderson 3167c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 0, 0); 3168c482cb11SRichard Henderson 3169c482cb11SRichard Henderson gen = table[memop & (MO_SIZE | MO_BSWAP)]; 3170c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3171c482cb11SRichard Henderson 3172c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU 3173c482cb11SRichard Henderson { 3174c482cb11SRichard Henderson TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop & ~MO_SIGN, idx)); 31751c2adb95SRichard Henderson gen(ret, cpu_env, addr, val, oi); 3176c482cb11SRichard Henderson tcg_temp_free_i32(oi); 3177c482cb11SRichard Henderson } 3178c482cb11SRichard Henderson #else 31791c2adb95SRichard Henderson gen(ret, cpu_env, addr, val); 3180c482cb11SRichard Henderson #endif 3181c482cb11SRichard Henderson 3182c482cb11SRichard Henderson if (memop & MO_SIGN) { 3183c482cb11SRichard Henderson tcg_gen_ext_i32(ret, ret, memop); 3184c482cb11SRichard Henderson } 3185c482cb11SRichard Henderson } 3186c482cb11SRichard Henderson 3187c482cb11SRichard Henderson static void do_nonatomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, 3188*14776ab5STony Nguyen TCGArg idx, MemOp memop, bool new_val, 3189c482cb11SRichard Henderson void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64)) 3190c482cb11SRichard Henderson { 3191c482cb11SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 3192c482cb11SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 3193c482cb11SRichard Henderson 3194c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 3195c482cb11SRichard Henderson 3196c482cb11SRichard Henderson tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN); 3197c482cb11SRichard Henderson gen(t2, t1, val); 3198c482cb11SRichard Henderson tcg_gen_qemu_st_i64(t2, addr, idx, memop); 3199c482cb11SRichard Henderson 3200c482cb11SRichard Henderson tcg_gen_ext_i64(ret, (new_val ? t2 : t1), memop); 3201c482cb11SRichard Henderson tcg_temp_free_i64(t1); 3202c482cb11SRichard Henderson tcg_temp_free_i64(t2); 3203c482cb11SRichard Henderson } 3204c482cb11SRichard Henderson 3205c482cb11SRichard Henderson static void do_atomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, 3206*14776ab5STony Nguyen TCGArg idx, MemOp memop, void * const table[]) 3207c482cb11SRichard Henderson { 3208c482cb11SRichard Henderson memop = tcg_canonicalize_memop(memop, 1, 0); 3209c482cb11SRichard Henderson 3210c482cb11SRichard Henderson if ((memop & MO_SIZE) == MO_64) { 3211df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64 3212c482cb11SRichard Henderson gen_atomic_op_i64 gen; 3213c482cb11SRichard Henderson 3214c482cb11SRichard Henderson gen = table[memop & (MO_SIZE | MO_BSWAP)]; 3215c482cb11SRichard Henderson tcg_debug_assert(gen != NULL); 3216c482cb11SRichard Henderson 3217c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU 3218c482cb11SRichard Henderson { 3219c482cb11SRichard Henderson TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop & ~MO_SIGN, idx)); 32201c2adb95SRichard Henderson gen(ret, cpu_env, addr, val, oi); 3221c482cb11SRichard Henderson tcg_temp_free_i32(oi); 3222c482cb11SRichard Henderson } 3223c482cb11SRichard Henderson #else 32241c2adb95SRichard Henderson gen(ret, cpu_env, addr, val); 3225c482cb11SRichard Henderson #endif 3226df79b996SRichard Henderson #else 32271c2adb95SRichard Henderson gen_helper_exit_atomic(cpu_env); 322879b1af90SRichard Henderson /* Produce a result, so that we have a well-formed opcode stream 322979b1af90SRichard Henderson with respect to uses of the result in the (dead) code following. */ 323079b1af90SRichard Henderson tcg_gen_movi_i64(ret, 0); 3231df79b996SRichard Henderson #endif /* CONFIG_ATOMIC64 */ 3232c482cb11SRichard Henderson } else { 3233c482cb11SRichard Henderson TCGv_i32 v32 = tcg_temp_new_i32(); 3234c482cb11SRichard Henderson TCGv_i32 r32 = tcg_temp_new_i32(); 3235c482cb11SRichard Henderson 3236c482cb11SRichard Henderson tcg_gen_extrl_i64_i32(v32, val); 3237c482cb11SRichard Henderson do_atomic_op_i32(r32, addr, v32, idx, memop & ~MO_SIGN, table); 3238c482cb11SRichard Henderson tcg_temp_free_i32(v32); 3239c482cb11SRichard Henderson 3240c482cb11SRichard Henderson tcg_gen_extu_i32_i64(ret, r32); 3241c482cb11SRichard Henderson tcg_temp_free_i32(r32); 3242c482cb11SRichard Henderson 3243c482cb11SRichard Henderson if (memop & MO_SIGN) { 3244c482cb11SRichard Henderson tcg_gen_ext_i64(ret, ret, memop); 3245c482cb11SRichard Henderson } 3246c482cb11SRichard Henderson } 3247c482cb11SRichard Henderson } 3248c482cb11SRichard Henderson 3249c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(NAME, OP, NEW) \ 3250c482cb11SRichard Henderson static void * const table_##NAME[16] = { \ 3251c482cb11SRichard Henderson [MO_8] = gen_helper_atomic_##NAME##b, \ 3252c482cb11SRichard Henderson [MO_16 | MO_LE] = gen_helper_atomic_##NAME##w_le, \ 3253c482cb11SRichard Henderson [MO_16 | MO_BE] = gen_helper_atomic_##NAME##w_be, \ 3254c482cb11SRichard Henderson [MO_32 | MO_LE] = gen_helper_atomic_##NAME##l_le, \ 3255c482cb11SRichard Henderson [MO_32 | MO_BE] = gen_helper_atomic_##NAME##l_be, \ 3256df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_##NAME##q_le) \ 3257df79b996SRichard Henderson WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_##NAME##q_be) \ 3258c482cb11SRichard Henderson }; \ 3259c482cb11SRichard Henderson void tcg_gen_atomic_##NAME##_i32 \ 3260*14776ab5STony Nguyen (TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, MemOp memop) \ 3261c482cb11SRichard Henderson { \ 3262b1311c4aSEmilio G. Cota if (tcg_ctx->tb_cflags & CF_PARALLEL) { \ 3263c482cb11SRichard Henderson do_atomic_op_i32(ret, addr, val, idx, memop, table_##NAME); \ 3264c482cb11SRichard Henderson } else { \ 3265c482cb11SRichard Henderson do_nonatomic_op_i32(ret, addr, val, idx, memop, NEW, \ 3266c482cb11SRichard Henderson tcg_gen_##OP##_i32); \ 3267c482cb11SRichard Henderson } \ 3268c482cb11SRichard Henderson } \ 3269c482cb11SRichard Henderson void tcg_gen_atomic_##NAME##_i64 \ 3270*14776ab5STony Nguyen (TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, MemOp memop) \ 3271c482cb11SRichard Henderson { \ 3272b1311c4aSEmilio G. Cota if (tcg_ctx->tb_cflags & CF_PARALLEL) { \ 3273c482cb11SRichard Henderson do_atomic_op_i64(ret, addr, val, idx, memop, table_##NAME); \ 3274c482cb11SRichard Henderson } else { \ 3275c482cb11SRichard Henderson do_nonatomic_op_i64(ret, addr, val, idx, memop, NEW, \ 3276c482cb11SRichard Henderson tcg_gen_##OP##_i64); \ 3277c482cb11SRichard Henderson } \ 3278c482cb11SRichard Henderson } 3279c482cb11SRichard Henderson 3280c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add, add, 0) 3281c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and, and, 0) 3282c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or, or, 0) 3283c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor, xor, 0) 32845507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_smin, smin, 0) 32855507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_umin, umin, 0) 32865507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_smax, smax, 0) 32875507c2bfSRichard Henderson GEN_ATOMIC_HELPER(fetch_umax, umax, 0) 3288c482cb11SRichard Henderson 3289c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch, add, 1) 3290c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch, and, 1) 3291c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch, or, 1) 3292c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch, xor, 1) 32935507c2bfSRichard Henderson GEN_ATOMIC_HELPER(smin_fetch, smin, 1) 32945507c2bfSRichard Henderson GEN_ATOMIC_HELPER(umin_fetch, umin, 1) 32955507c2bfSRichard Henderson GEN_ATOMIC_HELPER(smax_fetch, smax, 1) 32965507c2bfSRichard Henderson GEN_ATOMIC_HELPER(umax_fetch, umax, 1) 3297c482cb11SRichard Henderson 3298c482cb11SRichard Henderson static void tcg_gen_mov2_i32(TCGv_i32 r, TCGv_i32 a, TCGv_i32 b) 3299c482cb11SRichard Henderson { 3300c482cb11SRichard Henderson tcg_gen_mov_i32(r, b); 3301c482cb11SRichard Henderson } 3302c482cb11SRichard Henderson 3303c482cb11SRichard Henderson static void tcg_gen_mov2_i64(TCGv_i64 r, TCGv_i64 a, TCGv_i64 b) 3304c482cb11SRichard Henderson { 3305c482cb11SRichard Henderson tcg_gen_mov_i64(r, b); 3306c482cb11SRichard Henderson } 3307c482cb11SRichard Henderson 3308c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xchg, mov2, 0) 3309c482cb11SRichard Henderson 3310c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 3311