From patchwork Thu Sep 27 23:43:48 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 187565 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id ADC172C00B0 for ; Fri, 28 Sep 2012 09:44:12 +1000 (EST) Received: from localhost ([::1]:53783 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1THNkY-0003W5-RU for incoming@patchwork.ozlabs.org; Thu, 27 Sep 2012 19:44:10 -0400 Received: from eggs.gnu.org ([208.118.235.92]:50532) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1THNkI-0003Ly-Nn for qemu-devel@nongnu.org; Thu, 27 Sep 2012 19:43:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1THNkG-0006ir-Kh for qemu-devel@nongnu.org; Thu, 27 Sep 2012 19:43:54 -0400 Received: from mail-pb0-f45.google.com ([209.85.160.45]:64184) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1THNkG-0006ih-BR for qemu-devel@nongnu.org; Thu, 27 Sep 2012 19:43:52 -0400 Received: by pbbrp2 with SMTP id rp2so4318650pbb.4 for ; Thu, 27 Sep 2012 16:43:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=yYZZFe1/ZpAesscjMEcL1Yb8OQ6if2FbZiLauIbzeo4=; b=Zhx6WiyjGElJdmci2Mua/I0CekgRkiqeYVR5yv1yTOJoPyxe1wr28E7uFwIDrjsDqA 654C6z/O0Owk62oNqgXeMeSEOjQdwbB1c3ABSZ3c3APidVmvxal0JvI76q3Htnu9/Dbd l1SK0xqRmNs6NTmY+6b/g7s35FfFGOMbAEdyN3jL232HDIawgfarg8wHEJLnqP6RPf4w Vx1cYTZQjYzhwxt/J8aJo657EiYdLYm/+tO2B8yYrvu2/xGKy1rmK4E4+K4/sRcgh09o 8S9hKA306E0MfEcG59lOluZlDDZ69E00WlnqfskuDbrTK7ir0Bq7kEi4qsxMQqvUw02K I3rg== Received: by 10.68.221.70 with SMTP id qc6mr15877394pbc.92.1348789431661; Thu, 27 Sep 2012 16:43:51 -0700 (PDT) Received: from anchor.twiddle.home.com ([173.160.232.49]) by mx.google.com with ESMTPS id vi9sm2771221pbc.41.2012.09.27.16.43.50 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 27 Sep 2012 16:43:51 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Thu, 27 Sep 2012 16:43:48 -0700 Message-Id: <1348789428-24890-1-git-send-email-rth@twiddle.net> X-Mailer: git-send-email 1.7.11.4 In-Reply-To: <1348785610-23418-1-git-send-email-rth@twiddle.net> References: <1348785610-23418-1-git-send-email-rth@twiddle.net> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.160.45 Cc: Alexander Graf Subject: [Qemu-devel] [PATCH 052/147] target-s390: Convert SHIFT, ROTATE SINGLE X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Note that we were missing the 32-bit SLA. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 56 +++++++++--- target-s390x/cpu.h | 6 +- target-s390x/insn-data.def | 21 +++++ target-s390x/translate.c | 207 ++++++++++++++++++++++++--------------------- 4 files changed, 176 insertions(+), 114 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index d13f241..bead820 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -345,34 +345,59 @@ static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) } } -static uint32_t cc_calc_slag(uint64_t src, uint64_t shift) +static uint32_t cc_calc_sla_32(uint32_t src, int shift) { - uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); - uint64_t match, r; + uint32_t mask = ((1U << shift) - 1U) << (32 - shift); + uint32_t sign = 1U << 31; + uint32_t match; + int32_t r; - /* check if the sign bit stays the same */ - if (src & (1ULL << 63)) { + /* Check if the sign bit stays the same. */ + if (src & sign) { match = mask; } else { match = 0; } - if ((src & mask) != match) { - /* overflow */ + /* Overflow. */ return 3; } - r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63)); - - if ((int64_t)r == 0) { + r = ((src << shift) & ~sign) | (src & sign); + if (r == 0) { return 0; - } else if ((int64_t)r < 0) { + } else if (r < 0) { return 1; } - return 2; } +static uint32_t cc_calc_sla_64(uint64_t src, int shift) +{ + uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); + uint64_t sign = 1ULL << 63; + uint64_t match; + int64_t r; + + /* Check if the sign bit stays the same. */ + if (src & sign) { + match = mask; + } else { + match = 0; + } + if ((src & mask) != match) { + /* Overflow. */ + return 3; + } + + r = ((src << shift) & ~sign) | (src & sign); + if (r == 0) { + return 0; + } else if (r < 0) { + return 1; + } + return 2; +} static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr) @@ -473,8 +498,11 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_ICM: r = cc_calc_icm(src, dst); break; - case CC_OP_SLAG: - r = cc_calc_slag(src, dst); + case CC_OP_SLA_32: + r = cc_calc_sla_32(src, dst); + break; + case CC_OP_SLA_64: + r = cc_calc_sla_64(src, dst); break; case CC_OP_LTGT_F32: diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 5b6df0e..ae9b4a3 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -478,7 +478,8 @@ enum cc_op { CC_OP_NZ_F64, /* FP dst != 0 (64bit) */ CC_OP_ICM, /* insert characters under mask */ - CC_OP_SLAG, /* Calculate shift left signed */ + CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ + CC_OP_SLA_64, /* Calculate shift left signed (64bit) */ CC_OP_MAX }; @@ -521,7 +522,8 @@ static const char *cc_names[] = { [CC_OP_NZ_F32] = "CC_OP_NZ_F32", [CC_OP_NZ_F64] = "CC_OP_NZ_F64", [CC_OP_ICM] = "CC_OP_ICM", - [CC_OP_SLAG] = "CC_OP_SLAG", + [CC_OP_SLA_32] = "CC_OP_SLA_32", + [CC_OP_SLA_64] = "CC_OP_SLA_64", }; static inline const char *cc_name(int cc_op) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0a0ec0a..6020e04 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -315,6 +315,27 @@ D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) +/* ROTATE LEFT SINGLE LOGICAL */ + C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) + C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) + +/* SHIFT LEFT SINGLE */ + D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) + D(0xebdd, SLAK, RSY_a, DO, r3, sh32, new, r1_32, sla, 0, 31) + D(0xeb0b, SLAG, RSY_a, Z, r3, sh64, r1, 0, sla, 0, 63) +/* SHIFT LEFT SINGLE LOGICAL */ + C(0x8900, SLL, RS_a, Z, r1_o, sh32, new, r1_32, sll, 0) + C(0xebdf, SLLK, RSY_a, DO, r3_o, sh32, new, r1_32, sll, 0) + C(0xeb0d, SLLG, RSY_a, Z, r3_o, sh64, r1, 0, sll, 0) +/* SHIFT RIGHT SINGLE */ + C(0x8a00, SRA, RS_a, Z, r1_32s, sh32, new, r1_32, sra, s32) + C(0xebdc, SRAK, RSY_a, DO, r3_32s, sh32, new, r1_32, sra, s32) + C(0xeb0a, SRAG, RSY_a, Z, r3_o, sh64, r1, 0, sra, s64) +/* SHIFT RIGHT SINGLE LOGICAL */ + C(0x8800, SRL, RS_a, Z, r1_32u, sh32, new, r1_32, srl, 0) + C(0xebde, SRLK, RSY_a, DO, r3_32u, sh32, new, r1_32, srl, 0) + C(0xeb0c, SRLG, RSY_a, Z, r3_o, sh64, r1, 0, srl, 0) + /* STORE */ C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 49e3599..848bb26 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -636,7 +636,8 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_TM_64: case CC_OP_LTGT_F32: case CC_OP_LTGT_F64: - case CC_OP_SLAG: + case CC_OP_SLA_32: + case CC_OP_SLA_64: /* 2 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); break; @@ -1330,74 +1331,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); switch (op) { - case 0xc: /* SRLG R1,R3,D2(B2) [RSY] */ - case 0xd: /* SLLG R1,R3,D2(B2) [RSY] */ - case 0xa: /* SRAG R1,R3,D2(B2) [RSY] */ - case 0xb: /* SLAG R1,R3,D2(B2) [RSY] */ - case 0x1c: /* RLLG R1,R3,D2(B2) [RSY] */ - if (b2) { - tmp = get_address(s, 0, b2, d2); - tcg_gen_andi_i64(tmp, tmp, 0x3f); - } else { - tmp = tcg_const_i64(d2 & 0x3f); - } - switch (op) { - case 0xc: - tcg_gen_shr_i64(regs[r1], regs[r3], tmp); - break; - case 0xd: - tcg_gen_shl_i64(regs[r1], regs[r3], tmp); - break; - case 0xa: - tcg_gen_sar_i64(regs[r1], regs[r3], tmp); - break; - case 0xb: - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - gen_op_update2_cc_i64(s, CC_OP_SLAG, regs[r3], tmp); - tcg_gen_shl_i64(tmp2, regs[r3], tmp); - /* override sign bit with source sign */ - tcg_gen_andi_i64(tmp2, tmp2, ~0x8000000000000000ULL); - tcg_gen_andi_i64(tmp3, regs[r3], 0x8000000000000000ULL); - tcg_gen_or_i64(regs[r1], tmp2, tmp3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x1c: - tcg_gen_rotl_i64(regs[r1], regs[r3], tmp); - break; - default: - tcg_abort(); - break; - } - if (op == 0xa) { - set_cc_s64(s, regs[r1]); - } - tcg_temp_free_i64(tmp); - break; - case 0x1d: /* RLL R1,R3,D2(B2) [RSY] */ - if (b2) { - tmp = get_address(s, 0, b2, d2); - tcg_gen_andi_i64(tmp, tmp, 0x3f); - } else { - tmp = tcg_const_i64(d2 & 0x3f); - } - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = load_reg32(r3); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - switch (op) { - case 0x1d: - tcg_gen_rotl_i32(tmp32_1, tmp32_2, tmp32_1); - break; - default: - tcg_abort(); - break; - } - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x4: /* LMG R1,R3,D2(B2) [RSE] */ case 0x24: /* STMG R1,R3,D2(B2) [RSE] */ stm_len = 8; @@ -2355,35 +2288,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x88: /* SRL R1,D2(B2) [RS] */ - case 0x89: /* SLL R1,D2(B2) [RS] */ - case 0x8a: /* SRA R1,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp32_2, tmp); - tcg_gen_andi_i32(tmp32_2, tmp32_2, 0x3f); - switch (opc) { - case 0x88: - tcg_gen_shr_i32(tmp32_1, tmp32_1, tmp32_2); - break; - case 0x89: - tcg_gen_shl_i32(tmp32_1, tmp32_1, tmp32_2); - break; - case 0x8a: - tcg_gen_sar_i32(tmp32_1, tmp32_1, tmp32_2); - set_cc_s32(s, tmp32_1); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x8c: /* SRDL R1,D2(B2) [RS] */ case 0x8d: /* SLDL R1,D2(B2) [RS] */ case 0x8e: /* SRDA R1,D2(B2) [RS] */ @@ -3029,6 +2933,20 @@ struct DisasInsn { /* ====================================================================== */ /* Miscelaneous helpers, used by several operations. */ +static void help_l2_shift(DisasContext *s, DisasFields *f, + DisasOps *o, int mask) +{ + int b2 = get_field(f, b2); + int d2 = get_field(f, d2); + + if (b2 == 0) { + o->in2 = tcg_const_i64(d2 & mask); + } else { + o->in2 = get_address(s, 0, b2, d2); + tcg_gen_andi_i64(o->in2, o->in2, mask); + } +} + static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) { if (dest == s->next_pc) { @@ -3591,6 +3509,59 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_rll32(DisasContext *s, DisasOps *o) +{ + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 to = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t1, o->in1); + tcg_gen_trunc_i64_i32(t2, o->in2); + tcg_gen_rotl_i32(to, t1, t2); + tcg_gen_extu_i32_i64(o->out, to); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(to); + return NO_EXIT; +} + +static ExitStatus op_rll64(DisasContext *s, DisasOps *o) +{ + tcg_gen_rotl_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sla(DisasContext *s, DisasOps *o) +{ + uint64_t sign = 1ull << s->insn->data; + enum cc_op cco = s->insn->data == 31 ? CC_OP_SLA_32 : CC_OP_SLA_64; + gen_op_update2_cc_i64(s, cco, o->in1, o->in2); + tcg_gen_shl_i64(o->out, o->in1, o->in2); + /* The arithmetic left shift is curious in that it does not affect + the sign bit. Copy that over from the source unchanged. */ + tcg_gen_andi_i64(o->out, o->out, ~sign); + tcg_gen_andi_i64(o->in1, o->in1, sign); + tcg_gen_or_i64(o->out, o->out, o->in1); + return NO_EXIT; +} + +static ExitStatus op_sll(DisasContext *s, DisasOps *o) +{ + tcg_gen_shl_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sra(DisasContext *s, DisasOps *o) +{ + tcg_gen_sar_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_srl(DisasContext *s, DisasOps *o) +{ + tcg_gen_shr_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_ssm(DisasContext *s, DisasOps *o) { @@ -3961,6 +3932,18 @@ static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = true; } +static void in1_r1_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1)]); +} + +static void in1_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1)]); +} + static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o) { /* ??? Specification exception: r1 must be even. */ @@ -4002,6 +3985,24 @@ static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = load_reg(get_field(f, r3)); } +static void in1_r3_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = regs[get_field(f, r3)]; + o->g_in1 = true; +} + +static void in1_r3_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r3)]); +} + +static void in1_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r3)]); +} + static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_freg32_i64(get_field(f, r1)); @@ -4153,6 +4154,16 @@ static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2); } +static void in2_sh32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + help_l2_shift(s, f, o, 31); +} + +static void in2_sh64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + help_l2_shift(s, f, o, 63); +} + static void in2_m2_8u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o);