static int disas_neon_data_insn(DisasContext *s, uint32_t insn)

{

    int op;

    int q;

    int rd, rn, rm;

    int size;

    int shift;

    int pass;

    int count;

    int pairwise;

    int u;

    uint32_t imm, mask;

    TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5;

    TCGv_i64 tmp64;

    /* FIXME: this access check should not take precedence over UNDEF

     * for invalid encodings; we will generate incorrect syndrome information

     * for attempts to execute invalid vfp/neon encodings with FP disabled.

     */

    if (!s->cpacr_fpen) {

        gen_exception_insn(s, 4, EXCP_UDEF,

                           syn_fp_access_trap(1, 0xe, s->thumb),

                           default_exception_el(s));

        return 0;

    }

    if (!s->vfp_enabled)

      return 1;

    q = (insn & (1 << 6)) != 0;

    u = (insn >> 24) & 1;

    VFP_DREG_D(rd, insn);

    VFP_DREG_N(rn, insn);

    VFP_DREG_M(rm, insn);

    size = (insn >> 20) & 3;

    if ((insn & (1 << 23)) == 0) {

        /* Three register same length.  */

        op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1);

        /* Catch invalid op and bad size combinations: UNDEF */

        if ((neon_3r_sizes[op] & (1 << size)) == 0) {

            return 1;

        }

        /* All insns of this form UNDEF for either this condition or the

         * superset of cases "Q==1"; we catch the latter later.

         */

        if (q && ((rd | rn | rm) & 1)) {

            return 1;

        }

        /*

         * The SHA-1/SHA-256 3-register instructions require special treatment

         * here, as their size field is overloaded as an op type selector, and

         * they all consume their input in a single pass.

         */

        if (op == NEON_3R_SHA) {

            if (!q) {

                return 1;

            }

            if (!u) { /* SHA-1 */

                if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)) {

                    return 1;

                }

                tmp = tcg_const_i32(rd);

                tmp2 = tcg_const_i32(rn);

                tmp3 = tcg_const_i32(rm);

                tmp4 = tcg_const_i32(size);

                gen_helper_crypto_sha1_3reg(cpu_env, tmp, tmp2, tmp3, tmp4);

                tcg_temp_free_i32(tmp4);

            } else { /* SHA-256 */

                if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA256) || size == 3) {

                    return 1;

                }

                tmp = tcg_const_i32(rd);

                tmp2 = tcg_const_i32(rn);

                tmp3 = tcg_const_i32(rm);

                switch (size) {

                case 0:

                    gen_helper_crypto_sha256h(cpu_env, tmp, tmp2, tmp3);

                    break;

                case 1:

                    gen_helper_crypto_sha256h2(cpu_env, tmp, tmp2, tmp3);

                    break;

                case 2:

                    gen_helper_crypto_sha256su1(cpu_env, tmp, tmp2, tmp3);

                    break;

                }

            }

            tcg_temp_free_i32(tmp);

            tcg_temp_free_i32(tmp2);

            tcg_temp_free_i32(tmp3);

            return 0;

        }

        if (size == 3 && op != NEON_3R_LOGIC) {

            /* 64-bit element instructions. */

            for (pass = 0; pass < (q ? 2 : 1); pass++) {

                neon_load_reg64(cpu_V0, rn + pass);

                neon_load_reg64(cpu_V1, rm + pass);

                switch (op) {

                case NEON_3R_VQADD:

                    if (u) {

                        gen_helper_neon_qadd_u64(cpu_V0, cpu_env,

                                                 cpu_V0, cpu_V1);

                    } else {

                        gen_helper_neon_qadd_s64(cpu_V0, cpu_env,

                                                 cpu_V0, cpu_V1);

                    }

                    break;

                case NEON_3R_VQSUB:

                    if (u) {

                        gen_helper_neon_qsub_u64(cpu_V0, cpu_env,

                                                 cpu_V0, cpu_V1);

                    } else {

                        gen_helper_neon_qsub_s64(cpu_V0, cpu_env,

                                                 cpu_V0, cpu_V1);

                    }

                    break;

                case NEON_3R_VSHL:

                    if (u) {

                        gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0);

                    } else {

                        gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0);

                    }

                    break;

                case NEON_3R_VQSHL:

                    if (u) {

                        gen_helper_neon_qshl_u64(cpu_V0, cpu_env,

                                                 cpu_V1, cpu_V0);

                    } else {

                        gen_helper_neon_qshl_s64(cpu_V0, cpu_env,

                                                 cpu_V1, cpu_V0);

                    }

                    break;

                case NEON_3R_VRSHL:

                    if (u) {

                        gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);

                    } else {

                        gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);

                    }

                    break;

                case NEON_3R_VQRSHL:

                    if (u) {

                        gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,

                                                  cpu_V1, cpu_V0);

                    } else {

                        gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,

                                                  cpu_V1, cpu_V0);

                    }

                    break;

                case NEON_3R_VADD_VSUB:

                    if (u) {

                        tcg_gen_sub_i64(CPU_V001);

                    } else {

                        tcg_gen_add_i64(CPU_V001);

                    }

                    break;

                default:

                    abort();

                }

                neon_store_reg64(cpu_V0, rd + pass);

            }

            return 0;

        }

        pairwise = 0;

        switch (op) {

        case NEON_3R_VSHL:

        case NEON_3R_VQSHL:

        case NEON_3R_VRSHL:

        case NEON_3R_VQRSHL:

            {

                int rtmp;

                /* Shift instruction operands are reversed.  */

                rtmp = rn;

                rn = rm;

                rm = rtmp;

            }

            break;

        case NEON_3R_VPADD:

            if (u) {

                return 1;

            }

            /* Fall through */

        case NEON_3R_VPMAX:

        case NEON_3R_VPMIN:

            pairwise = 1;

            break;

        case NEON_3R_FLOAT_ARITH:

            pairwise = (u && size < 2); /* if VPADD (float) */

            break;

        case NEON_3R_FLOAT_MINMAX:

            pairwise = u; /* if VPMIN/VPMAX (float) */

            break;

        case NEON_3R_FLOAT_CMP:

            if (!u && size) {

                /* no encoding for U=0 C=1x */

                return 1;

            }

            break;

        case NEON_3R_FLOAT_ACMP:

            if (!u) {

                return 1;

            }

            break;

        case NEON_3R_FLOAT_MISC:

            /* VMAXNM/VMINNM in ARMv8 */

            if (u && !arm_dc_feature(s, ARM_FEATURE_V8)) {

                return 1;

            }

            break;

        case NEON_3R_VMUL:

            if (u && (size != 0)) {

                /* UNDEF on invalid size for polynomial subcase */

                return 1;

            }

            break;

        case NEON_3R_VFM:

            if (!arm_dc_feature(s, ARM_FEATURE_VFP4) || u) {

                return 1;

            }

            break;

        default:

            break;

        }

        if (pairwise && q) {

            /* All the pairwise insns UNDEF if Q is set */

            return 1;

        }

        for (pass = 0; pass < (q ? 4 : 2); pass++) {

        if (pairwise) {

            /* Pairwise.  */

            if (pass < 1) {

                tmp = neon_load_reg(rn, 0);

                tmp2 = neon_load_reg(rn, 1);

            } else {

                tmp = neon_load_reg(rm, 0);

                tmp2 = neon_load_reg(rm, 1);

            }

        } else {

            /* Elementwise.  */

            tmp = neon_load_reg(rn, pass);

            tmp2 = neon_load_reg(rm, pass);

        }

        switch (op) {

        case NEON_3R_VHADD:

            GEN_NEON_INTEGER_OP(hadd);

            break;

        case NEON_3R_VQADD:

            GEN_NEON_INTEGER_OP_ENV(qadd);

            break;

        case NEON_3R_VRHADD:

            GEN_NEON_INTEGER_OP(rhadd);

            break;

        case NEON_3R_LOGIC: /* Logic ops.  */

            switch ((u << 2) | size) {

            case 0: /* VAND */

                tcg_gen_and_i32(tmp, tmp, tmp2);

                break;

            case 1: /* BIC */

                tcg_gen_andc_i32(tmp, tmp, tmp2);

                break;

            case 2: /* VORR */

                tcg_gen_or_i32(tmp, tmp, tmp2);

                break;

            case 3: /* VORN */

                tcg_gen_orc_i32(tmp, tmp, tmp2);

                break;

            case 4: /* VEOR */

                tcg_gen_xor_i32(tmp, tmp, tmp2);

                break;

            case 5: /* VBSL */

                tmp3 = neon_load_reg(rd, pass);

                gen_neon_bsl(tmp, tmp, tmp2, tmp3);

                tcg_temp_free_i32(tmp3);

                break;

            case 6: /* VBIT */

                tmp3 = neon_load_reg(rd, pass);

                gen_neon_bsl(tmp, tmp, tmp3, tmp2);

                tcg_temp_free_i32(tmp3);

                break;

            case 7: /* VBIF */

                tmp3 = neon_load_reg(rd, pass);

                gen_neon_bsl(tmp, tmp3, tmp, tmp2);

                tcg_temp_free_i32(tmp3);

                break;

            }

            break;

        case NEON_3R_VHSUB:

            GEN_NEON_INTEGER_OP(hsub);

            break;

        case NEON_3R_VQSUB:

            GEN_NEON_INTEGER_OP_ENV(qsub);

            break;

        case NEON_3R_VCGT:

            GEN_NEON_INTEGER_OP(cgt);

            break;

        case NEON_3R_VCGE:

            GEN_NEON_INTEGER_OP(cge);

            break;

        case NEON_3R_VSHL:

            GEN_NEON_INTEGER_OP(shl);

            break;

        case NEON_3R_VQSHL:

            GEN_NEON_INTEGER_OP_ENV(qshl);

            break;

        case NEON_3R_VRSHL:

            GEN_NEON_INTEGER_OP(rshl);

            break;

        case NEON_3R_VQRSHL:

            GEN_NEON_INTEGER_OP_ENV(qrshl);

            break;

        case NEON_3R_VMAX:

            GEN_NEON_INTEGER_OP(max);

            break;

        case NEON_3R_VMIN:

            GEN_NEON_INTEGER_OP(min);

            break;

        case NEON_3R_VABD:

            GEN_NEON_INTEGER_OP(abd);

            break;

        case NEON_3R_VABA:

            GEN_NEON_INTEGER_OP(abd);

            tcg_temp_free_i32(tmp2);

            tmp2 = neon_load_reg(rd, pass);

            gen_neon_add(size, tmp, tmp2);

            break;

        case NEON_3R_VADD_VSUB:

            if (!u) { /* VADD */

                gen_neon_add(size, tmp, tmp2);

            } else { /* VSUB */

                switch (size) {

                case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break;

                case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break;

                case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break;

                default: abort();

                }

            }

            break;

        case NEON_3R_VTST_VCEQ:

            if (!u) { /* VTST */

                switch (size) {

                case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break;

                case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break;

                case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break;

                default: abort();

                }

            } else { /* VCEQ */

                switch (size) {

                case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;

                case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;

                case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;

                default: abort();

                }

            }

            break;

        case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */

            switch (size) {

            case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;

            case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;

            case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;

            default: abort();

            }

            tcg_temp_free_i32(tmp2);

            tmp2 = neon_load_reg(rd, pass);

            if (u) { /* VMLS */

                gen_neon_rsb(size, tmp, tmp2);

            } else { /* VMLA */

                gen_neon_add(size, tmp, tmp2);

            }

            break;

        case NEON_3R_VMUL:

            if (u) { /* polynomial */

                gen_helper_neon_mul_p8(tmp, tmp, tmp2);

            } else { /* Integer */

                switch (size) {

                case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;

                case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;

                case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;

                default: abort();

                }

            }

            break;

        case NEON_3R_VPMAX:

            GEN_NEON_INTEGER_OP(pmax);

            break;

        case NEON_3R_VPMIN:

            GEN_NEON_INTEGER_OP(pmin);

            break;

        case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high.  */

            if (!u) { /* VQDMULH */

                switch (size) {

                case 1:

                    gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);

                    break;

                case 2:

                    gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);

                    break;

                default: abort();

                }

            } else { /* VQRDMULH */

                switch (size) {

                case 1:

                    gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);

                    break;

                case 2:

                    gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);

                    break;

                default: abort();

                }

            }

            break;

        case NEON_3R_VPADD:

            switch (size) {

            case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break;

            case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break;

            case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break;

            default: abort();

            }

            break;

        case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */

        {

            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

            switch ((u << 2) | size) {

            case 0: /* VADD */

            case 4: /* VPADD */

                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);

                break;

            case 2: /* VSUB */

                gen_helper_vfp_subs(tmp, tmp, tmp2, fpstatus);

                break;

            case 6: /* VABD */

                gen_helper_neon_abd_f32(tmp, tmp, tmp2, fpstatus);

                break;

            default:

                abort();

            }

            tcg_temp_free_ptr(fpstatus);

            break;

        }

        case NEON_3R_FLOAT_MULTIPLY:

        {

            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);

            if (!u) {

                tcg_temp_free_i32(tmp2);

                tmp2 = neon_load_reg(rd, pass);

                if (size == 0) {

                    gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);

                } else {

                    gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);

                }

            }

            tcg_temp_free_ptr(fpstatus);

            break;

        }

        case NEON_3R_FLOAT_CMP:

        {

            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

            if (!u) {

                gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);

            } else {

                if (size == 0) {

                    gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);

                } else {

                    gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);

                }

            }

            tcg_temp_free_ptr(fpstatus);

            break;

        }

        case NEON_3R_FLOAT_ACMP:

        {

            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

            if (size == 0) {

                gen_helper_neon_acge_f32(tmp, tmp, tmp2, fpstatus);

            } else {

                gen_helper_neon_acgt_f32(tmp, tmp, tmp2, fpstatus);

            }

            tcg_temp_free_ptr(fpstatus);

            break;

        }

        case NEON_3R_FLOAT_MINMAX:

        {

            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

            if (size == 0) {

                gen_helper_vfp_maxs(tmp, tmp, tmp2, fpstatus);

            } else {

                gen_helper_vfp_mins(tmp, tmp, tmp2, fpstatus);

            }

            tcg_temp_free_ptr(fpstatus);

            break;

        }

        case NEON_3R_FLOAT_MISC:

            if (u) {

                /* VMAXNM/VMINNM */

                TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                if (size == 0) {

                    gen_helper_vfp_maxnums(tmp, tmp, tmp2, fpstatus);

                } else {

                    gen_helper_vfp_minnums(tmp, tmp, tmp2, fpstatus);

                }

                tcg_temp_free_ptr(fpstatus);

            } else {

                if (size == 0) {

                    gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);

                } else {

                    gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);

              }

            }

            break;

        case NEON_3R_VFM:

        {

            /* VFMA, VFMS: fused multiply-add */

            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

            TCGv_i32 tmp3 = neon_load_reg(rd, pass);

            if (size) {

                /* VFMS */

                gen_helper_vfp_negs(tmp, tmp);

            }

            gen_helper_vfp_muladds(tmp, tmp, tmp2, tmp3, fpstatus);

            tcg_temp_free_i32(tmp3);

            tcg_temp_free_ptr(fpstatus);

            break;

        }

        default:

            abort();

        }

        tcg_temp_free_i32(tmp2);

        /* Save the result.  For elementwise operations we can put it

           straight into the destination register.  For pairwise operations

           we have to be careful to avoid clobbering the source operands.  */

        if (pairwise && rd == rm) {

            neon_store_scratch(pass, tmp);

        } else {

            neon_store_reg(rd, pass, tmp);

        }

        } /* for pass */

        if (pairwise && rd == rm) {

            for (pass = 0; pass < (q ? 4 : 2); pass++) {

                tmp = neon_load_scratch(pass);

                neon_store_reg(rd, pass, tmp);

            }

        }

        /* End of 3 register same size operations.  */

    } else if (insn & (1 << 4)) {

        if ((insn & 0x00380080) != 0) {

            /* Two registers and shift.  */

            op = (insn >> 8) & 0xf;

            if (insn & (1 << 7)) {

                /* 64-bit shift. */

                if (op > 7) {

                    return 1;

                }

                size = 3;

            } else {

                size = 2;

                while ((insn & (1 << (size + 19))) == 0)

                    size--;

            }

            shift = (insn >> 16) & ((1 << (3 + size)) - 1);

            /* To avoid excessive duplication of ops we implement shift

               by immediate using the variable shift operations.  */

            if (op < 8) {

                /* Shift by immediate:

                   VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU.  */

                if (q && ((rd | rm) & 1)) {

                    return 1;

                }

                if (!u && (op == 4 || op == 6)) {

                    return 1;

                }

                /* Right shifts are encoded as N - shift, where N is the

                   element size in bits.  */

                if (op <= 4)

                    shift = shift - (1 << (size + 3));

                if (size == 3) {

                    count = q + 1;

                } else {

                    count = q ? 4: 2;

                }

                switch (size) {

                case 0:

                    imm = (uint8_t) shift;

                    imm |= imm << 8;

                    imm |= imm << 16;

                    break;

                case 1:

                    imm = (uint16_t) shift;

                    imm |= imm << 16;

                    break;

                case 2:

                case 3:

                    imm = shift;

                    break;

                default:

                    abort();

                }

                for (pass = 0; pass < count; pass++) {

                    if (size == 3) {

                        neon_load_reg64(cpu_V0, rm + pass);

                        tcg_gen_movi_i64(cpu_V1, imm);

                        switch (op) {

                        case 0:  /* VSHR */

                        case 1:  /* VSRA */

                            if (u)

                                gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);

                            else

                                gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);

                            break;

                        case 2: /* VRSHR */

                        case 3: /* VRSRA */

                            if (u)

                                gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);

                            else

                                gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);

                            break;

                        case 4: /* VSRI */

                        case 5: /* VSHL, VSLI */

                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);

                            break;

                        case 6: /* VQSHLU */

                            gen_helper_neon_qshlu_s64(cpu_V0, cpu_env,

                                                      cpu_V0, cpu_V1);

                            break;

                        case 7: /* VQSHL */

                            if (u) {

                                gen_helper_neon_qshl_u64(cpu_V0, cpu_env,

                                                         cpu_V0, cpu_V1);

                            } else {

                                gen_helper_neon_qshl_s64(cpu_V0, cpu_env,

                                                         cpu_V0, cpu_V1);

                            }

                            break;

                        }

                        if (op == 1 || op == 3) {

                            /* Accumulate.  */

                            neon_load_reg64(cpu_V1, rd + pass);

                            tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);

                        } else if (op == 4 || (op == 5 && u)) {

                            /* Insert */

                            neon_load_reg64(cpu_V1, rd + pass);

                            uint64_t mask;

                            if (shift < -63 || shift > 63) {

                                mask = 0;

                            } else {

                                if (op == 4) {

                                    mask = 0xffffffffffffffffull >> -shift;

                                } else {

                                    mask = 0xffffffffffffffffull << shift;

                                }

                            }

                            tcg_gen_andi_i64(cpu_V1, cpu_V1, ~mask);

                            tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);

                        }

                        neon_store_reg64(cpu_V0, rd + pass);

                    } else { /* size < 3 */

                        /* Operands in T0 and T1.  */

                        tmp = neon_load_reg(rm, pass);

                        tmp2 = tcg_temp_new_i32();

                        tcg_gen_movi_i32(tmp2, imm);

                        switch (op) {

                        case 0:  /* VSHR */

                        case 1:  /* VSRA */

                            GEN_NEON_INTEGER_OP(shl);

                            break;

                        case 2: /* VRSHR */

                        case 3: /* VRSRA */

                            GEN_NEON_INTEGER_OP(rshl);

                            break;

                        case 4: /* VSRI */

                        case 5: /* VSHL, VSLI */

                            switch (size) {

                            case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break;

                            case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break;

                            case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break;

                            default: abort();

                            }

                            break;

                        case 6: /* VQSHLU */

                            switch (size) {

                            case 0:

                                gen_helper_neon_qshlu_s8(tmp, cpu_env,

                                                         tmp, tmp2);

                                break;

                            case 1:

                                gen_helper_neon_qshlu_s16(tmp, cpu_env,

                                                          tmp, tmp2);

                                break;

                            case 2:

                                gen_helper_neon_qshlu_s32(tmp, cpu_env,

                                                          tmp, tmp2);

                                break;

                            default:

                                abort();

                            }

                            break;

                        case 7: /* VQSHL */

                            GEN_NEON_INTEGER_OP_ENV(qshl);

                            break;

                        }

                        tcg_temp_free_i32(tmp2);

                        if (op == 1 || op == 3) {

                            /* Accumulate.  */

                            tmp2 = neon_load_reg(rd, pass);

                            gen_neon_add(size, tmp, tmp2);

                            tcg_temp_free_i32(tmp2);

                        } else if (op == 4 || (op == 5 && u)) {

                            /* Insert */

                            switch (size) {

                            case 0:

                                if (op == 4)

                                    mask = 0xff >> -shift;

                                else

                                    mask = (uint8_t)(0xff << shift);

                                mask |= mask << 8;

                                mask |= mask << 16;

                                break;

                            case 1:

                                if (op == 4)

                                    mask = 0xffff >> -shift;

                                else

                                    mask = (uint16_t)(0xffff << shift);

                                mask |= mask << 16;

                                break;

                            case 2:

                                if (shift < -31 || shift > 31) {

                                    mask = 0;

                                } else {

                                    if (op == 4)

                                        mask = 0xffffffffu >> -shift;

                                    else

                                        mask = 0xffffffffu << shift;

                                }

                                break;

                            default:

                                abort();

                            }

                            tmp2 = neon_load_reg(rd, pass);

                            tcg_gen_andi_i32(tmp, tmp, mask);

                            tcg_gen_andi_i32(tmp2, tmp2, ~mask);

                            tcg_gen_or_i32(tmp, tmp, tmp2);

                            tcg_temp_free_i32(tmp2);

                        }

                        neon_store_reg(rd, pass, tmp);

                    }

                } /* for pass */

            } else if (op < 10) {

                /* Shift by immediate and narrow:

                   VSHRN, VRSHRN, VQSHRN, VQRSHRN.  */

                int input_unsigned = (op == 8) ? !u : u;

                if (rm & 1) {

                    return 1;

                }

                shift = shift - (1 << (size + 3));

                size++;

                if (size == 3) {

                    tmp64 = tcg_const_i64(shift);

                    neon_load_reg64(cpu_V0, rm);

                    neon_load_reg64(cpu_V1, rm + 1);

                    for (pass = 0; pass < 2; pass++) {

                        TCGv_i64 in;

                        if (pass == 0) {

                            in = cpu_V0;

                        } else {

                            in = cpu_V1;

                        }

                        if (q) {

                            if (input_unsigned) {

                                gen_helper_neon_rshl_u64(cpu_V0, in, tmp64);

                            } else {

                                gen_helper_neon_rshl_s64(cpu_V0, in, tmp64);

                            }

                        } else {

                            if (input_unsigned) {

                                gen_helper_neon_shl_u64(cpu_V0, in, tmp64);

                            } else {

                                gen_helper_neon_shl_s64(cpu_V0, in, tmp64);

                            }

                        }

                        tmp = tcg_temp_new_i32();

                        gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);

                        neon_store_reg(rd, pass, tmp);

                    } /* for pass */

                    tcg_temp_free_i64(tmp64);

                } else {

                    if (size == 1) {

                        imm = (uint16_t)shift;

                        imm |= imm << 16;

                    } else {

                        /* size == 2 */

                        imm = (uint32_t)shift;

                    }

                    tmp2 = tcg_const_i32(imm);

                    tmp4 = neon_load_reg(rm + 1, 0);

                    tmp5 = neon_load_reg(rm + 1, 1);

                    for (pass = 0; pass < 2; pass++) {

                        if (pass == 0) {

                            tmp = neon_load_reg(rm, 0);

                        } else {

                            tmp = tmp4;

                        }

                        gen_neon_shift_narrow(size, tmp, tmp2, q,

                                              input_unsigned);

                        if (pass == 0) {

                            tmp3 = neon_load_reg(rm, 1);

                        } else {

                            tmp3 = tmp5;

                        }

                        gen_neon_shift_narrow(size, tmp3, tmp2, q,

                                              input_unsigned);

                        tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);

                        tcg_temp_free_i32(tmp);

                        tcg_temp_free_i32(tmp3);

                        tmp = tcg_temp_new_i32();

                        gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);

                        neon_store_reg(rd, pass, tmp);

                    } /* for pass */

                    tcg_temp_free_i32(tmp2);

                }

            } else if (op == 10) {

                /* VSHLL, VMOVL */

                if (q || (rd & 1)) {

                    return 1;

                }

                tmp = neon_load_reg(rm, 0);

                tmp2 = neon_load_reg(rm, 1);

                for (pass = 0; pass < 2; pass++) {

                    if (pass == 1)

                        tmp = tmp2;

                    gen_neon_widen(cpu_V0, tmp, size, u);

                    if (shift != 0) {

                        /* The shift is less than the width of the source

                           type, so we can just shift the whole register.  */

                        tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);

                        /* Widen the result of shift: we need to clear

                         * the potential overflow bits resulting from

                         * left bits of the narrow input appearing as

                         * right bits of left the neighbour narrow

                         * input.  */

                        if (size < 2 || !u) {

                            uint64_t imm64;

                            if (size == 0) {

                                imm = (0xffu >> (8 - shift));

                                imm |= imm << 16;

                            } else if (size == 1) {

                                imm = 0xffff >> (16 - shift);

                            } else {

                                /* size == 2 */

                                imm = 0xffffffff >> (32 - shift);

                            }

                            if (size < 2) {

                                imm64 = imm | (((uint64_t)imm) << 32);

                            } else {

                                imm64 = imm;

                            }

                            tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);

                        }

                    }

                    neon_store_reg64(cpu_V0, rd + pass);

                }

            } else if (op >= 14) {

                /* VCVT fixed-point.  */

                if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {

                    return 1;

                }

                /* We have already masked out the must-be-1 top bit of imm6,

                 * hence this 32-shift where the ARM ARM has 64-imm6.

                 */

                shift = 32 - shift;

                for (pass = 0; pass < (q ? 4 : 2); pass++) {

                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));

                    if (!(op & 1)) {

                        if (u)

                            gen_vfp_ulto(0, shift, 1);

                        else

                            gen_vfp_slto(0, shift, 1);

                    } else {

                        if (u)

                            gen_vfp_toul(0, shift, 1);

                        else

                            gen_vfp_tosl(0, shift, 1);

                    }

                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));

                }

            } else {

                return 1;

            }

        } else { /* (insn & 0x00380080) == 0 */

            int invert;

            if (q && (rd & 1)) {

                return 1;

            }

            op = (insn >> 8) & 0xf;

            /* One register and immediate.  */

            imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);

            invert = (insn & (1 << 5)) != 0;

            /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.

             * We choose to not special-case this and will behave as if a

             * valid constant encoding of 0 had been given.

             */

            switch (op) {

            case 0: case 1:

                /* no-op */

                break;

            case 2: case 3:

                imm <<= 8;

                break;

            case 4: case 5:

                imm <<= 16;

                break;

            case 6: case 7:

                imm <<= 24;

                break;

            case 8: case 9:

                imm |= imm << 16;

                break;

            case 10: case 11:

                imm = (imm << 8) | (imm << 24);

                break;

            case 12:

                imm = (imm << 8) | 0xff;

                break;

            case 13:

                imm = (imm << 16) | 0xffff;

                break;

            case 14:

                imm |= (imm << 8) | (imm << 16) | (imm << 24);

                if (invert)

                    imm = ~imm;

                break;

            case 15:

                if (invert) {

                    return 1;

                }

                imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)

                      | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));

                break;

            }

            if (invert)

                imm = ~imm;

            for (pass = 0; pass < (q ? 4 : 2); pass++) {

                if (op & 1 && op < 12) {

                    tmp = neon_load_reg(rd, pass);

                    if (invert) {

                        /* The immediate value has already been inverted, so

                           BIC becomes AND.  */

                        tcg_gen_andi_i32(tmp, tmp, imm);

                    } else {

                        tcg_gen_ori_i32(tmp, tmp, imm);

                    }

                } else {

                    /* VMOV, VMVN.  */

                    tmp = tcg_temp_new_i32();

                    if (op == 14 && invert) {

                        int n;

                        uint32_t val;

                        val = 0;

                        for (n = 0; n < 4; n++) {

                            if (imm & (1 << (n + (pass & 1) * 4)))

                                val |= 0xff << (n * 8);

                        }

                        tcg_gen_movi_i32(tmp, val);

                    } else {

                        tcg_gen_movi_i32(tmp, imm);

                    }

                }

                neon_store_reg(rd, pass, tmp);

            }

        }

    } else { /* (insn & 0x00800010 == 0x00800000) */

        if (size != 3) {

            op = (insn >> 8) & 0xf;

            if ((insn & (1 << 6)) == 0) {

                /* Three registers of different lengths.  */

                int src1_wide;

                int src2_wide;

                int prewiden;

                /* undefreq: bit 0 : UNDEF if size == 0

                 *           bit 1 : UNDEF if size == 1

                 *           bit 2 : UNDEF if size == 2

                 *           bit 3 : UNDEF if U == 1

                 * Note that [2:0] set implies 'always UNDEF'

                 */

                int undefreq;

                /* prewiden, src1_wide, src2_wide, undefreq */

                static const int neon_3reg_wide[16][4] = {

                    {1, 0, 0, 0}, /* VADDL */

                    {1, 1, 0, 0}, /* VADDW */

                    {1, 0, 0, 0}, /* VSUBL */

                    {1, 1, 0, 0}, /* VSUBW */

                    {0, 1, 1, 0}, /* VADDHN */

                    {0, 0, 0, 0}, /* VABAL */

                    {0, 1, 1, 0}, /* VSUBHN */

                    {0, 0, 0, 0}, /* VABDL */

                    {0, 0, 0, 0}, /* VMLAL */

                    {0, 0, 0, 9}, /* VQDMLAL */

                    {0, 0, 0, 0}, /* VMLSL */

                    {0, 0, 0, 9}, /* VQDMLSL */

                    {0, 0, 0, 0}, /* Integer VMULL */

                    {0, 0, 0, 1}, /* VQDMULL */

                    {0, 0, 0, 0xa}, /* Polynomial VMULL */

                    {0, 0, 0, 7}, /* Reserved: always UNDEF */

                };

                prewiden = neon_3reg_wide[op][0];

                src1_wide = neon_3reg_wide[op][1];

                src2_wide = neon_3reg_wide[op][2];

                undefreq = neon_3reg_wide[op][3];

                if ((undefreq & (1 << size)) ||

                    ((undefreq & 8) && u)) {

                    return 1;

                }

                if ((src1_wide && (rn & 1)) ||

                    (src2_wide && (rm & 1)) ||

                    (!src2_wide && (rd & 1))) {

                    return 1;

                }

                /* Handle VMULL.P64 (Polynomial 64x64 to 128 bit multiply)

                 * outside the loop below as it only performs a single pass.

                 */

                if (op == 14 && size == 2) {

                    TCGv_i64 tcg_rn, tcg_rm, tcg_rd;

                    if (!arm_dc_feature(s, ARM_FEATURE_V8_PMULL)) {

                        return 1;

                    }

                    tcg_rn = tcg_temp_new_i64();

                    tcg_rm = tcg_temp_new_i64();

                    tcg_rd = tcg_temp_new_i64();

                    neon_load_reg64(tcg_rn, rn);

                    neon_load_reg64(tcg_rm, rm);

                    gen_helper_neon_pmull_64_lo(tcg_rd, tcg_rn, tcg_rm);

                    neon_store_reg64(tcg_rd, rd);

                    gen_helper_neon_pmull_64_hi(tcg_rd, tcg_rn, tcg_rm);

                    neon_store_reg64(tcg_rd, rd + 1);

                    tcg_temp_free_i64(tcg_rn);

                    tcg_temp_free_i64(tcg_rm);

                    tcg_temp_free_i64(tcg_rd);

                    return 0;

                }

                /* Avoid overlapping operands.  Wide source operands are

                   always aligned so will never overlap with wide

                   destinations in problematic ways.  */

                if (rd == rm && !src2_wide) {

                    tmp = neon_load_reg(rm, 1);

                    neon_store_scratch(2, tmp);

                } else if (rd == rn && !src1_wide) {

                    tmp = neon_load_reg(rn, 1);

                    neon_store_scratch(2, tmp);

                }

                TCGV_UNUSED_I32(tmp3);

                for (pass = 0; pass < 2; pass++) {

                    if (src1_wide) {

                        neon_load_reg64(cpu_V0, rn + pass);

                        TCGV_UNUSED_I32(tmp);

                    } else {

                        if (pass == 1 && rd == rn) {

                            tmp = neon_load_scratch(2);

                        } else {

                            tmp = neon_load_reg(rn, pass);

                        }

                        if (prewiden) {

                            gen_neon_widen(cpu_V0, tmp, size, u);

                        }

                    }

                    if (src2_wide) {

                        neon_load_reg64(cpu_V1, rm + pass);

                        TCGV_UNUSED_I32(tmp2);

                    } else {

                        if (pass == 1 && rd == rm) {

                            tmp2 = neon_load_scratch(2);

                        } else {

                            tmp2 = neon_load_reg(rm, pass);

                        }

                        if (prewiden) {

                            gen_neon_widen(cpu_V1, tmp2, size, u);

                        }

                    }

                    switch (op) {

                    case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */

                        gen_neon_addl(size);

                        break;

                    case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHN, VRSUBHN */

                        gen_neon_subl(size);

                        break;

                    case 5: case 7: /* VABAL, VABDL */

                        switch ((size << 1) | u) {

                        case 0:

                            gen_helper_neon_abdl_s16(cpu_V0, tmp, tmp2);

                            break;

                        case 1:

                            gen_helper_neon_abdl_u16(cpu_V0, tmp, tmp2);

                            break;

                        case 2:

                            gen_helper_neon_abdl_s32(cpu_V0, tmp, tmp2);

                            break;

                        case 3:

                            gen_helper_neon_abdl_u32(cpu_V0, tmp, tmp2);

                            break;

                        case 4:

                            gen_helper_neon_abdl_s64(cpu_V0, tmp, tmp2);

                            break;

                        case 5:

                            gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2);

                            break;

                        default: abort();

                        }

                        tcg_temp_free_i32(tmp2);

                        tcg_temp_free_i32(tmp);

                        break;

                    case 8: case 9: case 10: case 11: case 12: case 13:

                        /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */

                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);

                        break;

                    case 14: /* Polynomial VMULL */

                        gen_helper_neon_mull_p8(cpu_V0, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                        tcg_temp_free_i32(tmp);

                        break;

                    default: /* 15 is RESERVED: caught earlier  */

                        abort();

                    }

                    if (op == 13) {

                        /* VQDMULL */

                        gen_neon_addl_saturate(cpu_V0, cpu_V0, size);

                        neon_store_reg64(cpu_V0, rd + pass);

                    } else if (op == 5 || (op >= 8 && op <= 11)) {

                        /* Accumulate.  */

                        neon_load_reg64(cpu_V1, rd + pass);

                        switch (op) {

                        case 10: /* VMLSL */

                            gen_neon_negl(cpu_V0, size);

                            /* Fall through */

                        case 5: case 8: /* VABAL, VMLAL */

                            gen_neon_addl(size);

                            break;

                        case 9: case 11: /* VQDMLAL, VQDMLSL */

                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);

                            if (op == 11) {

                                gen_neon_negl(cpu_V0, size);

                            }

                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);

                            break;

                        default:

                            abort();

                        }

                        neon_store_reg64(cpu_V0, rd + pass);

                    } else if (op == 4 || op == 6) {

                        /* Narrowing operation.  */

                        tmp = tcg_temp_new_i32();

                        if (!u) {

                            switch (size) {

                            case 0:

                                gen_helper_neon_narrow_high_u8(tmp, cpu_V0);

                                break;

                            case 1:

                                gen_helper_neon_narrow_high_u16(tmp, cpu_V0);

                                break;

                            case 2:

                                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);

                                tcg_gen_trunc_i64_i32(tmp, cpu_V0);

                                break;

                            default: abort();

                            }

                        } else {

                            switch (size) {

                            case 0:

                                gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0);

                                break;

                            case 1:

                                gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0);

                                break;

                            case 2:

                                tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31);

                                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);

                                tcg_gen_trunc_i64_i32(tmp, cpu_V0);

                                break;

                            default: abort();

                            }

                        }

                        if (pass == 0) {

                            tmp3 = tmp;

                        } else {

                            neon_store_reg(rd, 0, tmp3);

                            neon_store_reg(rd, 1, tmp);

                        }

                    } else {

                        /* Write back the result.  */

                        neon_store_reg64(cpu_V0, rd + pass);

                    }

                }

            } else {

                /* Two registers and a scalar. NB that for ops of this form

                 * the ARM ARM labels bit 24 as Q, but it is in our variable

                 * 'u', not 'q'.

                 */

                if (size == 0) {

                    return 1;

                }

                switch (op) {

                case 1: /* Float VMLA scalar */

                case 5: /* Floating point VMLS scalar */

                case 9: /* Floating point VMUL scalar */

                    if (size == 1) {

                        return 1;

                    }

                    /* fall through */

                case 0: /* Integer VMLA scalar */

                case 4: /* Integer VMLS scalar */

                case 8: /* Integer VMUL scalar */

                case 12: /* VQDMULH scalar */

                case 13: /* VQRDMULH scalar */

                    if (u && ((rd | rn) & 1)) {

                        return 1;

                    }

                    tmp = neon_get_scalar(size, rm);

                    neon_store_scratch(0, tmp);

                    for (pass = 0; pass < (u ? 4 : 2); pass++) {

                        tmp = neon_load_scratch(0);

                        tmp2 = neon_load_reg(rn, pass);

                        if (op == 12) {

                            if (size == 1) {

                                gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);

                            } else {

                                gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);

                            }

                        } else if (op == 13) {

                            if (size == 1) {

                                gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);

                            } else {

                                gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);

                            }

                        } else if (op & 1) {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);

                            tcg_temp_free_ptr(fpstatus);

                        } else {

                            switch (size) {

                            case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;

                            case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;

                            case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;

                            default: abort();

                            }

                        }

                        tcg_temp_free_i32(tmp2);

                        if (op < 8) {

                            /* Accumulate.  */

                            tmp2 = neon_load_reg(rd, pass);

                            switch (op) {

                            case 0:

                                gen_neon_add(size, tmp, tmp2);

                                break;

                            case 1:

                            {

                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);

                                tcg_temp_free_ptr(fpstatus);

                                break;

                            }

                            case 4:

                                gen_neon_rsb(size, tmp, tmp2);

                                break;

                            case 5:

                            {

                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                                gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);

                                tcg_temp_free_ptr(fpstatus);

                                break;

                            }

                            default:

                                abort();

                            }

                            tcg_temp_free_i32(tmp2);

                        }

                        neon_store_reg(rd, pass, tmp);

                    }

                    break;

                case 3: /* VQDMLAL scalar */

                case 7: /* VQDMLSL scalar */

                case 11: /* VQDMULL scalar */

                    if (u == 1) {

                        return 1;

                    }

                    /* fall through */

                case 2: /* VMLAL sclar */

                case 6: /* VMLSL scalar */

                case 10: /* VMULL scalar */

                    if (rd & 1) {

                        return 1;

                    }

                    tmp2 = neon_get_scalar(size, rm);

                    /* We need a copy of tmp2 because gen_neon_mull

                     * deletes it during pass 0.  */

                    tmp4 = tcg_temp_new_i32();

                    tcg_gen_mov_i32(tmp4, tmp2);

                    tmp3 = neon_load_reg(rn, 1);

                    for (pass = 0; pass < 2; pass++) {

                        if (pass == 0) {

                            tmp = neon_load_reg(rn, 0);

                        } else {

                            tmp = tmp3;

                            tmp2 = tmp4;

                        }

                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);

                        if (op != 11) {

                            neon_load_reg64(cpu_V1, rd + pass);

                        }

                        switch (op) {

                        case 6:

                            gen_neon_negl(cpu_V0, size);

                            /* Fall through */

                        case 2:

                            gen_neon_addl(size);

                            break;

                        case 3: case 7:

                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);

                            if (op == 7) {

                                gen_neon_negl(cpu_V0, size);

                            }

                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);

                            break;

                        case 10:

                            /* no-op */

                            break;

                        case 11:

                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);

                            break;

                        default:

                            abort();

                        }

                        neon_store_reg64(cpu_V0, rd + pass);

                    }

                    break;

                default: /* 14 and 15 are RESERVED */

                    return 1;

                }

            }

        } else { /* size == 3 */

            if (!u) {

                /* Extract.  */

                imm = (insn >> 8) & 0xf;

                if (imm > 7 && !q)

                    return 1;

                if (q && ((rd | rn | rm) & 1)) {

                    return 1;

                }

                if (imm == 0) {

                    neon_load_reg64(cpu_V0, rn);

                    if (q) {

                        neon_load_reg64(cpu_V1, rn + 1);

                    }

                } else if (imm == 8) {

                    neon_load_reg64(cpu_V0, rn + 1);

                    if (q) {

                        neon_load_reg64(cpu_V1, rm);

                    }

                } else if (q) {

                    tmp64 = tcg_temp_new_i64();

                    if (imm < 8) {

                        neon_load_reg64(cpu_V0, rn);

                        neon_load_reg64(tmp64, rn + 1);

                    } else {

                        neon_load_reg64(cpu_V0, rn + 1);

                        neon_load_reg64(tmp64, rm);

                    }

                    tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);

                    tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8));

                    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);

                    if (imm < 8) {

                        neon_load_reg64(cpu_V1, rm);

                    } else {

                        neon_load_reg64(cpu_V1, rm + 1);

                        imm -= 8;

                    }

                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));

                    tcg_gen_shri_i64(tmp64, tmp64, imm * 8);

                    tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64);

                    tcg_temp_free_i64(tmp64);

                } else {

                    /* BUGFIX */

                    neon_load_reg64(cpu_V0, rn);

                    tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8);

                    neon_load_reg64(cpu_V1, rm);

                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));

                    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);

                }

                neon_store_reg64(cpu_V0, rd);

                if (q) {

                    neon_store_reg64(cpu_V1, rd + 1);

                }

            } else if ((insn & (1 << 11)) == 0) {

                /* Two register misc.  */

                op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);

                size = (insn >> 18) & 3;

                /* UNDEF for unknown op values and bad op-size combinations */

                if ((neon_2rm_sizes[op] & (1 << size)) == 0) {

                    return 1;

                }

                if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&

                    q && ((rm | rd) & 1)) {

                    return 1;

                }

                switch (op) {

                case NEON_2RM_VREV64:

                    for (pass = 0; pass < (q ? 2 : 1); pass++) {

                        tmp = neon_load_reg(rm, pass * 2);

                        tmp2 = neon_load_reg(rm, pass * 2 + 1);

                        switch (size) {

                        case 0: tcg_gen_bswap32_i32(tmp, tmp); break;

                        case 1: gen_swap_half(tmp); break;

                        case 2: /* no-op */ break;

                        default: abort();

                        }

                        neon_store_reg(rd, pass * 2 + 1, tmp);

                        if (size == 2) {

                            neon_store_reg(rd, pass * 2, tmp2);

                        } else {

                            switch (size) {

                            case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break;

                            case 1: gen_swap_half(tmp2); break;

                            default: abort();

                            }

                            neon_store_reg(rd, pass * 2, tmp2);

                        }

                    }

                    break;

                case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:

                case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:

                    for (pass = 0; pass < q + 1; pass++) {

                        tmp = neon_load_reg(rm, pass * 2);

                        gen_neon_widen(cpu_V0, tmp, size, op & 1);

                        tmp = neon_load_reg(rm, pass * 2 + 1);

                        gen_neon_widen(cpu_V1, tmp, size, op & 1);

                        switch (size) {

                        case 0: gen_helper_neon_paddl_u16(CPU_V001); break;

                        case 1: gen_helper_neon_paddl_u32(CPU_V001); break;

                        case 2: tcg_gen_add_i64(CPU_V001); break;

                        default: abort();

                        }

                        if (op >= NEON_2RM_VPADAL) {

                            /* Accumulate.  */

                            neon_load_reg64(cpu_V1, rd + pass);

                            gen_neon_addl(size);

                        }

                        neon_store_reg64(cpu_V0, rd + pass);

                    }

                    break;

                case NEON_2RM_VTRN:

                    if (size == 2) {

                        int n;

                        for (n = 0; n < (q ? 4 : 2); n += 2) {

                            tmp = neon_load_reg(rm, n);

                            tmp2 = neon_load_reg(rd, n + 1);

                            neon_store_reg(rm, n, tmp2);

                            neon_store_reg(rd, n + 1, tmp);

                        }

                    } else {

                        goto elementwise;

                    }

                    break;

                case NEON_2RM_VUZP:

                    if (gen_neon_unzip(rd, rm, size, q)) {

                        return 1;

                    }

                    break;

                case NEON_2RM_VZIP:

                    if (gen_neon_zip(rd, rm, size, q)) {

                        return 1;

                    }

                    break;

                case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:

                    /* also VQMOVUN; op field and mnemonics don't line up */

                    if (rm & 1) {

                        return 1;

                    }

                    TCGV_UNUSED_I32(tmp2);

                    for (pass = 0; pass < 2; pass++) {

                        neon_load_reg64(cpu_V0, rm + pass);

                        tmp = tcg_temp_new_i32();

                        gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size,

                                           tmp, cpu_V0);

                        if (pass == 0) {

                            tmp2 = tmp;

                        } else {

                            neon_store_reg(rd, 0, tmp2);

                            neon_store_reg(rd, 1, tmp);

                        }

                    }

                    break;

                case NEON_2RM_VSHLL:

                    if (q || (rd & 1)) {

                        return 1;

                    }

                    tmp = neon_load_reg(rm, 0);

                    tmp2 = neon_load_reg(rm, 1);

                    for (pass = 0; pass < 2; pass++) {

                        if (pass == 1)

                            tmp = tmp2;

                        gen_neon_widen(cpu_V0, tmp, size, 1);

                        tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size);

                        neon_store_reg64(cpu_V0, rd + pass);

                    }

                    break;

                case NEON_2RM_VCVT_F16_F32:

                    if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) ||

                        q || (rm & 1)) {

                        return 1;

                    }

                    tmp = tcg_temp_new_i32();

                    tmp2 = tcg_temp_new_i32();

                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));

                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);

                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));

                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);

                    tcg_gen_shli_i32(tmp2, tmp2, 16);

                    tcg_gen_or_i32(tmp2, tmp2, tmp);

                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));

                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);

                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));

                    neon_store_reg(rd, 0, tmp2);

                    tmp2 = tcg_temp_new_i32();

                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);

                    tcg_gen_shli_i32(tmp2, tmp2, 16);

                    tcg_gen_or_i32(tmp2, tmp2, tmp);

                    neon_store_reg(rd, 1, tmp2);

                    tcg_temp_free_i32(tmp);

                    break;

                case NEON_2RM_VCVT_F32_F16:

                    if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) ||

                        q || (rd & 1)) {

                        return 1;

                    }

                    tmp3 = tcg_temp_new_i32();

                    tmp = neon_load_reg(rm, 0);

                    tmp2 = neon_load_reg(rm, 1);

                    tcg_gen_ext16u_i32(tmp3, tmp);

                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);

                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));

                    tcg_gen_shri_i32(tmp3, tmp, 16);

                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);

                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));

                    tcg_temp_free_i32(tmp);

                    tcg_gen_ext16u_i32(tmp3, tmp2);

                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);

                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));

                    tcg_gen_shri_i32(tmp3, tmp2, 16);

                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);

                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));

                    tcg_temp_free_i32(tmp2);

                    tcg_temp_free_i32(tmp3);

                    break;

                case NEON_2RM_AESE: case NEON_2RM_AESMC:

                    if (!arm_dc_feature(s, ARM_FEATURE_V8_AES)

                        || ((rm | rd) & 1)) {

                        return 1;

                    }

                    tmp = tcg_const_i32(rd);

                    tmp2 = tcg_const_i32(rm);

                     /* Bit 6 is the lowest opcode bit; it distinguishes between

                      * encryption (AESE/AESMC) and decryption (AESD/AESIMC)

                      */

                    tmp3 = tcg_const_i32(extract32(insn, 6, 1));

                    if (op == NEON_2RM_AESE) {

                        gen_helper_crypto_aese(cpu_env, tmp, tmp2, tmp3);

                    } else {

                        gen_helper_crypto_aesmc(cpu_env, tmp, tmp2, tmp3);

                    }

                    tcg_temp_free_i32(tmp);

                    tcg_temp_free_i32(tmp2);

                    tcg_temp_free_i32(tmp3);

                    break;

                case NEON_2RM_SHA1H:

                    if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)

                        || ((rm | rd) & 1)) {

                        return 1;

                    }

                    tmp = tcg_const_i32(rd);

                    tmp2 = tcg_const_i32(rm);

                    gen_helper_crypto_sha1h(cpu_env, tmp, tmp2);

                    tcg_temp_free_i32(tmp);

                    tcg_temp_free_i32(tmp2);

                    break;

                case NEON_2RM_SHA1SU1:

                    if ((rm | rd) & 1) {

                            return 1;

                    }

                    /* bit 6 (q): set -> SHA256SU0, cleared -> SHA1SU1 */

                    if (q) {

                        if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA256)) {

                            return 1;

                        }

                    } else if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)) {

                        return 1;

                    }

                    tmp = tcg_const_i32(rd);

                    tmp2 = tcg_const_i32(rm);

                    if (q) {

                        gen_helper_crypto_sha256su0(cpu_env, tmp, tmp2);

                    } else {

                        gen_helper_crypto_sha1su1(cpu_env, tmp, tmp2);

                    }

                    tcg_temp_free_i32(tmp);

                    tcg_temp_free_i32(tmp2);

                    break;

                default:

                elementwise:

                    for (pass = 0; pass < (q ? 4 : 2); pass++) {

                        if (neon_2rm_is_float_op(op)) {

                            tcg_gen_ld_f32(cpu_F0s, cpu_env,

                                           neon_reg_offset(rm, pass));

                            TCGV_UNUSED_I32(tmp);

                        } else {

                            tmp = neon_load_reg(rm, pass);

                        }

                        switch (op) {

                        case NEON_2RM_VREV32:

                            switch (size) {

                            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;

                            case 1: gen_swap_half(tmp); break;

                            default: abort();

                            }

                            break;

                        case NEON_2RM_VREV16:

                            gen_rev16(tmp);

                            break;

                        case NEON_2RM_VCLS:

                            switch (size) {

                            case 0: gen_helper_neon_cls_s8(tmp, tmp); break;

                            case 1: gen_helper_neon_cls_s16(tmp, tmp); break;

                            case 2: gen_helper_neon_cls_s32(tmp, tmp); break;

                            default: abort();

                            }

                            break;

                        case NEON_2RM_VCLZ:

                            switch (size) {

                            case 0: gen_helper_neon_clz_u8(tmp, tmp); break;

                            case 1: gen_helper_neon_clz_u16(tmp, tmp); break;

                            case 2: gen_helper_clz(tmp, tmp); break;

                            default: abort();

                            }

                            break;

                        case NEON_2RM_VCNT:

                            gen_helper_neon_cnt_u8(tmp, tmp);

                            break;

                        case NEON_2RM_VMVN:

                            tcg_gen_not_i32(tmp, tmp);

                            break;

                        case NEON_2RM_VQABS:

                            switch (size) {

                            case 0:

                                gen_helper_neon_qabs_s8(tmp, cpu_env, tmp);

                                break;

                            case 1:

                                gen_helper_neon_qabs_s16(tmp, cpu_env, tmp);

                                break;

                            case 2:

                                gen_helper_neon_qabs_s32(tmp, cpu_env, tmp);

                                break;

                            default: abort();

                            }

                            break;

                        case NEON_2RM_VQNEG:

                            switch (size) {

                            case 0:

                                gen_helper_neon_qneg_s8(tmp, cpu_env, tmp);

                                break;

                            case 1:

                                gen_helper_neon_qneg_s16(tmp, cpu_env, tmp);

                                break;

                            case 2:

                                gen_helper_neon_qneg_s32(tmp, cpu_env, tmp);

                                break;

                            default: abort();

                            }

                            break;

                        case NEON_2RM_VCGT0: case NEON_2RM_VCLE0:

                            tmp2 = tcg_const_i32(0);

                            switch(size) {

                            case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break;

                            case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break;

                            case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break;

                            default: abort();

                            }

                            tcg_temp_free_i32(tmp2);

                            if (op == NEON_2RM_VCLE0) {

                                tcg_gen_not_i32(tmp, tmp);

                            }

                            break;

                        case NEON_2RM_VCGE0: case NEON_2RM_VCLT0:

                            tmp2 = tcg_const_i32(0);

                            switch(size) {

                            case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break;

                            case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break;

                            case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break;

                            default: abort();

                            }

                            tcg_temp_free_i32(tmp2);

                            if (op == NEON_2RM_VCLT0) {

                                tcg_gen_not_i32(tmp, tmp);

                            }

                            break;

                        case NEON_2RM_VCEQ0:

                            tmp2 = tcg_const_i32(0);

                            switch(size) {

                            case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;

                            case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;

                            case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;

                            default: abort();

                            }

                            tcg_temp_free_i32(tmp2);

                            break;

                        case NEON_2RM_VABS:

                            switch(size) {

                            case 0: gen_helper_neon_abs_s8(tmp, tmp); break;

                            case 1: gen_helper_neon_abs_s16(tmp, tmp); break;

                            case 2: tcg_gen_abs_i32(tmp, tmp); break;

                            default: abort();

                            }

                            break;

                        case NEON_2RM_VNEG:

                            tmp2 = tcg_const_i32(0);

                            gen_neon_rsb(size, tmp, tmp2);

                            tcg_temp_free_i32(tmp2);

                            break;

                        case NEON_2RM_VCGT0_F:

                        {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            tmp2 = tcg_const_i32(0);

                            gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);

                            tcg_temp_free_i32(tmp2);

                            tcg_temp_free_ptr(fpstatus);

                            break;

                        }

                        case NEON_2RM_VCGE0_F:

                        {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            tmp2 = tcg_const_i32(0);

                            gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);

                            tcg_temp_free_i32(tmp2);

                            tcg_temp_free_ptr(fpstatus);

                            break;

                        }

                        case NEON_2RM_VCEQ0_F:

                        {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            tmp2 = tcg_const_i32(0);

                            gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);

                            tcg_temp_free_i32(tmp2);

                            tcg_temp_free_ptr(fpstatus);

                            break;

                        }

                        case NEON_2RM_VCLE0_F:

                        {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            tmp2 = tcg_const_i32(0);

                            gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus);

                            tcg_temp_free_i32(tmp2);

                            tcg_temp_free_ptr(fpstatus);

                            break;

                        }

                        case NEON_2RM_VCLT0_F:

                        {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            tmp2 = tcg_const_i32(0);

                            gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus);

                            tcg_temp_free_i32(tmp2);

                            tcg_temp_free_ptr(fpstatus);

                            break;

                        }

                        case NEON_2RM_VABS_F:

                            gen_vfp_abs(0);

                            break;

                        case NEON_2RM_VNEG_F:

                            gen_vfp_neg(0);

                            break;

                        case NEON_2RM_VSWP:

                            tmp2 = neon_load_reg(rd, pass);

                            neon_store_reg(rm, pass, tmp2);

                            break;

                        case NEON_2RM_VTRN:

                            tmp2 = neon_load_reg(rd, pass);

                            switch (size) {

                            case 0: gen_neon_trn_u8(tmp, tmp2); break;

                            case 1: gen_neon_trn_u16(tmp, tmp2); break;

                            default: abort();

                            }

                            neon_store_reg(rm, pass, tmp2);

                            break;

                        case NEON_2RM_VRINTN:

                        case NEON_2RM_VRINTA:

                        case NEON_2RM_VRINTM:

                        case NEON_2RM_VRINTP:

                        case NEON_2RM_VRINTZ:

                        {

                            TCGv_i32 tcg_rmode;

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            int rmode;

                            if (op == NEON_2RM_VRINTZ) {

                                rmode = FPROUNDING_ZERO;

                            } else {

                                rmode = fp_decode_rm[((op & 0x6) >> 1) ^ 1];

                            }

                            tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));

                            gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,

                                                      cpu_env);

                            gen_helper_rints(cpu_F0s, cpu_F0s, fpstatus);

                            gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,

                                                      cpu_env);

                            tcg_temp_free_ptr(fpstatus);

                            tcg_temp_free_i32(tcg_rmode);

                            break;

                        }

                        case NEON_2RM_VRINTX:

                        {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            gen_helper_rints_exact(cpu_F0s, cpu_F0s, fpstatus);

                            tcg_temp_free_ptr(fpstatus);

                            break;

                        }

                        case NEON_2RM_VCVTAU:

                        case NEON_2RM_VCVTAS:

                        case NEON_2RM_VCVTNU:

                        case NEON_2RM_VCVTNS:

                        case NEON_2RM_VCVTPU:

                        case NEON_2RM_VCVTPS:

                        case NEON_2RM_VCVTMU:

                        case NEON_2RM_VCVTMS:

                        {

                            bool is_signed = !extract32(insn, 7, 1);

                            TCGv_ptr fpst = get_fpstatus_ptr(1);

                            TCGv_i32 tcg_rmode, tcg_shift;

                            int rmode = fp_decode_rm[extract32(insn, 8, 2)];

                            tcg_shift = tcg_const_i32(0);

                            tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));

                            gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,

                                                      cpu_env);

                            if (is_signed) {

                                gen_helper_vfp_tosls(cpu_F0s, cpu_F0s,

                                                     tcg_shift, fpst);

                            } else {

                                gen_helper_vfp_touls(cpu_F0s, cpu_F0s,

                                                     tcg_shift, fpst);

                            }

                            gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,

                                                      cpu_env);

                            tcg_temp_free_i32(tcg_rmode);

                            tcg_temp_free_i32(tcg_shift);

                            tcg_temp_free_ptr(fpst);

                            break;

                        }

                        case NEON_2RM_VRECPE:

                        {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            gen_helper_recpe_u32(tmp, tmp, fpstatus);

                            tcg_temp_free_ptr(fpstatus);

                            break;

                        }

                        case NEON_2RM_VRSQRTE:

                        {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            gen_helper_rsqrte_u32(tmp, tmp, fpstatus);

                            tcg_temp_free_ptr(fpstatus);

                            break;

                        }

                        case NEON_2RM_VRECPE_F:

                        {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            gen_helper_recpe_f32(cpu_F0s, cpu_F0s, fpstatus);

                            tcg_temp_free_ptr(fpstatus);

                            break;

                        }

                        case NEON_2RM_VRSQRTE_F:

                        {

                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);

                            gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, fpstatus);

                            tcg_temp_free_ptr(fpstatus);

                            break;

                        }

                        case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */

                            gen_vfp_sito(0, 1);

                            break;

                        case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */

                            gen_vfp_uito(0, 1);

                            break;

                        case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */

                            gen_vfp_tosiz(0, 1);

                            break;

                        case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */

                            gen_vfp_touiz(0, 1);

                            break;

                        default:

                            /* Reserved op values were caught by the

                             * neon_2rm_sizes[] check earlier.

                             */

                            abort();

                        }

                        if (neon_2rm_is_float_op(op)) {

                            tcg_gen_st_f32(cpu_F0s, cpu_env,

                                           neon_reg_offset(rd, pass));

                        } else {

                            neon_store_reg(rd, pass, tmp);

                        }

                    }

                    break;

                }

            } else if ((insn & (1 << 10)) == 0) {

                /* VTBL, VTBX.  */

                int n = ((insn >> 8) & 3) + 1;

                if ((rn + n) > 32) {

                    /* This is UNPREDICTABLE; we choose to UNDEF to avoid the

                     * helper function running off the end of the register file.

                     */

                    return 1;

                }

                n <<= 3;

                if (insn & (1 << 6)) {

                    tmp = neon_load_reg(rd, 0);

                } else {

                    tmp = tcg_temp_new_i32();

                    tcg_gen_movi_i32(tmp, 0);

                }

                tmp2 = neon_load_reg(rm, 0);

                tmp4 = tcg_const_i32(rn);

                tmp5 = tcg_const_i32(n);

                gen_helper_neon_tbl(tmp2, cpu_env, tmp2, tmp, tmp4, tmp5);

                tcg_temp_free_i32(tmp);

                if (insn & (1 << 6)) {

                    tmp = neon_load_reg(rd, 1);

                } else {

                    tmp = tcg_temp_new_i32();

                    tcg_gen_movi_i32(tmp, 0);

                }

                tmp3 = neon_load_reg(rm, 1);

                gen_helper_neon_tbl(tmp3, cpu_env, tmp3, tmp, tmp4, tmp5);

                tcg_temp_free_i32(tmp5);

                tcg_temp_free_i32(tmp4);

                neon_store_reg(rd, 0, tmp2);

                neon_store_reg(rd, 1, tmp3);

                tcg_temp_free_i32(tmp);

            } else if ((insn & 0x380) == 0) {

                /* VDUP */

                if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {

                    return 1;

                }

                if (insn & (1 << 19)) {

                    tmp = neon_load_reg(rm, 1);

                } else {

                    tmp = neon_load_reg(rm, 0);

                }

                if (insn & (1 << 16)) {

                    gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8);

                } else if (insn & (1 << 17)) {

                    if ((insn >> 18) & 1)

                        gen_neon_dup_high16(tmp);

                    else

                        gen_neon_dup_low16(tmp);

                }

                for (pass = 0; pass < (q ? 4 : 2); pass++) {

                    tmp2 = tcg_temp_new_i32();

                    tcg_gen_mov_i32(tmp2, tmp);

                    neon_store_reg(rd, pass, tmp2);

                }

                tcg_temp_free_i32(tmp);

            } else {

                return 1;

            }

        }

    }

    return 0;

}


