From 8612c935831647c193281992738f96292428b9e6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 Sep 2013 09:31:37 -0700 Subject: [PATCH 01/10] target-s390: Implement SAM specification exception Also, these are user-mode instructions; allow their use in CONFIG_USER_ONLY. Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 8 ++++---- target-s390x/translate.c | 31 +++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4d2feb6977..42b99b2746 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -566,6 +566,10 @@ /* SET ACCESS */ C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) +/* SET ADDRESSING MODE */ + D(0x010c, SAM24, E, Z, 0, 0, 0, 0, sam, 0, 0) + D(0x010d, SAM31, E, Z, 0, 0, 0, 0, sam, 0, 1) + D(0x010e, SAM64, E, Z, 0, 0, 0, 0, sam, 0, 3) /* SET FPC */ C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0) /* SET FPC AND SIGNAL */ @@ -743,10 +747,6 @@ C(0xb22a, RRBE, RRE, Z, 0, r2_o, 0, 0, rrbe, 0) /* SERVICE CALL LOGICAL PROCESSOR (PV hypercall) */ C(0xb220, SERVC, RRE, Z, r1_o, r2_o, 0, 0, servc, 0) -/* SET ADDRESSING MODE */ - D(0x010c, SAM24, E, Z, 0, 0, 0, 0, sam, 0, 0) - D(0x010d, SAM31, E, Z, 0, 0, 0, 0, sam, 0, 1) - D(0x010e, SAM64, E, Z, 0, 0, 0, 0, sam, 0, 3) /* SET ADDRESS SPACE CONTROL FAST */ C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0) /* SET CLOCK */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index ab01bc004e..1338bb5a34 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2925,19 +2925,42 @@ static ExitStatus op_sacf(DisasContext *s, DisasOps *o) /* Addressing mode has changed, so end the block. */ return EXIT_PC_STALE; } +#endif static ExitStatus op_sam(DisasContext *s, DisasOps *o) { int sam = s->insn->data; - TCGv_i64 tsam = tcg_const_i64(sam); + TCGv_i64 tsam; + uint64_t mask; - /* Overwrite PSW_MASK_64 and PSW_MASK_32 */ + switch (sam) { + case 0: + mask = 0xffffff; + break; + case 1: + mask = 0x7fffffff; + break; + default: + mask = -1; + break; + } + + /* Bizzare but true, we check the address of the current insn for the + specification exception, not the next to be executed. Thus the PoO + documents that Bad Things Happen two bytes before the end. */ + if (s->pc & ~mask) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + s->next_pc &= mask; + + tsam = tcg_const_i64(sam); tcg_gen_deposit_i64(psw_mask, psw_mask, tsam, 31, 2); - tcg_temp_free_i64(tsam); + + /* Always exit the TB, since we (may have) changed execution mode. */ return EXIT_PC_STALE; } -#endif static ExitStatus op_sar(DisasContext *s, DisasOps *o) { From e30a9d3fea58c356000ce328421fe65e03143bb1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 Sep 2013 09:48:08 -0700 Subject: [PATCH 02/10] target-s390: Implement EPSW Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 42b99b2746..859cfba8a0 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -287,6 +287,8 @@ C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0) /* EXTRACT FPC */ C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0) +/* EXTRACT PSW */ + C(0xb98d, EPSW, RRE, Z, 0, 0, 0, 0, epsw, 0) /* FIND LEFTMOST ONE */ C(0xb983, FLOGR, RRE, EI, 0, r2_o, r1_P, 0, flogr, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1338bb5a34..97137c99cf 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2051,6 +2051,24 @@ static ExitStatus op_efpc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_epsw(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r2 = get_field(s->fields, r2); + TCGv_i64 t = tcg_temp_new_i64(); + + /* Note the "subsequently" in the PoO, which implies a defined result + if r1 == r2. Thus we cannot defer these writes to an output hook. */ + tcg_gen_shri_i64(t, psw_mask, 32); + store_reg32_i64(r1, t); + if (r2 != 0) { + store_reg32_i64(r2, psw_mask); + } + + tcg_temp_free_i64(t); + return NO_EXIT; +} + static ExitStatus op_ex(DisasContext *s, DisasOps *o) { /* ??? Perhaps a better way to implement EXECUTE is to set a bit in From 7f745b31b39cb9be8b3c3dfaf3173390ae07353e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 20 Sep 2013 11:33:41 -0700 Subject: [PATCH 03/10] target-s390: Fix STIDP The implementation had been incomplete, as we did not store the machine type. Note that the machine_type member is still unset during initialization, so this has no effect yet. Signed-off-by: Richard Henderson --- target-s390x/cpu.h | 4 +++- target-s390x/translate.c | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index c123b6f023..2e2554c4b3 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -133,7 +133,9 @@ typedef struct CPUS390XState { /* reset does memset(0) up to here */ - int cpu_num; + uint32_t cpu_num; + uint32_t machine_type; + uint8_t *storage_keys; uint64_t tod_offset; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 97137c99cf..0c5191737d 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -3262,8 +3262,14 @@ static ExitStatus op_stctl(DisasContext *s, DisasOps *o) static ExitStatus op_stidp(DisasContext *s, DisasOps *o) { + TCGv_i64 t1 = tcg_temp_new_i64(); + check_privileged(s); tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num)); + tcg_gen_ld32u_i64(t1, cpu_env, offsetof(CPUS390XState, machine_type)); + tcg_gen_deposit_i64(o->out, o->out, t1, 32, 32); + tcg_temp_free_i64(t1); + return NO_EXIT; } From 81822c2f42e0c3d7bf36f6eec92941de33ed92b8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 20 Sep 2013 12:46:49 -0700 Subject: [PATCH 04/10] target-s390: Fix STURA We were storing 16 bits instead of 32. Signed-off-by: Richard Henderson --- target-s390x/mem_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 5a55de86a1..4736b7bba8 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -1039,7 +1039,7 @@ void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1) { CPUState *cs = CPU(s390_env_get_cpu(env)); - stw_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1); + stl_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1); } /* load real address */ From 9c3fd85b142f244ac1900b9da02f2d733d03c1b1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 20 Sep 2013 13:04:28 -0700 Subject: [PATCH 05/10] target-s390: Implement LURA, LURAG, STURG Signed-off-by: Richard Henderson --- target-s390x/helper.h | 3 +++ target-s390x/insn-data.def | 4 ++++ target-s390x/mem_helper.c | 22 ++++++++++++++++++++++ target-s390x/translate.c | 26 ++++++++++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index faebfd96aa..8d2c8596bb 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -111,5 +111,8 @@ DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(lra, i64, env, i64) +DEF_HELPER_FLAGS_2(lura, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(lurag, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64) #endif diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 859cfba8a0..60dbe805bb 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -739,6 +739,9 @@ C(0xb100, LRA, RX_a, Z, 0, a2, r1, 0, lra, 0) C(0xe313, LRAY, RXY_a, LD, 0, a2, r1, 0, lra, 0) C(0xe303, LRAG, RXY_a, Z, 0, a2, r1, 0, lra, 0) +/* LOAD USING REAL ADDRESS */ + C(0xb24b, LURA, RRE, Z, 0, r2, new, r1_32, lura, 0) + C(0xb905, LURAG, RRE, Z, 0, r2, r1, 0, lurag, 0) /* MOVE TO PRIMARY */ C(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0) /* MOVE TO SECONDARY */ @@ -796,6 +799,7 @@ C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE USING REAL ADDRESS */ C(0xb246, STURA, RRE, Z, r1_o, r2_o, 0, 0, stura, 0) + C(0xb925, STURG, RRE, Z, r1_o, r2_o, 0, 0, sturg, 0) /* TEST PROTECTION */ C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 4736b7bba8..53bb629fc3 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -1034,6 +1034,21 @@ void HELPER(ptlb)(CPUS390XState *env) tlb_flush(CPU(cpu), 1); } +/* load using real address */ +uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr) +{ + CPUState *cs = CPU(s390_env_get_cpu(env)); + + return (uint32_t)ldl_phys(cs->as, get_address(env, 0, 0, addr)); +} + +uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr) +{ + CPUState *cs = CPU(s390_env_get_cpu(env)); + + return ldq_phys(cs->as, get_address(env, 0, 0, addr)); +} + /* store using real address */ void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1) { @@ -1042,6 +1057,13 @@ void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1) stl_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1); } +void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1) +{ + CPUState *cs = CPU(s390_env_get_cpu(env)); + + stq_phys(cs->as, get_address(env, 0, 0, addr), v1); +} + /* load real address */ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0c5191737d..b7b74ea759 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2478,6 +2478,24 @@ static ExitStatus op_lm64(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_lura(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_lura(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_lurag(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_lurag(o->out, cpu_env, o->in2); + return NO_EXIT; +} +#endif + static ExitStatus op_mov2(DisasContext *s, DisasOps *o) { o->out = o->in2; @@ -3364,6 +3382,14 @@ static ExitStatus op_stura(DisasContext *s, DisasOps *o) gen_helper_stura(cpu_env, o->in2, o->in1); return NO_EXIT; } + +static ExitStatus op_sturg(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_sturg(cpu_env, o->in2, o->in1); + return NO_EXIT; +} #endif static ExitStatus op_st8(DisasContext *s, DisasOps *o) From 0774710f1bd052b05cc68ca3af06d8fc1a65664b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 20 Sep 2013 15:34:34 -0700 Subject: [PATCH 06/10] target-s390: Implement ECAG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 60dbe805bb..8d8e47e0bf 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -285,6 +285,8 @@ /* EXTRACT ACCESS */ C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0) +/* EXTRACT CPU ATTRIBUTE */ + C(0xeb4c, ECAG, RSY_a, GIE, 0, a2, r1, 0, ecag, 0) /* EXTRACT FPC */ C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0) /* EXTRACT PSW */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b7b74ea759..e7a6c1d621 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2045,6 +2045,13 @@ static ExitStatus op_ear(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ecag(DisasContext *s, DisasOps *o) +{ + /* No cache information provided. */ + tcg_gen_movi_i64(o->out, -1); + return NO_EXIT; +} + static ExitStatus op_efpc(DisasContext *s, DisasOps *o) { tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc)); From 8841d9dfc7f871cec7c3401a8a2d31ad34e881f7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jan 2015 16:28:30 +0000 Subject: [PATCH 07/10] target-s390x: Mark check_privileged() as !CONFIG_USER_ONLY The function check_privileged() is only used in the softmmu configs; wrap it in an #ifndef CONFIG_USER_ONLY to avoid clang warnings on the linux-user builds. [rth: Remove inline marker too; it was only there to prevent exactly this warning in GCC.] Signed-off-by: Peter Maydell Reviewed-by: Stefan Weil Message-id: 1419373100-17690-2-git-send-email-peter.maydell@linaro.org Signed-off-by: Richard Henderson --- target-s390x/translate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e7a6c1d621..8b36eca718 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -317,12 +317,14 @@ static inline void gen_illegal_opcode(DisasContext *s) gen_program_exception(s, PGM_SPECIFICATION); } -static inline void check_privileged(DisasContext *s) +#ifndef CONFIG_USER_ONLY +static void check_privileged(DisasContext *s) { if (s->tb->flags & (PSW_MASK_PSTATE >> 32)) { gen_program_exception(s, PGM_PRIVILEGED); } } +#endif static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) { From 5b279407704613dbee8bc0866817bf7006b487a5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Jan 2015 16:28:31 +0000 Subject: [PATCH 08/10] disas/s390.c: Remove unused variables The variables s390_opformats and s390_num_opformats are unused and provoke clang warnings: disas/s390.c:849:33: warning: variable 's390_opformats' is not needed and will not be emitted [-Wunneeded-internal-declaration] static const struct s390_opcode s390_opformats[] = ^ disas/s390.c:875:18: warning: unused variable 's390_num_opformats' [-Wunused-const-variable] static const int s390_num_opformats = ^ Delete them, since QEMU doesn't use them. Signed-off-by: Peter Maydell Reviewed-by: Stefan Weil Message-id: 1419373100-17690-3-git-send-email-peter.maydell@linaro.org Signed-off-by: Richard Henderson --- disas/s390.c | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/disas/s390.c b/disas/s390.c index 25499ba419..974460c814 100644 --- a/disas/s390.c +++ b/disas/s390.c @@ -106,10 +106,6 @@ struct s390_opcode static const struct s390_opcode s390_opcodes[]; static const int s390_num_opcodes; -/* A opcode format table for the .insn pseudo mnemonic. */ -static const struct s390_opcode s390_opformats[]; -static const int s390_num_opformats; - /* Values defined for the flags field of a struct powerpc_opcode. */ /* The operands table is an array of struct s390_operand. */ @@ -844,37 +840,6 @@ static const struct s390_operand s390_operands[] = #define MASK_SIY_DRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } /* QEMU-END */ -/* The opcode formats table (blueprints for .insn pseudo mnemonic). */ - -static const struct s390_opcode s390_opformats[] = - { - { "e", OP8(0x00LL), MASK_E, INSTR_E, 3, 0 }, - { "ri", OP8(0x00LL), MASK_RI_RI, INSTR_RI_RI, 3, 0 }, - { "rie", OP8(0x00LL), MASK_RIE_RRP, INSTR_RIE_RRP, 3, 0 }, - { "ril", OP8(0x00LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 0 }, - { "rilu", OP8(0x00LL), MASK_RIL_RU, INSTR_RIL_RU, 3, 0 }, - { "rr", OP8(0x00LL), MASK_RR_RR, INSTR_RR_RR, 3, 0 }, - { "rre", OP8(0x00LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0 }, - { "rrf", OP8(0x00LL), MASK_RRF_RURR, INSTR_RRF_RURR, 3, 0 }, - { "rs", OP8(0x00LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0 }, - { "rse", OP8(0x00LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0 }, - { "rsi", OP8(0x00LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0 }, - { "rsy", OP8(0x00LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3 }, - { "rx", OP8(0x00LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0 }, - { "rxe", OP8(0x00LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 0 }, - { "rxf", OP8(0x00LL), MASK_RXF_RRRDR, INSTR_RXF_RRRDR,3, 0 }, - { "rxy", OP8(0x00LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3 }, - { "s", OP8(0x00LL), MASK_S_RD, INSTR_S_RD, 3, 0 }, - { "si", OP8(0x00LL), MASK_SI_URD, INSTR_SI_URD, 3, 0 }, - { "siy", OP8(0x00LL), MASK_SIY_URD, INSTR_SIY_URD, 3, 3 }, - { "ss", OP8(0x00LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD,3, 0 }, - { "sse", OP8(0x00LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0 }, - { "ssf", OP8(0x00LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD,3, 0 }, -}; - -static const int s390_num_opformats = - sizeof (s390_opformats) / sizeof (s390_opformats[0]); - /* include "s390-opc.tab" generated from opcodes/s390-opc.txt rev 1.17 */ /* The opcode table. This file was generated by s390-mkopc. From 8cf02f93dc37bc3de30dfb74eb0e904d1700dbf6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 8 Jan 2015 18:01:08 +0100 Subject: [PATCH 09/10] target-s390x: support OC and NC in the EX instruction This is needed to run the GMP testsuite. Reported-by: Torbjorn Granlund Tested-by: Torbjorn Granlund Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-s390x/mem_helper.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 53bb629fc3..d67b345ad1 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -490,10 +490,18 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, helper_mvc(env, l, get_address(env, 0, b1, d1), get_address(env, 0, b2, d2)); break; + case 0x400: + cc = helper_nc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; case 0x500: cc = helper_clc(env, l, get_address(env, 0, b1, d1), get_address(env, 0, b2, d2)); break; + case 0x600: + cc = helper_oc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; case 0x700: cc = helper_xc(env, l, get_address(env, 0, b1, d1), get_address(env, 0, b2, d2)); From 9ef1473693a1400a903567489d3122fc9511765d Mon Sep 17 00:00:00 2001 From: Torbjorn Granlund Date: Thu, 8 Jan 2015 18:01:09 +0100 Subject: [PATCH 10/10] target-s390x: fix and optimize slb* and slbg* computation of carry/borrow flag This patch fixes the bug with borrow_in being set incorrectly, but it also simplifies the logic to be much more plain, improving speed. It fixes both the 32-bit SLB* and 64-bit SLBG*. The SLBG* change has been well-tested. I haven't tested the SLB* change explicitly, but the code was copy-pasted from the tested code. The error of these functions' current implementations would not likely be triggered by compiler-generated code, since the only error was in the state of the carry/borrow flag. Compilers rarely generate an instruction sequence such as carry-set -> carry-set-and-use -> carry-use. (With Paolo's fix and mine, there are still a couple of failures from GMP's testsuite, but they are almost surely due to incorrect code generation from gcc 4.9. But since this gcc is running under qemu, it might be qemu bugs. I intend to investigate this.) Signed-off-by: Torbjorn Granlund Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 373eb176a1..00bc883a8a 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -179,16 +179,11 @@ static uint32_t cc_calc_subu_64(uint64_t a1, uint64_t a2, uint64_t ar) static uint32_t cc_calc_subb_64(uint64_t a1, uint64_t a2, uint64_t ar) { - /* We had borrow-in if normal subtraction isn't equal. */ - int borrow_in = ar - (a1 - a2); int borrow_out; - /* If a2 was ULONG_MAX, and borrow_in, then a2 is logically 65 bits, - and we must have had borrow out. */ - if (borrow_in && a2 == (uint64_t)-1) { - borrow_out = 1; + if (ar != a1 - a2) { /* difference means borrow-in */ + borrow_out = (a2 >= a1); } else { - a2 += borrow_in; borrow_out = (a2 > a1); } @@ -285,16 +280,11 @@ static uint32_t cc_calc_subu_32(uint32_t a1, uint32_t a2, uint32_t ar) static uint32_t cc_calc_subb_32(uint32_t a1, uint32_t a2, uint32_t ar) { - /* We had borrow-in if normal subtraction isn't equal. */ - int borrow_in = ar - (a1 - a2); int borrow_out; - /* If a2 was UINT_MAX, and borrow_in, then a2 is logically 65 bits, - and we must have had borrow out. */ - if (borrow_in && a2 == (uint32_t)-1) { - borrow_out = 1; + if (ar != a1 - a2) { /* difference means borrow-in */ + borrow_out = (a2 >= a1); } else { - a2 += borrow_in; borrow_out = (a2 > a1); }