static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token,

                        uint32_t nargs, target_ulong args,

                        uint32_t nret, target_ulong rets)

{

    struct ics_state *ics = spapr->icp->ics;

    uint32_t nr;

    if ((nargs != 1) || (nret != 1)) {

        rtas_st(rets, 0, -3);

        return;

    }

    nr = rtas_ld(args, 0);

    if (!ics_valid_irq(ics, nr)) {

        rtas_st(rets, 0, -3);

        return;

    }

    ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,

                   ics->irqs[nr - ics->offset].saved_priority,

                   ics->irqs[nr - ics->offset].saved_priority);

    rtas_st(rets, 0, 0); /* Success */

}


static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)

{

    const mon_cmd_t *cmd;

    const char *item = qdict_get_try_str(qdict, "item");

    if (!item)

        goto help;

    for (cmd = info_cmds; cmd->name != NULL; cmd++) {

        if (compare_cmd(item, cmd->name))

            break;

    }

    if (cmd->name == NULL)

        goto help;

    if (monitor_handler_ported(cmd)) {

        cmd->mhandler.info_new(mon, ret_data);

        if (*ret_data)

            cmd->user_print(mon, *ret_data);

    } else {

        cmd->mhandler.info(mon);

    }

    return;

help:

    help_cmd(mon, "info");

}


static int ehci_state_fetchsitd(EHCIState *ehci, int async)

{

    uint32_t entry;

    EHCIsitd sitd;

    assert(!async);

    entry = ehci_get_fetch_addr(ehci, async);

    get_dwords(NLPTR_GET(entry), (uint32_t *)&sitd,

               sizeof(EHCIsitd) >> 2);

    ehci_trace_sitd(ehci, entry, &sitd);

    if (!(sitd.results & SITD_RESULTS_ACTIVE)) {

        /* siTD is not active, nothing to do */;

    } else {

        /* TODO: split transfers are not implemented */

        fprintf(stderr, "WARNING: Skipping active siTD\n");

    }

    ehci_set_fetch_addr(ehci, async, sitd.next);

    ehci_set_state(ehci, async, EST_FETCHENTRY);

    return 1;

}


static void test_cdrom_dma(void)

{

    static const size_t len = ATAPI_BLOCK_SIZE;

    char *pattern = g_malloc(ATAPI_BLOCK_SIZE * 16);

    char *rx = g_malloc0(len);

    uintptr_t guest_buf;

    PrdtEntry prdt[1];

    FILE *fh;

    ide_test_start("-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "

                   "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);

    qtest_irq_intercept_in(global_qtest, "ioapic");

    guest_buf = guest_alloc(guest_malloc, len);

    prdt[0].addr = cpu_to_le32(guest_buf);

    prdt[0].size = cpu_to_le32(len | PRDT_EOT);

    generate_pattern(pattern, ATAPI_BLOCK_SIZE * 16, ATAPI_BLOCK_SIZE);

    fh = fopen(tmp_path, "w+");

    fwrite(pattern, ATAPI_BLOCK_SIZE, 16, fh);

    fclose(fh);

    send_dma_request(CMD_PACKET, 0, 1, prdt, 1, send_scsi_cdb_read10);

    /* Read back data from guest memory into local qtest memory */

    memread(guest_buf, rx, len);

    g_assert_cmpint(memcmp(pattern, rx, len), ==, 0);

    g_free(pattern);

    g_free(rx);

    test_bmdma_teardown();

}


static void test_abstract_interfaces(void)

{

    QList *all_types;

    QList *obj_types;

    QListEntry *ae;

    qtest_start(common_args);

    /* qom-list-types implements=interface would return any type

     * that implements _any_ interface (not just interface types),

     * so use a trick to find the interface type names:

     * - list all object types

     * - list all types, and look for items that are not

     *   on the first list

     */

    all_types = qom_list_types(NULL, false);

    obj_types = qom_list_types("object", false);

    QLIST_FOREACH_ENTRY(all_types, ae) {

        QDict *at = qobject_to_qdict(qlist_entry_obj(ae));

        const char *aname = qdict_get_str(at, "name");

        QListEntry *oe;

        const char *found = NULL;

        QLIST_FOREACH_ENTRY(obj_types, oe) {

            QDict *ot = qobject_to_qdict(qlist_entry_obj(oe));

            const char *oname = qdict_get_str(ot, "name");

            if (!strcmp(aname, oname)) {

                found = oname;

                break;

            }

        }

        /* Using g_assert_cmpstr() will give more useful failure

         * messages than g_assert(found) */

        g_assert_cmpstr(aname, ==, found);

    }

    QDECREF(all_types);

    QDECREF(obj_types);

    qtest_end();

}


static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,

                        const char *kernel_filename, const char *kernel_cmdline,

                        const char *initrd_filename, const char *cpu_model)

{

    char *filename;

    unsigned long ram_offset, bios_offset;

    long bios_size;

    int64_t kernel_entry;

    qemu_irq *i8259;

    qemu_irq *cpu_exit_irq;

    int via_devfn;

    PCIBus *pci_bus;

    uint8_t *eeprom_buf;

    i2c_bus *smbus;

    int i;

    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];

    DeviceState *eeprom;

    CPUState *env;

    /* init CPUs */

    if (cpu_model == NULL) {

        cpu_model = "Loongson-2E";

    }

    env = cpu_init(cpu_model);

    if (!env) {

        fprintf(stderr, "Unable to find CPU definition\n");

        exit(1);

    }

    register_savevm(NULL, "cpu", 0, 3, cpu_save, cpu_load, env);

    qemu_register_reset(main_cpu_reset, env);

    /* fulong 2e has 256M ram. */

    ram_size = 256 * 1024 * 1024;

    /* fulong 2e has a 1M flash.Winbond W39L040AP70Z */

    bios_size = 1024 * 1024;

    /* allocate RAM */

    ram_offset = qemu_ram_alloc(NULL, "fulong2e.ram", ram_size);

    bios_offset = qemu_ram_alloc(NULL, "fulong2e.bios", bios_size);

    cpu_register_physical_memory(0, ram_size, ram_offset);

    cpu_register_physical_memory(0x1fc00000LL,

					   bios_size, bios_offset | IO_MEM_ROM);

    /* We do not support flash operation, just loading pmon.bin as raw BIOS.

     * Please use -L to set the BIOS path and -bios to set bios name. */

    if (kernel_filename) {

        loaderparams.ram_size = ram_size;

        loaderparams.kernel_filename = kernel_filename;

        loaderparams.kernel_cmdline = kernel_cmdline;

        loaderparams.initrd_filename = initrd_filename;

        kernel_entry = load_kernel (env);

        write_bootloader(env, qemu_get_ram_ptr(bios_offset), kernel_entry);

    } else {

        if (bios_name == NULL) {

                bios_name = FULONG_BIOSNAME;

        }

        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);

        if (filename) {

            bios_size = load_image_targphys(filename, 0x1fc00000LL,

                                            BIOS_SIZE);

            qemu_free(filename);

        } else {

            bios_size = -1;

        }

        if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {

            fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", bios_name);

            exit(1);

        }

    }

    /* Init internal devices */

    cpu_mips_irq_init_cpu(env);

    cpu_mips_clock_init(env);

    /* Interrupt controller */

    /* The 8259 -> IP5  */

    i8259 = i8259_init(env->irq[5]);

    /* North bridge, Bonito --> IP2 */

    pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));

    /* South bridge */

    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {

        fprintf(stderr, "qemu: too many IDE bus\n");

        exit(1);

    }

    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {

        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);

    }

    via_devfn = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));

    if (via_devfn < 0) {

        fprintf(stderr, "vt82c686b_init error \n");

        exit(1);

    }

    isa_bus_irqs(i8259);

    vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1));

    usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2));

    usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3));

    smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4),

                              0xeee1, NULL);

    eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */

    memcpy(eeprom_buf, eeprom_spd, sizeof(eeprom_spd));

    /* TODO: Populate SPD eeprom data.  */

    eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");

    qdev_prop_set_uint8(eeprom, "address", 0x50);

    qdev_prop_set_ptr(eeprom, "data", eeprom_buf);

    qdev_init_nofail(eeprom);

    /* init other devices */

    pit = pit_init(0x40, isa_reserve_irq(0));

    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);

    DMA_init(0, cpu_exit_irq);

    /* Super I/O */

    isa_create_simple("i8042");

    rtc_init(2000, NULL);

    for(i = 0; i < MAX_SERIAL_PORTS; i++) {

        if (serial_hds[i]) {

            serial_isa_init(i, serial_hds[i]);

        }

    }

    if (parallel_hds[0]) {

        parallel_init(0, parallel_hds[0]);

    }

    /* Sound card */

    audio_init(pci_bus);

    /* Network card */

    network_init();

}