From be8f3260feb1b5eea339328f349d15af6b81e244 Mon Sep 17 00:00:00 2001 From: Florian Krohm Date: Fri, 13 Apr 2012 04:04:06 +0000 Subject: [PATCH] Translation chaining for s390. To be debugged. git-svn-id: svn://svn.valgrind.org/vex/branches/TCHAIN@2279 --- VEX/priv/guest_s390_defs.h | 1 - VEX/priv/guest_s390_helpers.c | 2 + VEX/priv/guest_s390_toIR.c | 173 +++--- VEX/priv/host_s390_defs.c | 963 +++++++++++++++++++++++++++------- VEX/priv/host_s390_defs.h | 85 ++- VEX/priv/host_s390_isel.c | 165 +++++- VEX/priv/main_main.c | 27 +- VEX/pub/libvex_guest_s390x.h | 6 +- VEX/pub/libvex_s390x_common.h | 13 +- 9 files changed, 1151 insertions(+), 284 deletions(-) diff --git a/VEX/priv/guest_s390_defs.h b/VEX/priv/guest_s390_defs.h index 754ce3d091..b7e57ba4a8 100644 --- a/VEX/priv/guest_s390_defs.h +++ b/VEX/priv/guest_s390_defs.h @@ -43,7 +43,6 @@ /* Convert one s390 insn to IR. See the type DisOneInstrFn in bb_to_IR.h. */ DisResult disInstr_S390 ( IRSB* irbb, - Bool put_IP, Bool (*resteerOkFn) ( void*, Addr64 ), Bool resteerCisOk, void* callback_opaque, diff --git a/VEX/priv/guest_s390_helpers.c b/VEX/priv/guest_s390_helpers.c index 47a0635c0c..167d426a58 100644 --- a/VEX/priv/guest_s390_helpers.c +++ b/VEX/priv/guest_s390_helpers.c @@ -130,6 +130,8 @@ LibVEX_GuestS390X_initialise(VexGuestS390XState *state) state->guest_TILEN = 0; state->guest_IP_AT_SYSCALL = 0; state->guest_EMWARN = EmWarn_NONE; + state->host_EvC_COUNTER = 0; + state->host_EvC_FAILADDR = 0; /*------------------------------------------------------------*/ /*--- Initialise thunk ---*/ diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index ca23acb042..5befc74fad 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -120,6 +120,13 @@ mkexpr(IRTemp tmp) return IRExpr_RdTmp(tmp); } +/* Generate an expression node for an address. */ +static __inline__ IRExpr * +mkaddr_expr(Addr64 addr) +{ + return IRExpr_Const(IRConst_U64(addr)); +} + /* Add a statement that assigns to a temporary */ static __inline__ void assign(IRTemp dst, IRExpr *expr) @@ -127,6 +134,22 @@ assign(IRTemp dst, IRExpr *expr) stmt(IRStmt_WrTmp(dst, expr)); } +/* Write an address into the guest_IA */ +static __inline__ void +put_IA(IRExpr *address) +{ + stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_IA), address)); +} + +/* Add a dummy put to the guest_IA to satisfy an assert in bb_to_IR + that wants the last statement in an IRSB to be a put to the guest_IA. + Mostly used for insns that use the "counter" pseudo guest reg. */ +static __inline__ void +dummy_put_IA(void) +{ + put_IA(IRExpr_Get(S390X_GUEST_OFFSET(guest_IA), Ity_I64)); +} + /* Create a temporary of the given type and assign the expression to it */ static __inline__ IRTemp mktemp(IRType type, IRExpr *expr) @@ -242,10 +265,10 @@ load(IRType type, IRExpr *addr) static void call_function(IRExpr *callee_address) { - irsb->next = callee_address; - irsb->jumpkind = Ijk_Call; + put_IA(callee_address); - dis_res->whatNext = Dis_StopHere; + dis_res->whatNext = Dis_StopHere; + dis_res->jk_StopHere = Ijk_Call; } /* Function call with known target. */ @@ -256,9 +279,10 @@ call_function_and_chase(Addr64 callee_address) dis_res->whatNext = Dis_ResteerU; dis_res->continueAt = callee_address; } else { - irsb->next = mkU64(callee_address); - irsb->jumpkind = Ijk_Call; + put_IA(mkaddr_expr(callee_address)); + dis_res->whatNext = Dis_StopHere; + dis_res->jk_StopHere = Ijk_Call; } } @@ -266,10 +290,10 @@ call_function_and_chase(Addr64 callee_address) static void return_from_function(IRExpr *return_address) { - irsb->next = return_address; - irsb->jumpkind = Ijk_Ret; + put_IA(return_address); - dis_res->whatNext = Dis_StopHere; + dis_res->whatNext = Dis_StopHere; + dis_res->jk_StopHere = Ijk_Ret; } /* A conditional branch whose target is not known at instrumentation time. @@ -289,12 +313,13 @@ if_not_condition_goto_computed(IRExpr *condition, IRExpr *target) { vassert(typeOfIRExpr(irsb->tyenv, condition) == Ity_I1); - stmt(IRStmt_Exit3(condition, Ijk_Boring, IRConst_U64(guest_IA_next_instr))); + stmt(IRStmt_Exit(condition, Ijk_Boring, IRConst_U64(guest_IA_next_instr), + S390X_GUEST_OFFSET(guest_IA))); - irsb->next = target; - irsb->jumpkind = Ijk_Boring; + put_IA(target); - dis_res->whatNext = Dis_StopHere; + dis_res->whatNext = Dis_StopHere; + dis_res->jk_StopHere = Ijk_Boring; } /* A conditional branch whose target is known at instrumentation time. */ @@ -303,8 +328,13 @@ if_condition_goto(IRExpr *condition, Addr64 target) { vassert(typeOfIRExpr(irsb->tyenv, condition) == Ity_I1); - stmt(IRStmt_Exit3(condition, Ijk_Boring, IRConst_U64(target))); - dis_res->whatNext = Dis_Continue; + stmt(IRStmt_Exit(condition, Ijk_Boring, IRConst_U64(target), + S390X_GUEST_OFFSET(guest_IA))); + + put_IA(mkaddr_expr(target)); + + dis_res->whatNext = Dis_StopHere; + dis_res->jk_StopHere = Ijk_Boring; } /* An unconditional branch. Target may or may not be known at instrumentation @@ -312,23 +342,26 @@ if_condition_goto(IRExpr *condition, Addr64 target) static void always_goto(IRExpr *target) { - irsb->next = target; - irsb->jumpkind = Ijk_Boring; + put_IA(target); - dis_res->whatNext = Dis_StopHere; + dis_res->whatNext = Dis_StopHere; + dis_res->jk_StopHere = Ijk_Boring; } + /* An unconditional branch to a known target. */ static void always_goto_and_chase(Addr64 target) { if (resteer_fn(resteer_data, target)) { + /* Follow into the target */ dis_res->whatNext = Dis_ResteerU; dis_res->continueAt = target; } else { - irsb->next = mkU64(target); - irsb->jumpkind = Ijk_Boring; - dis_res->whatNext = Dis_StopHere; + put_IA(mkaddr_expr(target)); + + dis_res->whatNext = Dis_StopHere; + dis_res->jk_StopHere = Ijk_Boring; } } @@ -343,14 +376,13 @@ system_call(IRExpr *sysno) stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_IP_AT_SYSCALL), mkU64(guest_IA_curr_instr))); + put_IA(mkaddr_expr(guest_IA_next_instr)); + /* It's important that all ArchRegs carry their up-to-date value at this point. So we declare an end-of-block here, which forces any TempRegs caching ArchRegs to be flushed. */ - irsb->next = mkU64(guest_IA_next_instr); - - irsb->jumpkind = Ijk_Sys_syscall; - - dis_res->whatNext = Dis_StopHere; + dis_res->whatNext = Dis_StopHere; + dis_res->jk_StopHere = Ijk_Sys_syscall; } /* Encode the s390 rounding mode as it appears in the m3/m4 fields of certain @@ -8576,6 +8608,7 @@ s390_irgen_CLC(UChar length, IRTemp start1, IRTemp start2) if_condition_goto(binop(Iop_CmpNE64, mkexpr(counter), mkU64(length)), guest_IA_curr_instr); put_counter_dw0(mkU64(0)); + dummy_put_IA(); return "clc"; } @@ -8869,8 +8902,8 @@ void (*irgen)(IRTemp length, IRTemp start1, IRTemp start2), int lensize) stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_TISTART), mkU64(guest_IA_curr_instr))); stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_TILEN), mkU64(4))); - stmt(IRStmt_Exit3(mkexpr(cond), Ijk_TInval, - IRConst_U64(guest_IA_curr_instr))); + stmt(IRStmt_Exit(mkexpr(cond), Ijk_TInval, IRConst_U64(guest_IA_curr_instr), + S390X_GUEST_OFFSET(guest_IA))); ss.bytes = last_execute_target; assign(start1, binop(Iop_Add64, mkU64(ss.dec.d1), @@ -8880,6 +8913,8 @@ void (*irgen)(IRTemp length, IRTemp start1, IRTemp start2), int lensize) assign(len, unop(lensize == 64 ? Iop_8Uto64 : Iop_8Uto32, binop(Iop_Or8, r != 0 ? get_gpr_b7(r): mkU8(0), mkU8(ss.dec.l)))); irgen(len, start1, start2); + dummy_put_IA(); + last_execute_target = 0; } @@ -8900,8 +8935,9 @@ s390_irgen_EX(UChar r1, IRTemp addr2) stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_TISTART), mkU64(guest_IA_curr_instr))); stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_TILEN), mkU64(4))); - stmt(IRStmt_Exit3(IRExpr_Const(IRConst_U1(True)), Ijk_TInval, - IRConst_U64(guest_IA_curr_instr))); + stmt(IRStmt_Exit(IRExpr_Const(IRConst_U1(True)), Ijk_TInval, + IRConst_U64(guest_IA_curr_instr), + S390X_GUEST_OFFSET(guest_IA))); /* we know that this will be invalidated */ irsb->next = mkU64(guest_IA_next_instr); dis_res->whatNext = Dis_StopHere; @@ -8958,8 +8994,9 @@ s390_irgen_EX(UChar r1, IRTemp addr2) /* and restart */ stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_TISTART), mkU64(guest_IA_curr_instr))); stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_TILEN), mkU64(4))); - stmt(IRStmt_Exit3(mkexpr(cond), Ijk_TInval, - IRConst_U64(guest_IA_curr_instr))); + stmt(IRStmt_Exit(mkexpr(cond), Ijk_TInval, + IRConst_U64(guest_IA_curr_instr), + S390X_GUEST_OFFSET(guest_IA))); /* Now comes the actual translation */ bytes = (UChar *) &last_execute_target; @@ -9032,11 +9069,13 @@ s390_irgen_SRST(UChar r1, UChar r2) put_counter_dw0(binop(Iop_Add64, mkexpr(counter), mkU64(1))); put_gpr_dw0(r1, mkexpr(next)); put_gpr_dw0(r2, binop(Iop_Add64, mkexpr(address), mkU64(1))); - stmt(IRStmt_Exit3(binop(Iop_CmpNE64, mkexpr(counter), mkU64(255)), - Ijk_Boring, IRConst_U64(guest_IA_curr_instr))); + stmt(IRStmt_Exit(binop(Iop_CmpNE64, mkexpr(counter), mkU64(255)), + Ijk_Boring, IRConst_U64(guest_IA_curr_instr), + S390X_GUEST_OFFSET(guest_IA))); // >= 256 bytes done CC=3 s390_cc_set(3); put_counter_dw0(mkU64(0)); + dummy_put_IA(); return "srst"; } @@ -9098,11 +9137,13 @@ s390_irgen_CLST(UChar r1, UChar r2) put_counter_dw0(binop(Iop_Add64, mkexpr(counter), mkU64(1))); put_gpr_dw0(r1, binop(Iop_Add64, get_gpr_dw0(r1), mkU64(1))); put_gpr_dw0(r2, binop(Iop_Add64, get_gpr_dw0(r2), mkU64(1))); - stmt(IRStmt_Exit3(binop(Iop_CmpNE64, mkexpr(counter), mkU64(255)), - Ijk_Boring, IRConst_U64(guest_IA_curr_instr))); + stmt(IRStmt_Exit(binop(Iop_CmpNE64, mkexpr(counter), mkU64(255)), + Ijk_Boring, IRConst_U64(guest_IA_curr_instr), + S390X_GUEST_OFFSET(guest_IA))); // >= 256 bytes done CC=3 s390_cc_set(3); put_counter_dw0(mkU64(0)); + dummy_put_IA(); return "clst"; } @@ -9297,6 +9338,7 @@ s390_irgen_xonc(IROp op, UChar length, IRTemp start1, IRTemp start2) s390_cc_thunk_put1(S390_CC_OP_BITWISE, mktemp(Ity_I32, get_counter_w1()), False); put_counter_dw0(mkU64(0)); + dummy_put_IA(); } static HChar * @@ -9338,6 +9380,7 @@ s390_irgen_XC_sameloc(UChar length, UChar b, UShort d) /* Reset counter */ put_counter_dw0(mkU64(0)); + dummy_put_IA(); } s390_cc_thunk_put1(S390_CC_OP_BITWISE, mktemp(Ity_I32, mkU32(0)), False); @@ -9378,6 +9421,7 @@ s390_irgen_MVC(UChar length, IRTemp start1, IRTemp start2) if_condition_goto(binop(Iop_CmpNE64, mkexpr(counter), mkU64(length)), guest_IA_curr_instr); put_counter_dw0(mkU64(0)); + dummy_put_IA(); return "mvc"; } @@ -9558,6 +9602,7 @@ s390_irgen_MVST(UChar r1, UChar r2) s390_cc_set(1); put_gpr_dw0(r1, binop(Iop_Add64, mkexpr(addr1), mkexpr(counter))); put_counter_dw0(mkU64(0)); + dummy_put_IA(); return "mvst"; } @@ -9823,8 +9868,9 @@ s390_irgen_cas_32(UChar r1, UChar r3, IRTemp op2addr) Otherwise, store the old_value from memory in r1 and yield. */ assign(nequal, binop(Iop_CmpNE32, s390_call_calculate_cc(), mkU32(0))); put_gpr_w1(r1, mkite(mkexpr(nequal), mkexpr(old_mem), mkexpr(op1))); - stmt(IRStmt_Exit3(mkexpr(nequal), Ijk_Yield, - IRConst_U64(guest_IA_next_instr))); + stmt(IRStmt_Exit(mkexpr(nequal), Ijk_Yield, + IRConst_U64(guest_IA_next_instr), + S390X_GUEST_OFFSET(guest_IA))); } static HChar * @@ -9872,8 +9918,9 @@ s390_irgen_CSG(UChar r1, UChar r3, IRTemp op2addr) Otherwise, store the old_value from memory in r1 and yield. */ assign(nequal, binop(Iop_CmpNE32, s390_call_calculate_cc(), mkU32(0))); put_gpr_dw0(r1, mkite(mkexpr(nequal), mkexpr(old_mem), mkexpr(op1))); - stmt(IRStmt_Exit3(mkexpr(nequal), Ijk_Yield, - IRConst_U64(guest_IA_next_instr))); + stmt(IRStmt_Exit(mkexpr(nequal), Ijk_Yield, + IRConst_U64(guest_IA_next_instr), + S390X_GUEST_OFFSET(guest_IA))); return "csg"; } @@ -11059,6 +11106,7 @@ s390_irgen_TR(UChar length, IRTemp start1, IRTemp start2) guest_IA_curr_instr); put_counter_dw0(mkU64(0)); + dummy_put_IA(); return "tr"; } @@ -13518,14 +13566,6 @@ s390_decode_and_irgen(UChar *bytes, UInt insn_length, DisResult *dres) } -/* Generate an IRExpr for an address. */ -static __inline__ IRExpr * -mkaddr_expr(Addr64 addr) -{ - return IRExpr_Const(IRConst_U64(addr)); -} - - /* Disassemble a single instruction INSN into IR. */ static DisResult disInstr_S390_WRK(UChar *insn) @@ -13553,6 +13593,7 @@ disInstr_S390_WRK(UChar *insn) dres.whatNext = Dis_Continue; dres.len = insn_length; dres.continueAt = 0; + dres.jk_StopHere = Ijk_INVALID; /* fixs390: consider chasing of conditional jumps */ @@ -13561,17 +13602,28 @@ disInstr_S390_WRK(UChar *insn) /* All decode failures end up here. The decoder has already issued an error message. Tell the dispatcher that this insn cannot be decoded, and so has - not been executed, and (is currently) the next to be executed. - IA should be up-to-date since it made so at the start of each - insn, but nevertheless be paranoid and update it again right - now. */ - stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_IA), - mkaddr_expr(guest_IA_curr_instr))); - - irsb->next = mkaddr_expr(guest_IA_next_instr); - irsb->jumpkind = Ijk_NoDecode; - dres.whatNext = Dis_StopHere; - dres.len = 0; + not been executed, and (is currently) the next to be executed. */ + put_IA(mkaddr_expr(guest_IA_curr_instr)); + + dres.whatNext = Dis_StopHere; + dres.jk_StopHere = Ijk_NoDecode; + dres.continueAt = 0; + dres.len = 0; + } else { + /* Decode success */ + switch (dres.whatNext) { + case Dis_Continue: + put_IA(mkaddr_expr(guest_IA_curr_instr)); + break; + case Dis_ResteerU: + case Dis_ResteerC: + put_IA(mkaddr_expr(dres.continueAt)); + break; + case Dis_StopHere: + break; + default: + vassert(0); + } } return dres; @@ -13587,7 +13639,6 @@ disInstr_S390_WRK(UChar *insn) DisResult disInstr_S390(IRSB *irsb_IN, - Bool put_IP __attribute__((unused)), Bool (*resteerOkFn)(void *, Addr64), Bool resteerCisOk, void *callback_opaque, @@ -13610,10 +13661,6 @@ disInstr_S390(IRSB *irsb_IN, resteer_fn = resteerOkFn; resteer_data = callback_opaque; - /* Always update the guest IA. See comment in s390_isel_stmt for Ist_Put. */ - stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_IA), - mkaddr_expr(guest_IA_curr_instr))); - return disInstr_S390_WRK(guest_code + delta); } diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index 2de126d94a..0a3d98d38e 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -118,7 +118,7 @@ s390_hreg_get_allocable(Int *nregs, HReg **arr) /* Total number of allocable registers (all classes) */ *nregs = 16 /* GPRs */ - 1 /* r0 */ - - 1 /* r12 register holding VG_(dispatch_ctr) */ + - 1 /* r12 scratch register for translation chaining support */ - 1 /* r13 guest state pointer */ - 1 /* r14 link register */ - 1 /* r15 stack pointer */ @@ -144,12 +144,8 @@ s390_hreg_get_allocable(Int *nregs, HReg **arr) Otherwise, they are available to the allocator */ (*arr)[i++] = mkHReg(10, HRcInt64, False); (*arr)[i++] = mkHReg(11, HRcInt64, False); - /* GPR12 is not available because it caches VG_(dispatch_ctr). - Setting aside a register for the counter gives slightly better - performance - most of the time. From the 10 tests in "make perf" - 8 run faster with a max observed speedup of 2.6% for bz2. ffbench - is the counter example. It runs 1.3% faster without the dedicated - register. */ + /* GPR12 is not available because it us used as a scratch register + in translation chaining. */ /* GPR13 is not available because it is used as guest state pointer */ /* GPR14 is not available because it is used as link register */ /* GPR15 is not available because it is used as stack pointer */ @@ -183,6 +179,7 @@ s390_hreg_guest_state_pointer(void) return mkHReg(S390_REGNO_GUEST_STATE_POINTER, HRcInt64, False); } + /* Is VALUE within the domain of a 20-bit signed integer. */ static __inline__ Bool fits_signed_20bit(Int value) @@ -617,14 +614,6 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn) s390_opnd_RMI_get_reg_usage(u, insn->variant.compare.src2); break; - case S390_INSN_BRANCH: - s390_opnd_RMI_get_reg_usage(u, insn->variant.branch.dst); - /* The destination address is loaded into S390_REGNO_RETURN_VALUE. - See s390_insn_branch_emit. */ - addHRegUse(u, HRmWrite, - mkHReg(S390_REGNO_RETURN_VALUE, HRcInt64, False)); - break; - case S390_INSN_HELPER_CALL: { UInt i; @@ -718,6 +707,29 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn) case S390_INSN_GADD: break; + case S390_INSN_EVCHECK: + s390_amode_get_reg_usage(u, insn->variant.evcheck.counter); + s390_amode_get_reg_usage(u, insn->variant.evcheck.fail_addr); + break; + + case S390_INSN_PROFINC: + /* Does not use any register visible to the register allocator */ + break; + + case S390_INSN_XDIRECT: + s390_amode_get_reg_usage(u, insn->variant.xdirect.guest_IA); + break; + + case S390_INSN_XINDIR: + addHRegUse(u, HRmRead, insn->variant.xindir.dst); + s390_amode_get_reg_usage(u, insn->variant.xindir.guest_IA); + break; + + case S390_INSN_XASSISTED: + addHRegUse(u, HRmRead, insn->variant.xassisted.dst); + s390_amode_get_reg_usage(u, insn->variant.xassisted.guest_IA); + break; + default: vpanic("s390_insn_get_reg_usage"); } @@ -829,11 +841,6 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn) s390_opnd_RMI_map_regs(m, &insn->variant.compare.src2); break; - case S390_INSN_BRANCH: - s390_opnd_RMI_map_regs(m, &insn->variant.branch.dst); - /* No need to map S390_REGNO_RETURN_VALUE. It's not virtual */ - break; - case S390_INSN_HELPER_CALL: /* s390_insn_helper_call_emit also reads / writes the link register and stack pointer. But those registers are not visible to the @@ -923,6 +930,31 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn) case S390_INSN_GADD: break; + case S390_INSN_EVCHECK: + s390_amode_map_regs(m, insn->variant.evcheck.counter); + s390_amode_map_regs(m, insn->variant.evcheck.fail_addr); + break; + + case S390_INSN_PROFINC: + /* Does not use any register visible to the register allocator */ + break; + + case S390_INSN_XDIRECT: + s390_amode_map_regs(m, insn->variant.xdirect.guest_IA); + break; + + case S390_INSN_XINDIR: + s390_amode_map_regs(m, insn->variant.xindir.guest_IA); + insn->variant.xindir.dst = + lookupHRegRemap(m, insn->variant.xindir.dst); + break; + + case S390_INSN_XASSISTED: + s390_amode_map_regs(m, insn->variant.xassisted.guest_IA); + insn->variant.xassisted.dst = + lookupHRegRemap(m, insn->variant.xassisted.dst); + break; + default: vpanic("s390_insn_map_regs"); } @@ -1402,6 +1434,16 @@ s390_emit_BRC(UChar *p, UChar r1, UShort i2) } +static UChar * +s390_emit_BRCL(UChar *p, UChar r1, ULong i2) +{ + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) + s390_disasm(ENC2(XMNM, PCREL), S390_XMNM_BRCL, r1, i2); + + return emit_RIL(p, 0xc00400000000ULL, r1, i2); +} + + static UChar * s390_emit_CR(UChar *p, UChar r1, UChar r2) { @@ -4251,21 +4293,6 @@ s390_insn_compare(UChar size, HReg src1, s390_opnd_RMI src2, } -s390_insn * -s390_insn_branch(IRJumpKind kind, s390_cc_t cond, s390_opnd_RMI dst) -{ - s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); - - insn->tag = S390_INSN_BRANCH; - insn->size = 0; /* does not matter */ - insn->variant.branch.kind = kind; - insn->variant.branch.dst = dst; - insn->variant.branch.cond = cond; - - return insn; -} - - s390_insn * s390_insn_helper_call(s390_cc_t cond, Addr64 target, UInt num_args, HChar *name) @@ -4489,6 +4516,89 @@ s390_insn_gadd(UChar size, UInt offset, UChar delta, ULong value) } +s390_insn * +s390_insn_xdirect(s390_cc_t cond, Addr64 dst, s390_amode *guest_IA, + Bool to_fast_entry) +{ + s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + + insn->tag = S390_INSN_XDIRECT; + insn->size = 0; /* does not matter */ + + insn->variant.xdirect.cond = cond; + insn->variant.xdirect.dst = dst; + insn->variant.xdirect.guest_IA = guest_IA; + insn->variant.xdirect.to_fast_entry = to_fast_entry; + + return insn; +} + + +s390_insn * +s390_insn_xindir(s390_cc_t cond, HReg dst, s390_amode *guest_IA) +{ + s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + + insn->tag = S390_INSN_XASSISTED; + insn->size = 0; /* does not matter */ + + insn->variant.xdirect.cond = cond; + insn->variant.xdirect.dst = dst; + insn->variant.xdirect.guest_IA = guest_IA; + + return insn; +} + + +s390_insn * +s390_insn_xassisted(s390_cc_t cond, HReg dst, s390_amode *guest_IA, + IRJumpKind kind) +{ + s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + + insn->tag = S390_INSN_XASSISTED; + insn->size = 0; /* does not matter */ + + insn->variant.xassisted.cond = cond; + insn->variant.xassisted.dst = dst; + insn->variant.xassisted.guest_IA = guest_IA; + insn->variant.xassisted.kind = kind; + + return insn; +} + + +s390_insn * +s390_insn_evcheck(s390_amode *counter, s390_amode *fail_addr) +{ + s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + + vassert(counter->tag == S390_AMODE_B12 || counter->tag == S390_AMODE_BX12); + vassert(fail_addr->tag == S390_AMODE_B12 || + fail_addr->tag == S390_AMODE_BX12); + + insn->tag = S390_INSN_EVCHECK; + insn->size = 0; /* does not matter */ + + insn->variant.evcheck.counter = counter; + insn->variant.evcheck.fail_addr = fail_addr; + + return insn; +} + + +s390_insn * +s390_insn_profinc(void) +{ + s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + + insn->tag = S390_INSN_PROFINC; + insn->size = 0; /* does not matter */ + + return insn; +} + + /*---------------------------------------------------------------*/ /*--- Debug print ---*/ /*---------------------------------------------------------------*/ @@ -4519,6 +4629,31 @@ s390_cc_as_string(s390_cc_t cc) } +static const HChar * +s390_jump_kind_as_string(IRJumpKind kind) +{ + switch (kind) { + case Ijk_Boring: return "Boring"; + case Ijk_Call: return "Call"; + case Ijk_Ret: return "Return"; + case Ijk_ClientReq: return "ClientReq"; + case Ijk_Yield: return "Yield"; + case Ijk_EmWarn: return "EmWarn"; + case Ijk_EmFail: return "EmFail"; + case Ijk_NoDecode: return "NoDecode"; + case Ijk_MapFail: return "MapFail"; + case Ijk_TInval: return "Invalidate"; + case Ijk_NoRedir: return "NoRedir"; + case Ijk_SigTRAP: return "SigTRAP"; + case Ijk_SigSEGV: return "SigSEGV"; + case Ijk_SigBUS: return "SigBUS"; + case Ijk_Sys_syscall: return "Sys_syscall"; + default: + vpanic("s390_jump_kind_as_string"); + } +} + + /* Helper function for writing out a V insn */ static void s390_sprintf(HChar *buf, HChar *fmt, ...) @@ -4568,6 +4703,11 @@ s390_sprintf(HChar *buf, HChar *fmt, ...) p += vex_sprintf(p, "%s", s390_cc_as_string(va_arg(args, s390_cc_t))); continue; + case 'J': /* &J = jump kind */ + p += vex_sprintf(p, "%s", + s390_jump_kind_as_string(va_arg(args, IRJumpKind))); + continue; + case 'L': { /* %L = argument list in helper call*/ UInt i, num_args; @@ -4762,43 +4902,13 @@ s390_insn_as_string(const s390_insn *insn) &insn->variant.compare.src2); break; - case S390_INSN_BRANCH: - switch (insn->variant.branch.kind) { - case Ijk_ClientReq: op = "clientreq"; break; - case Ijk_Sys_syscall: op = "syscall"; break; - case Ijk_Yield: op = "yield"; break; - case Ijk_EmWarn: op = "emwarn"; break; - case Ijk_EmFail: op = "emfail"; break; - case Ijk_MapFail: op = "mapfail"; break; - case Ijk_NoDecode: op = "nodecode"; break; - case Ijk_TInval: op = "tinval"; break; - case Ijk_NoRedir: op = "noredir"; break; - case Ijk_SigTRAP: op = "sigtrap"; break; - case Ijk_Boring: op = "goto"; break; - case Ijk_Call: op = "call"; break; - case Ijk_Ret: op = "return"; break; - default: - goto fail; - } - s390_sprintf(buf, "if (%C) %s %O", insn->variant.branch.cond, op, - &insn->variant.branch.dst); - break; - case S390_INSN_HELPER_CALL: { - - if (insn->variant.helper_call.cond != S390_CC_ALWAYS) { - s390_sprintf(buf, "%M if (%C) %s{%I}(%L)", "v-call", - insn->variant.helper_call.cond, - insn->variant.helper_call.name, - insn->variant.helper_call.target, - insn->variant.helper_call.num_args); - } else { - s390_sprintf(buf, "%M %s{%I}(%L)", "v-call", - insn->variant.helper_call.name, - insn->variant.helper_call.target, - insn->variant.helper_call.num_args); - } - break; + s390_sprintf(buf, "%M if (%C) %s{%I}(%L)", "v-call", + insn->variant.helper_call.cond, + insn->variant.helper_call.name, + insn->variant.helper_call.target, + insn->variant.helper_call.num_args); + return buf; /* avoid printing "size = ..." which is meaningless */ } case S390_INSN_BFP_TRIOP: @@ -4919,6 +5029,39 @@ s390_insn_as_string(const s390_insn *insn) insn->variant.gadd.value); break; + case S390_INSN_EVCHECK: + s390_sprintf(buf, "%M counter = %A, fail-addr = %A", "v-evcheck", + insn->variant.evcheck.counter, + insn->variant.evcheck.fail_addr); + return buf; /* avoid printing "size = ..." which is meaningless */ + + case S390_INSN_PROFINC: + s390_sprintf(buf, "%M", "v-profinc"); + return buf; /* avoid printing "size = ..." which is meaningless */ + + case S390_INSN_XDIRECT: + s390_sprintf(buf, "%M if (%C) %A = %I %s", "v-xdirect", + insn->variant.xdirect.cond, + insn->variant.xdirect.guest_IA, + insn->variant.xdirect.dst, + insn->variant.xdirect.to_fast_entry ? "fast" : "slow"); + return buf; /* avoid printing "size = ..." which is meaningless */ + + case S390_INSN_XINDIR: + s390_sprintf(buf, "%M if (%C) %A = %R", "v-xindir", + insn->variant.xindir.cond, + insn->variant.xindir.guest_IA, + insn->variant.xindir.dst); + return buf; /* avoid printing "size = ..." which is meaningless */ + + case S390_INSN_XASSISTED: + s390_sprintf(buf, "%M if (%C) %J %A = %R", "v-xassisted", + insn->variant.xassisted.cond, + insn->variant.xassisted.kind, + insn->variant.xassisted.guest_IA, + insn->variant.xassisted.dst); + return buf; /* avoid printing "size = ..." which is meaningless */ + default: goto fail; } @@ -6506,104 +6649,6 @@ s390_insn_clz_emit(UChar *buf, const s390_insn *insn) } -static UChar * -s390_insn_branch_emit(UChar *buf, const s390_insn *insn) -{ - s390_opnd_RMI dst; - s390_cc_t cond; - UInt trc; - UChar *p, *ptmp = 0; /* avoid compiler warnings */ - - cond = insn->variant.branch.cond; - dst = insn->variant.branch.dst; - - p = buf; - trc = 0; - - if (cond != S390_CC_ALWAYS) { - /* So we have something like this - if (cond) goto X; - Y: ... - We convert this into - if (! cond) goto Y; // BRC insn; 4 bytes - return_reg = X; - return to dispatcher - Y: - */ - ptmp = p; /* 4 bytes (a BRC insn) to be filled in here */ - p += 4; - } - - /* If a non-boring, set guest-state-pointer appropriately. */ - - switch (insn->variant.branch.kind) { - case Ijk_ClientReq: trc = VEX_TRC_JMP_CLIENTREQ; break; - case Ijk_Sys_syscall: trc = VEX_TRC_JMP_SYS_SYSCALL; break; - case Ijk_Yield: trc = VEX_TRC_JMP_YIELD; break; - case Ijk_EmWarn: trc = VEX_TRC_JMP_EMWARN; break; - case Ijk_EmFail: trc = VEX_TRC_JMP_EMFAIL; break; - case Ijk_MapFail: trc = VEX_TRC_JMP_MAPFAIL; break; - case Ijk_NoDecode: trc = VEX_TRC_JMP_NODECODE; break; - case Ijk_TInval: trc = VEX_TRC_JMP_TINVAL; break; - case Ijk_NoRedir: trc = VEX_TRC_JMP_NOREDIR; break; - case Ijk_SigTRAP: trc = VEX_TRC_JMP_SIGTRAP; break; - case Ijk_Ret: trc = 0; break; - case Ijk_Call: trc = 0; break; - case Ijk_Boring: trc = 0; break; - break; - - default: - vpanic("s390_insn_branch_emit: unknown jump kind"); - } - - /* Get the destination address into the return register */ - switch (dst.tag) { - case S390_OPND_REG: - p = s390_emit_LGR(p, S390_REGNO_RETURN_VALUE, hregNumber(dst.variant.reg)); - break; - - case S390_OPND_AMODE: { - const s390_amode *am = dst.variant.am; - UChar b = hregNumber(am->b); - UChar x = hregNumber(am->x); - Int d = am->d; - - p = s390_emit_LG(p, S390_REGNO_RETURN_VALUE, x, b, DISP20(d)); - break; - } - - case S390_OPND_IMMEDIATE: - p = s390_emit_load_64imm(p, S390_REGNO_RETURN_VALUE, dst.variant.imm); - break; - - default: - goto fail; - } - - if (trc != 0) { - /* Something special. Set guest-state pointer appropriately */ - p = s390_emit_LGHI(p, S390_REGNO_GUEST_STATE_POINTER, trc); - } else { - /* Nothing special needs to be done for calls and returns. */ - } - - p = s390_emit_BCR(p, S390_CC_ALWAYS, S390_REGNO_LINK_REGISTER); - - if (cond != S390_CC_ALWAYS) { - Int delta = p - ptmp; - - delta >>= 1; /* immediate constant is #half-words */ - vassert(delta > 0 && delta < (1 << 16)); - s390_emit_BRC(ptmp, s390_cc_invert(cond), delta); - } - - return p; - - fail: - vpanic("s390_insn_branch_emit"); -} - - static UChar * s390_insn_helper_call_emit(UChar *buf, const s390_insn *insn) { @@ -7158,9 +7203,395 @@ s390_insn_gadd_emit(UChar *buf, const s390_insn *insn) } +/* Define convenience functions needed for translation chaining. + Any changes need to be applied to the functions in concert. */ + +/* Load the 64-bit VALUE into REG. Note that this function must NOT + optimise the generated code by looking at the value. I.e. using + LGHI if value == 0 would be very wrong. + fixs390: Do it in a way that works everywhere for now. */ +static UChar * +s390_tchain_load64(UChar *buf, UChar regno, ULong value) +{ + buf = s390_emit_IILL(buf, regno, value & 0xFFFF); + value >>= 16; + buf = s390_emit_IILH(buf, regno, value & 0xFFFF); + value >>= 16; + buf = s390_emit_IIHL(buf, regno, value & 0xFFFF); + value >>= 16; + buf = s390_emit_IIHH(buf, regno, value & 0xFFFF); + + return buf; +} + +/* Return number of bytes generated by s390_tchain_load64 */ +static UInt +s390_tchain_load64_len(void) +{ + vassert(S390_TCHAIN_LOAD64_LEN == 16); + return 16; +} + +/* Verify that CODE is the code sequence generated by s390_tchain_load64 + to load VALUE into REGNO. Return pointer to the byte following the + insn sequence. */ +static const UChar * +s390_tchain_verify_load64(const UChar *code, UChar regno, ULong value) +{ + UInt regmask = regno << 4; + UInt hw; + + /* Check for IILL */ + hw = value & 0xFFFF; + vassert(code[0] == 0xA5); + vassert(code[1] == (0x03 | regmask)); + vassert(code[2] == (hw >> 8)); + vassert(code[3] == (hw & 0xFF)); + + /* Check for IILH */ + hw = (value >> 16) & 0xFFFF; + vassert(code[4] == 0xA5); + vassert(code[5] == (0x02 | regmask)); + vassert(code[6] == (hw >> 8)); + vassert(code[7] == (hw & 0xFF)); + + /* Check for IIHL */ + hw = (value >> 32) & 0xFFFF; + vassert(code[8] == 0xA5); + vassert(code[9] == (0x01 | regmask)); + vassert(code[10] == (hw >> 8)); + vassert(code[11] == (hw & 0xFF)); + + /* Check for IIHH */ + hw = (value >> 48) & 0xFFFF; + vassert(code[12] == 0xA5); + vassert(code[13] == (0x00 | regmask)); + vassert(code[14] == (hw >> 8)); + vassert(code[15] == (hw & 0xFF)); + + return code + 16; +} + +/* CODE points to the code sequence as generated by s390_tchain_load64. + Change the loaded value to VALUE. Return pointer to the byte following + the patched code sequence. */ +static UChar * +s390_tchain_patch_load64(UChar *code, ULong imm64) +{ + code[2] = imm64 & 0xFF; imm64 >>= 8; + code[3] = imm64 & 0xFF; imm64 >>= 8; + code[6] = imm64 & 0xFF; imm64 >>= 8; + code[7] = imm64 & 0xFF; imm64 >>= 8; + code[10] = imm64 & 0xFF; imm64 >>= 8; + code[11] = imm64 & 0xFF; imm64 >>= 8; + code[14] = imm64 & 0xFF; imm64 >>= 8; + code[15] = imm64 & 0xFF; imm64 >>= 8; + + return code + 16; +} + + +/* NB: what goes on here has to be very closely coordinated with the + chainXDirect_S390 and unchainXDirect_S390 below. */ +static UChar * +s390_insn_xdirect_emit(UChar *buf, const s390_insn *insn, + void *disp_cp_chain_me_to_slowEP, + void *disp_cp_chain_me_to_fastEP) +{ + /* We're generating chain-me requests here, so we need to be + sure this is actually allowed -- no-redir translations can't + use chain-me's. Hence: */ + vassert(disp_cp_chain_me_to_slowEP != NULL); + vassert(disp_cp_chain_me_to_fastEP != NULL); + + /* Use ptmp for backpatching conditional jumps. */ + UChar *ptmp = buf; + + /* First off, if this is conditional, create a conditional + jump over the rest of it. */ + s390_cc_t cond = insn->variant.xdirect.cond; + + if (cond != S390_CC_ALWAYS) { + /* So we have something like this + if (cond) do_xdirect; + Y: ... + We convert this into + if (! cond) goto Y; // BRC opcode; 4 bytes + do_xdirect; + Y: + */ + /* 4 bytes (a BRC insn) to be filled in here */ + buf += 4; + } + + /* Update the guest IA. */ + buf = s390_emit_load_64imm(buf, R0, insn->variant.xdirect.dst); + + const s390_amode *amode = insn->variant.xdirect.guest_IA; + vassert(amode->tag == S390_AMODE_B12 || amode->tag == S390_AMODE_BX12); + UInt b = hregNumber(amode->b); + UInt x = hregNumber(amode->x); /* 0 for B12 and B20 */ + UInt d = amode->d; + + buf = s390_emit_STG(buf, R0, x, b, DISP20(d)); + + /* --- FIRST PATCHABLE BYTE follows --- */ + /* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're calling + to) backs up the return address, so as to find the address of + the first patchable byte. So: don't change the length of the + two instructions below. */ + + /* Load the chosen entry point into the scratch reg */ + void *disp_cp_chain_me; + + disp_cp_chain_me = + insn->variant.xdirect.to_fast_entry ? disp_cp_chain_me_to_fastEP + : disp_cp_chain_me_to_slowEP; + + ULong addr = Ptr_to_ULong(disp_cp_chain_me); + buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH, addr); + + /* call *tchain_scratch */ + buf = s390_emit_BASR(buf, 1, S390_REGNO_TCHAIN_SCRATCH); + + /* --- END of PATCHABLE BYTES --- */ + + /* Fix up the conditional jump, if there was one. */ + if (cond != S390_CC_ALWAYS) { + Int delta = buf - ptmp; + + delta >>= 1; /* immediate constant is #half-words */ + vassert(delta > 0 && delta < (1 << 16)); + s390_emit_BRC(ptmp, s390_cc_invert(cond), delta); + } + + return buf; +} + +/* Return the number of patchable bytes from an xdirect insn. */ +static UInt +s390_xdirect_patchable_len(void) +{ + return s390_tchain_load64_len() + 2; /* 2 == BASR */ +} + + +static UChar * +s390_insn_xindir_emit(UChar *buf, const s390_insn *insn, void *disp_cp_xindir) +{ + /* We're generating transfers that could lead indirectly to a + chain-me, so we need to be sure this is actually allowed -- + no-redir translations are not allowed to reach normal + translations without going through the scheduler. That means + no XDirects or XIndirs out from no-redir translations. + Hence: */ + vassert(disp_cp_xindir != NULL); + + /* Use ptmp for backpatching conditional jumps. */ + UChar *ptmp = buf; + + /* First off, if this is conditional, create a conditional + jump over the rest of it. */ + s390_cc_t cond = insn->variant.xdirect.cond; + + if (cond != S390_CC_ALWAYS) { + /* So we have something like this + if (cond) do_xdirect; + Y: ... + We convert this into + if (! cond) goto Y; // BRC opcode; 4 bytes + do_xdirect; + Y: + */ + /* 4 bytes (a BRC insn) to be filled in here */ + buf += 4; + } + + /* Update the guest IA with the address in xdirect.dst. */ + const s390_amode *amode = insn->variant.xdirect.guest_IA; + + vassert(amode->tag == S390_AMODE_B12 || amode->tag == S390_AMODE_BX12); + UInt b = hregNumber(amode->b); + UInt x = hregNumber(amode->x); /* 0 for B12 and B20 */ + UInt d = amode->d; + UInt regno = hregNumber(insn->variant.xdirect.dst); + + buf = s390_emit_STG(buf, regno, x, b, DISP20(d)); + + /* load tchain_scratch, #disp_indir */ + buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH, + Ptr_to_ULong(disp_cp_xindir)); + /* BR *tchain_direct */ + buf = s390_emit_BCR(buf, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH); + + /* Fix up the conditional jump, if there was one. */ + if (cond != S390_CC_ALWAYS) { + Int delta = buf - ptmp; + + delta >>= 1; /* immediate constant is #half-words */ + vassert(delta > 0 && delta < (1 << 16)); + s390_emit_BRC(ptmp, s390_cc_invert(cond), delta); + } + + return buf; +} + +static UChar * +s390_insn_xassisted_emit(UChar *buf, const s390_insn *insn, + void *disp_cp_xassisted) +{ + /* Use ptmp for backpatching conditional jumps. */ + UChar *ptmp = buf; + + /* First off, if this is conditional, create a conditional + jump over the rest of it. */ + s390_cc_t cond = insn->variant.xdirect.cond; + + if (cond != S390_CC_ALWAYS) { + /* So we have something like this + if (cond) do_xdirect; + Y: ... + We convert this into + if (! cond) goto Y; // BRC opcode; 4 bytes + do_xdirect; + Y: + */ + /* 4 bytes (a BRC insn) to be filled in here */ + buf += 4; + } + + /* Update the guest IA with the address in xassisted.dst. */ + const s390_amode *amode = insn->variant.xassisted.guest_IA; + + vassert(amode->tag == S390_AMODE_B12 || amode->tag == S390_AMODE_BX12); + UInt b = hregNumber(amode->b); + UInt x = hregNumber(amode->x); /* 0 for B12 and B20 */ + UInt d = amode->d; + UInt regno = hregNumber(insn->variant.xassisted.dst); + + buf = s390_emit_STG(buf, regno, x, b, DISP20(d)); + + UInt trcval = 0; + + switch (insn->variant.xassisted.kind) { + case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break; + case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break; + case Ijk_Sys_int32: trcval = VEX_TRC_JMP_SYS_INT32; break; + case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break; + case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break; + case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break; + case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break; + case Ijk_TInval: trcval = VEX_TRC_JMP_TINVAL; break; + case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break; + case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break; + case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break; + case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break; + /* We don't expect to see the following being assisted. */ + case Ijk_Ret: + case Ijk_Call: + /* fallthrough */ + default: + ppIRJumpKind(insn->variant.xassisted.kind); + vpanic("s390_insn_xassisted_emit: unexpected jump kind"); + } + + vassert(trcval != 0); + + /* guest_state_pointer = trcval */ + buf = s390_emit_LGHI(buf, S390_REGNO_GUEST_STATE_POINTER, trcval); + + /* load tchain_scratch, #disp_assisted */ + buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH, + Ptr_to_ULong(disp_cp_xassisted)); + + /* BR *tchain_direct */ + buf = s390_emit_BCR(buf, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH); + + /* Fix up the conditional jump, if there was one. */ + if (cond != S390_CC_ALWAYS) { + Int delta = buf - ptmp; + + delta >>= 1; /* immediate constant is #half-words */ + vassert(delta > 0 && delta < (1 << 16)); + s390_emit_BRC(ptmp, s390_cc_invert(cond), delta); + } + + return buf; +} + + +/* Pseudo code: + + guest_state[host_EvC_COUNTER] -= 1; + if (guest_state[host_EvC_COUNTER] >= 0) goto nofail; + goto guest_state[host_EvC_FAILADDR]; + nofail: ; + + The dispatch counter is a 32-bit value. */ +static UChar * +s390_insn_evcheck_emit(UChar *buf, const s390_insn *insn) +{ + s390_amode *amode; + UInt b, x, d; + UChar *code_begin, *code_end; + + code_begin = buf; + + amode = insn->variant.evcheck.counter; + vassert(amode->tag == S390_AMODE_B12 || amode->tag == S390_AMODE_BX12); + b = hregNumber(amode->b); + x = hregNumber(amode->x); /* 0 for B12 and B20 */ + d = amode->d; + + /* Decrement the dispatch counter in the guest state */ + /* fixs390: ASI if available */ + buf = s390_emit_LHI(buf, R0, -1); /* 4 bytes */ + buf = s390_emit_A(buf, R0, x, b, d); /* 4 bytes */ + buf = s390_emit_ST(buf, R0, x, b, d); /* 4 bytes */ + + /* Jump over the next insn if >= 0 */ + buf = s390_emit_BRC(buf, S390_CC_HE, (4 + 6 + 2) / 2); /* 4 bytes */ + + /* Computed goto to fail_address */ + amode = insn->variant.evcheck.fail_addr; + b = hregNumber(amode->b); + x = hregNumber(amode->x); /* 0 for B12 and B20 */ + d = amode->d; + buf = s390_emit_LG(buf, S390_REGNO_TCHAIN_SCRATCH, x, b, DISP20(d)); /* 6 bytes */ + buf = s390_emit_BCR(buf, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH); /* 2 bytes */ + + code_end = buf; + + /* Make sure the size of the generated code is identical to the size + returned by evCheckSzB_S390 */ + vassert(evCheckSzB_S390() == code_end - code_begin); + + return buf; +} + + +static UChar * +s390_insn_profinc_emit(UChar *buf, + const s390_insn *insn __attribute__((unused))) +{ + /* Generate a code template to increment a memory location whose + address will be known later as an immediate value. This code + template will be patched once the memory location is known. + For now we do this with address == 0. */ + buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH, 0); + buf = s390_emit_LGHI(buf, R0, 1); + buf = s390_emit_AG( buf, R0, 0, S390_REGNO_TCHAIN_SCRATCH, DISP20(0)); + buf = s390_emit_STG(buf, R0, 0, S390_REGNO_TCHAIN_SCRATCH, DISP20(0)); + + return buf; +} + + Int -emit_S390Instr(UChar *buf, Int nbuf, s390_insn *insn, Bool mode64, - void *dispatch_unassisted, void *dispatch_assisted) +emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, s390_insn *insn, + Bool mode64, void *disp_cp_chain_me_to_slowEP, + void *disp_cp_chain_me_to_fastEP, void *disp_cp_xindir, + void *disp_cp_xassisted) { UChar *end; @@ -7225,12 +7656,6 @@ emit_S390Instr(UChar *buf, Int nbuf, s390_insn *insn, Bool mode64, end = s390_insn_compare_emit(buf, insn); break; - case S390_INSN_BRANCH: - vassert(dispatch_unassisted == NULL); - vassert(dispatch_assisted == NULL); - end = s390_insn_branch_emit(buf, insn); - break; - case S390_INSN_HELPER_CALL: end = s390_insn_helper_call_emit(buf, insn); break; @@ -7283,6 +7708,30 @@ emit_S390Instr(UChar *buf, Int nbuf, s390_insn *insn, Bool mode64, end = s390_insn_gadd_emit(buf, insn); break; + case S390_INSN_PROFINC: + end = s390_insn_profinc_emit(buf, insn); + /* Tell the caller .. */ + vassert(*is_profinc == False); + *is_profinc = True; + break; + + case S390_INSN_EVCHECK: + end = s390_insn_evcheck_emit(buf, insn); + break; + + case S390_INSN_XDIRECT: + end = s390_insn_xdirect_emit(buf, insn, disp_cp_chain_me_to_slowEP, + disp_cp_chain_me_to_fastEP); + break; + + case S390_INSN_XINDIR: + end = s390_insn_xindir_emit(buf, insn, disp_cp_xindir); + break; + + case S390_INSN_XASSISTED: + end = s390_insn_xassisted_emit(buf, insn, disp_cp_xassisted); + break; + default: vpanic("emit_S390Instr"); } @@ -7293,6 +7742,166 @@ emit_S390Instr(UChar *buf, Int nbuf, s390_insn *insn, Bool mode64, } +/* Return the number of bytes emitted for an S390_INSN_EVCHECK. + See s390_insn_evcheck_emit */ +Int +evCheckSzB_S390(void) +{ + return 24; +} + + +/* Patch the counter address into CODE_TO_PATCH as previously + generated by s390_insn_profinc_emit. */ +VexInvalRange +patchProfInc_S390(void *code_to_patch, ULong *location_of_counter) +{ + vassert(sizeof(ULong *) == 8); + + s390_tchain_verify_load64(code_to_patch, S390_REGNO_TCHAIN_SCRATCH, 0); + + s390_tchain_patch_load64(code_to_patch, Ptr_to_ULong(location_of_counter)); + + VexInvalRange vir = {0, 0}; + return vir; +} + + +/* NB: what goes on here has to be very closely coordinated with the + s390_insn_xdirect_emit code above. */ +VexInvalRange +chainXDirect_S390(void *place_to_chain, + void *disp_cp_chain_me_EXPECTED, + void *place_to_jump_to) +{ + /* What we're expecting to see @ PLACE_TI_CHAIN is: + + load disp_cp_chain_me_EXPECTED into S390_REGNO_TCHAIN_SCRATCH + BASR 1,S390_REGNO_TCHAIN_SCRATCH + */ + const UChar *next; + next = s390_tchain_verify_load64(place_to_chain, S390_REGNO_TCHAIN_SCRATCH, + Ptr_to_ULong(disp_cp_chain_me_EXPECTED)); + vassert(next[0] == 0x0D); // BASR 1,tchain_scratch + vassert(next[1] == (0x10 | S390_REGNO_TCHAIN_SCRATCH)); + + /* And what we want to change it to is either: + (general case): + + load tchain_scratch, #place_to_jump_to + BR *tchain_scratch + + ---OR--- + + in the case where the displacement is small enough + + BRCL delta where delta is in half-words + invalid opcodes + + In both cases the replacement has the same length as the original. + To remain sane & verifiable, + (1) limit the displacement for the short form to + (say) +/- one billion, so as to avoid wraparound + off-by-ones + (2) even if the short form is applicable, once every (say) + 1024 times use the long form anyway, so as to maintain + verifiability + */ + + /* This is the delta we need to put into a BRCL insn. Note, that the + offset in BRCL is in half-words. Hence division by 2. */ + Long delta = (Long)((UChar *)place_to_jump_to - (UChar *)place_to_chain) / 2; + Bool shortOK = delta >= -1000*1000*1000 && delta < 1000*1000*1000; + + static UInt shortCTR = 0; /* DO NOT MAKE NON-STATIC */ + if (shortOK) { + shortCTR++; // thread safety bleh + if (0 == (shortCTR & 0x3FF)) { + shortOK = False; + if (0) + vex_printf("QQQ chainXDirect_S390: shortCTR = %u, " + "using long jmp\n", shortCTR); + } + } + + /* And make the modifications. */ + UChar *p = (UChar *)place_to_chain; + if (shortOK) { + p = s390_emit_BRCL(p, S390_CC_ALWAYS, delta); /* 6 bytes */ + + /* Fill remaining bytes with 0x00 (invalid opcode) */ + Int i; + for (i = 0; i < s390_xdirect_patchable_len() - 6; ++i) + p[i] = 0x00; + } else { + /* Minimal modifications from the starting sequence. */ + p = s390_tchain_patch_load64(p, Ptr_to_ULong(place_to_jump_to)); + /* Turn the call into a branch: BR *tchain_scratch */ + s390_emit_BCR(p, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH); + } + + VexInvalRange vir = {0, 0}; + return vir; +} + + +/* NB: what goes on here has to be very closely coordinated with the + s390_insn_xdirect_emit code above. */ +VexInvalRange +unchainXDirect_S390(void *place_to_unchain, + void *place_to_jump_to_EXPECTED, + void *disp_cp_chain_me) +{ + /* What we're expecting to see @ PLACE_TO_UNCHAIN: + + load tchain_scratch, #place_to_jump_to_EXPECTED + BR *tchain_scratch + + ---OR--- + in the case where the displacement falls within 32 bits + + BRCL delta + invalid opcodes + */ + UChar *p = place_to_unchain; + + if (p[0] == 0xc0 && p[1] == (0x04 | S390_REGNO_TCHAIN_SCRATCH)) { + /* Looks like the short form */ + Int num_hw = *(Int *)&p[2]; + Int delta = 2 *num_hw; + + vassert(p + delta == place_to_jump_to_EXPECTED); + + p += 6; + Int i; + for (i = 0; i < s390_xdirect_patchable_len() - 6; ++i) + vassert(p[i] == 0x00); + } else { + /* Should be the long form */ + const UChar *next; + + next = s390_tchain_verify_load64(p, S390_REGNO_TCHAIN_SCRATCH, + Ptr_to_ULong(place_to_jump_to_EXPECTED)); + /* Check for BR *tchain_scratch */ + vassert(next[0] == 0x07 && /* BCR */ + (next[1] == (0xF0 | S390_REGNO_TCHAIN_SCRATCH))); + } + + /* And what we want to change it to is: + + load tchain_scratch, #disp_cp_chain_me + call *tchain_scratch + */ + ULong addr = Ptr_to_ULong(disp_cp_chain_me); + p = s390_tchain_load64(p, S390_REGNO_TCHAIN_SCRATCH, addr); + + /* call *tchain_scratch */ + s390_emit_BASR(p, 1, S390_REGNO_TCHAIN_SCRATCH); + + VexInvalRange vir = {0, 0}; + return vir; +} + /*---------------------------------------------------------------*/ /*--- end host_s390_defs.c ---*/ /*---------------------------------------------------------------*/ diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index 8b7548652c..ad99c4ffcf 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -130,7 +130,6 @@ typedef enum { S390_INSN_TEST, /* test operand and set cc */ S390_INSN_CC2BOOL,/* convert condition code to 0/1 */ S390_INSN_COMPARE, - S390_INSN_BRANCH, /* un/conditional goto */ S390_INSN_HELPER_CALL, S390_INSN_CAS, /* compare and swap */ S390_INSN_BFP_BINOP, /* Binary floating point 32-bit / 64-bit */ @@ -144,7 +143,13 @@ typedef enum { S390_INSN_BFP128_CONVERT_FROM, S390_INSN_MFENCE, S390_INSN_GZERO, /* Assign zero to a guest register */ - S390_INSN_GADD /* Add a value to a guest register */ + S390_INSN_GADD, /* Add a value to a guest register */ + /* The following 5 insns are mandated by translation chaining */ + S390_INSN_XDIRECT, /* direct transfer to guest address */ + S390_INSN_XINDIR, /* indirect transfer to guest address */ + S390_INSN_XASSISTED, /* assisted transfer to guest address */ + S390_INSN_EVCHECK, /* Event check */ + S390_INSN_PROFINC /* 64-bit profile counter increment */ } s390_insn_tag; @@ -338,11 +343,6 @@ typedef struct { HReg op3; HReg old_mem; } cas; - struct { - IRJumpKind kind; - s390_cc_t cond; - s390_opnd_RMI dst; - } branch; /* Pseudo-insn for representing a helper call. TARGET is the absolute address of the helper function NUM_ARGS says how many arguments are being passed. @@ -407,6 +407,44 @@ typedef struct { UChar delta; ULong value; /* for debugging only */ } gadd; + + /* The next 5 entries are generic to support translation chaining */ + + /* Update the guest IA value, then exit requesting to chain + to it. May be conditional. */ + struct { + s390_cc_t cond; + Bool to_fast_entry; /* chain to the what entry point? */ + Addr64 dst; /* next guest address */ + s390_amode *guest_IA; + } xdirect; + /* Boring transfer to a guest address not known at JIT time. + Not chainable. May be conditional. */ + struct { + s390_cc_t cond; + HReg dst; + s390_amode *guest_IA; + } xindir; + /* Assisted transfer to a guest address, most general case. + Not chainable. May be conditional. */ + struct { + s390_cc_t cond; + IRJumpKind kind; + HReg dst; + s390_amode *guest_IA; + } xassisted; + struct { + /* fixs390: I don't think these are really needed + as the gsp and the offset are fixed no ? */ + s390_amode *counter; /* dispatch counter */ + s390_amode *fail_addr; + } evcheck; + struct { + /* No fields. The address of the counter to increment is + installed later, post-translation, by patching it in, + as it is not known at translation time. */ + } profinc; + } variant; } s390_insn; @@ -433,7 +471,6 @@ s390_insn *s390_insn_cc2bool(HReg dst, s390_cc_t src); s390_insn *s390_insn_test(UChar size, s390_opnd_RMI src); s390_insn *s390_insn_compare(UChar size, HReg dst, s390_opnd_RMI opnd, Bool signed_comparison); -s390_insn *s390_insn_branch(IRJumpKind jk, s390_cc_t cond, s390_opnd_RMI dst); s390_insn *s390_insn_helper_call(s390_cc_t cond, Addr64 target, UInt num_args, HChar *name); s390_insn *s390_insn_bfp_triop(UChar size, s390_bfp_triop_t, HReg dst, HReg op2, @@ -460,6 +497,15 @@ s390_insn *s390_insn_mfence(void); s390_insn *s390_insn_gzero(UChar size, UInt offset); s390_insn *s390_insn_gadd(UChar size, UInt offset, UChar delta, ULong value); +/* Five for translation chaining */ +s390_insn *s390_insn_xdirect(s390_cc_t cond, Addr64 dst, s390_amode *guest_IA, + Bool to_fast_entry); +s390_insn *s390_insn_xindir(s390_cc_t cond, HReg dst, s390_amode *guest_IA); +s390_insn *s390_insn_xassisted(s390_cc_t cond, HReg dst, s390_amode *guest_IA, + IRJumpKind kind); +s390_insn *s390_insn_evcheck(s390_amode *counter, s390_amode *fail_addr); +s390_insn *s390_insn_profinc(void); + const HChar *s390_insn_as_string(const s390_insn *); /*--------------------------------------------------------*/ @@ -475,13 +521,30 @@ void ppHRegS390(HReg); void getRegUsage_S390Instr( HRegUsage *, s390_insn *, Bool ); void mapRegs_S390Instr ( HRegRemap *, s390_insn *, Bool ); Bool isMove_S390Instr ( s390_insn *, HReg *, HReg * ); -Int emit_S390Instr ( UChar *, Int, s390_insn *, Bool, - void *, void * ); +Int emit_S390Instr ( Bool *, UChar *, Int, s390_insn *, Bool, + void *, void *, void *, void *); void getAllocableRegs_S390( Int *, HReg **, Bool ); void genSpill_S390 ( HInstr **, HInstr **, HReg , Int , Bool ); void genReload_S390 ( HInstr **, HInstr **, HReg , Int , Bool ); s390_insn *directReload_S390 ( s390_insn *, HReg, Short ); -HInstrArray *iselSB_S390 ( IRSB *, VexArch, VexArchInfo *, VexAbiInfo * ); +HInstrArray *iselSB_S390 ( IRSB *, VexArch, VexArchInfo *, VexAbiInfo *, + Int, Int, Bool, Bool, Addr64); + +/* Return the number of bytes of code needed for an event check */ +Int evCheckSzB_S390(void); + +/* Perform a chaining and unchaining of an XDirect jump. */ +VexInvalRange chainXDirect_S390(void *place_to_chain, + void *disp_cp_chain_me_EXPECTED, + void *place_to_jump_to); + +VexInvalRange unchainXDirect_S390(void *place_to_unchain, + void *place_to_jump_to_EXPECTED, + void *disp_cp_chain_me); + +/* Patch the counter location into an existing ProfInc point. */ +VexInvalRange patchProfInc_S390(void *code_to_patch, + ULong *location_of_counter); /* KLUDGE: See detailled comment in host_s390_defs.c. */ extern const VexArchInfo *s390_archinfo_host; diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index a2217d4b8a..6c63cb3cf2 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -69,6 +69,18 @@ - The host subarchitecture we are selecting insns for. This is set at the start and does not change. + - A Bool for indicating whether we may generate chain-me + instructions for control flow transfers, or whether we must use + XAssisted. + + - The maximum guest address of any guest insn in this block. + Actually, the address of the highest-addressed byte from any insn + in this block. Is set at the start and does not change. This is + used for detecting jumps which are definitely forward-edges from + this block, and therefore can be made (chained) to the fast entry + point of the destination, thereby avoiding the destination's + event check. + - A flag to indicate whether the guest IA has been assigned to. - Values of certain guest registers which are often assigned constants. @@ -92,16 +104,19 @@ enum { typedef struct { IRTypeEnv *type_env; + HInstrArray *code; HReg *vregmap; HReg *vregmapHI; UInt n_vregmap; - - HInstrArray *code; + UInt vreg_ctr; + UInt hwcaps; ULong old_value[NUM_TRACKED_REGS]; - UInt vreg_ctr; - UInt hwcaps; + /* The next two are for translation chaining */ + Addr64 max_ga; + Bool chaining_allowed; + Bool first_IA_assignment; Bool old_value_valid[NUM_TRACKED_REGS]; } ISelEnv; @@ -2437,17 +2452,53 @@ s390_isel_stmt(ISelEnv *env, IRStmt *stmt) /* --------- EXIT --------- */ case Ist_Exit: { - s390_opnd_RMI dst; s390_cc_t cond; IRConstTag tag = stmt->Ist.Exit.dst->tag; if (tag != Ico_U64) vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value"); - dst = s390_isel_int_expr_RMI(env, IRExpr_Const(stmt->Ist.Exit.dst)); + s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP); cond = s390_isel_cc(env, stmt->Ist.Exit.guard); - addInstr(env, s390_insn_branch(stmt->Ist.Exit.jk, cond, dst)); - return; + + /* Case: boring transfer to known address */ + if (stmt->Ist.Exit.jk == Ijk_Boring) { + if (env->chaining_allowed) { + /* .. almost always true .. */ + /* Skip the event check at the dst if this is a forwards + edge. */ + Bool to_fast_entry + = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga; + if (0) vex_printf("%s", to_fast_entry ? "Y" : ","); + addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64, + guest_IA, to_fast_entry)); + } else { + /* .. very occasionally .. */ + /* We can't use chaining, so ask for an assisted transfer, + as that's the only alternative that is allowable. */ + HReg dst = s390_isel_int_expr(env, + IRExpr_Const(stmt->Ist.Exit.dst)); + addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring)); + } + return; + } + + /* Case: assisted transfer to arbitrary address */ + switch (stmt->Ist.Exit.jk) { + case Ijk_SigSEGV: + case Ijk_TInval: + case Ijk_EmWarn: { + HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst)); + addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, + stmt->Ist.Exit.jk)); + return; + } + default: + break; + } + + /* Do we ever expect to see any other kind? */ + goto stmt_fail; } /* --------- MEM FENCE --------- */ @@ -2484,20 +2535,79 @@ s390_isel_stmt(ISelEnv *env, IRStmt *stmt) /*---------------------------------------------------------*/ static void -iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk) +iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP) { - s390_opnd_RMI dst; - if (vex_traceflags & VEX_TRACE_VCODE) { - vex_printf("\n-- goto {"); - ppIRJumpKind(jk); - vex_printf("} "); + vex_printf("\n-- PUT(%d) = ", offsIP); ppIRExpr(next); + vex_printf("; exit-"); + ppIRJumpKind(jk); vex_printf("\n"); } - dst = s390_isel_int_expr_RMI(env, next); - addInstr(env, s390_insn_branch(jk, S390_CC_ALWAYS, dst)); + s390_amode *guest_IA = s390_amode_for_guest_state(offsIP); + + /* Case: boring transfer to known address */ + if (next->tag == Iex_Const) { + IRConst *cdst = next->Iex.Const.con; + vassert(cdst->tag == Ico_U64); + if (jk == Ijk_Boring || jk == Ijk_Call) { + /* Boring transfer to known address */ + if (env->chaining_allowed) { + /* .. almost always true .. */ + /* Skip the event check at the dst if this is a forwards + edge. */ + Bool to_fast_entry + = ((Addr64)cdst->Ico.U64) > env->max_ga; + if (0) vex_printf("%s", to_fast_entry ? "X" : "."); + addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64, + guest_IA, to_fast_entry)); + } else { + /* .. very occasionally .. */ + /* We can't use chaining, so ask for an indirect transfer, + as that's the cheapest alternative that is allowable. */ + HReg dst = s390_isel_int_expr(env, next); + addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, + Ijk_Boring)); + } + return; + } + } + + /* Case: call/return (==boring) transfer to any address */ + switch (jk) { + case Ijk_Boring: + case Ijk_Ret: + case Ijk_Call: { + HReg dst = s390_isel_int_expr(env, next); + if (env->chaining_allowed) { + addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA)); + } else { + addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, + Ijk_Boring)); + } + return; + } + default: + break; + } + + /* Case: some other kind of transfer to any address */ + switch (jk) { + case Ijk_Sys_syscall: + case Ijk_ClientReq: + case Ijk_NoRedir: + case Ijk_Yield: + case Ijk_SigTRAP: { + HReg dst = s390_isel_int_expr(env, next); + addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk)); + return; + } + default: + break; + } + + vpanic("iselNext"); } @@ -2509,7 +2619,9 @@ iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk) HInstrArray * iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host, - VexAbiInfo *vbi) + VexAbiInfo *vbi, Int offset_host_evcheck_counter, + Int offset_host_evcheck_fail_addr, Bool chaining_allowed, + Bool add_profinc, Addr64 max_ga) { UInt i, j; HReg hreg, hregHI; @@ -2552,6 +2664,9 @@ iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host, /* and finally ... */ env->hwcaps = hwcaps_host; + env->max_ga = max_ga; + env->chaining_allowed = chaining_allowed; + /* For each IR temporary, allocate a suitably-kinded virtual register. */ j = 0; @@ -2595,12 +2710,26 @@ iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host, } env->vreg_ctr = j; + /* The very first instruction must be an event check. */ + s390_amode *counter, *fail_addr; + counter = s390_amode_for_guest_state(offset_host_evcheck_counter); + fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr); + addInstr(env, s390_insn_evcheck(counter, fail_addr)); + + /* Possibly a block counter increment (for profiling). At this + point we don't know the address of the counter, so just pretend + it is zero. It will have to be patched later, but before this + translation is used, by a call to LibVEX_patchProfInc. */ + if (add_profinc) { + addInstr(env, s390_insn_profinc()); + } + /* Ok, finally we can iterate over the statements. */ for (i = 0; i < bb->stmts_used; i++) if (bb->stmts[i]) s390_isel_stmt(env, bb->stmts[i]); - iselNext(env, bb->next, bb->jumpkind); + iselNext(env, bb->next, bb->jumpkind, bb->offsIP); /* Record the number of vregs we used. */ env->code->n_vregs = env->vreg_ctr; diff --git a/VEX/priv/main_main.c b/VEX/priv/main_main.c index 521e63caf4..b0f03dea69 100644 --- a/VEX/priv/main_main.c +++ b/VEX/priv/main_main.c @@ -358,7 +358,7 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) vassert(vta->dispatch_unassisted == NULL); vassert(vta->dispatch_assisted == NULL); break; - +#endif case VexArchS390X: mode64 = True; getAllocableRegs_S390 ( &n_available_real_regs, @@ -371,16 +371,13 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) ppInstr = (void(*)(HInstr*, Bool)) ppS390Instr; ppReg = (void(*)(HReg)) ppHRegS390; iselSB = iselSB_S390; - emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*,void*)) - emit_S390Instr; + emit = (Int(*)(Bool*,UChar*,Int,HInstr*,Bool, + void*,void*,void*,void*)) emit_S390Instr; host_is_bigendian = True; host_word_type = Ity_I64; vassert(are_valid_hwcaps(VexArchS390X, vta->archinfo_host.hwcaps)); - /* return-to-dispatcher scheme */ - vassert(vta->dispatch_unassisted == NULL); - vassert(vta->dispatch_assisted == NULL); break; -#endif + case VexArchARM: mode64 = False; getAllocableRegs_ARM ( &n_available_real_regs, @@ -480,7 +477,7 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) vassert(sizeof( ((VexGuestPPC64State*)0)->guest_NRADDR ) == 8); vassert(sizeof( ((VexGuestPPC64State*)0)->guest_NRADDR_GPR2) == 8); break; - +#endif case VexArchS390X: preciseMemExnsFn = guest_s390x_state_requires_precise_mem_exns; disInstrFn = disInstr_S390; @@ -490,13 +487,17 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) guest_layout = &s390xGuest_layout; offB_TISTART = offsetof(VexGuestS390XState,guest_TISTART); offB_TILEN = offsetof(VexGuestS390XState,guest_TILEN); + offB_GUEST_IP = offsetof(VexGuestS390XState,guest_IA); + szB_GUEST_IP = sizeof( ((VexGuestS390XState*)0)->guest_IA); + offB_HOST_EvC_COUNTER = offsetof(VexGuestS390XState,host_EvC_COUNTER); + offB_HOST_EvC_FAILADDR = offsetof(VexGuestS390XState,host_EvC_FAILADDR); vassert(are_valid_hwcaps(VexArchS390X, vta->archinfo_guest.hwcaps)); vassert(0 == sizeof(VexGuestS390XState) % 16); vassert(sizeof( ((VexGuestS390XState*)0)->guest_TISTART ) == 8); vassert(sizeof( ((VexGuestS390XState*)0)->guest_TILEN ) == 8); vassert(sizeof( ((VexGuestS390XState*)0)->guest_NRADDR ) == 8); break; -#endif + case VexArchARM: preciseMemExnsFn = guest_arm_state_requires_precise_mem_exns; disInstrFn = disInstr_ARM; @@ -827,6 +828,8 @@ VexInvalRange LibVEX_Chain ( VexArch arch_host, chainXDirect = chainXDirect_AMD64; break; case VexArchARM: chainXDirect = chainXDirect_ARM; break; + case VexArchS390X: + chainXDirect = chainXDirect_S390; break; default: vassert(0); } @@ -850,6 +853,8 @@ VexInvalRange LibVEX_UnChain ( VexArch arch_host, unchainXDirect = unchainXDirect_AMD64; break; case VexArchARM: unchainXDirect = unchainXDirect_ARM; break; + case VexArchS390X: + unchainXDirect = unchainXDirect_S390; break; default: vassert(0); } @@ -871,6 +876,8 @@ Int LibVEX_evCheckSzB ( VexArch arch_host ) cached = evCheckSzB_AMD64(); break; case VexArchARM: cached = evCheckSzB_ARM(); break; + case VexArchS390X: + cached = evCheckSzB_S390(); break; default: vassert(0); } @@ -890,6 +897,8 @@ VexInvalRange LibVEX_PatchProfInc ( VexArch arch_host, patchProfInc = patchProfInc_AMD64; break; case VexArchARM: patchProfInc = patchProfInc_ARM; break; + case VexArchS390X: + patchProfInc = patchProfInc_S390; break; default: vassert(0); } diff --git a/VEX/pub/libvex_guest_s390x.h b/VEX/pub/libvex_guest_s390x.h index 3bbeaf2b37..84d8bdcdea 100644 --- a/VEX/pub/libvex_guest_s390x.h +++ b/VEX/pub/libvex_guest_s390x.h @@ -144,10 +144,14 @@ typedef struct { /* Emulation warnings; see comments in libvex_emwarn.h */ /* 416 */ UInt guest_EMWARN; + /* For translation chaining */ + /* 420 */ UInt host_EvC_COUNTER; + /* 424 */ ULong host_EvC_FAILADDR; + /*------------------------------------------------------------*/ /*--- Force alignment to 16 bytes ---*/ /*------------------------------------------------------------*/ - /* 420 */ UChar padding[12]; + /* No padding needed */ /* 432 */ /* This is the size of the guest state */ } VexGuestS390XState; diff --git a/VEX/pub/libvex_s390x_common.h b/VEX/pub/libvex_s390x_common.h index 95efef6b5a..6d8ef5c3f8 100644 --- a/VEX/pub/libvex_s390x_common.h +++ b/VEX/pub/libvex_s390x_common.h @@ -1,3 +1,4 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ /*--------------------------------------------------------------------*/ /*--- Common defs for s390x libvex_s390x_common.h ---*/ @@ -27,8 +28,6 @@ The GNU General Public License is contained in the file COPYING. */ -/* -*- mode: C; c-basic-offset: 3; -*- */ - #ifndef __LIBVEX_PUB_S390X_H #define __LIBVEX_PUB_S390X_H @@ -42,7 +41,7 @@ /*--------------------------------------------------------------*/ #define S390_REGNO_RETURN_VALUE 2 -#define S390_REGNO_DISPATCH_CTR 12 /* Holds VG_(dispatch_ctr) */ +#define S390_REGNO_TCHAIN_SCRATCH 12 #define S390_REGNO_GUEST_STATE_POINTER 13 #define S390_REGNO_LINK_REGISTER 14 #define S390_REGNO_STACK_POINTER 15 @@ -52,7 +51,7 @@ /*--- Offsets in the stack frame allocated by the dispatcher ---*/ /*--------------------------------------------------------------*/ -/* Where the profiling dispatcher saves the r2 contents. */ +/* Where the dispatcher saves the r2 contents. */ #define S390_OFFSET_SAVED_R2 160+96 /* Where client's FPC register is saved. */ @@ -88,6 +87,12 @@ /* Number of double words needed to store all facility bits. */ #define S390_NUM_FACILITY_DW 2 +/* The length of the instructions issued by s390_tchain_load64 */ +#define S390_TCHAIN_LOAD64_LEN 16 + +/* The length of the call insn (BASR) used in translation chaining */ +#define S390_TCHAIN_CALL_LEN 2 + #endif /* __LIBVEX_PUB_S390X_H */ /*--------------------------------------------------------------------*/ -- 2.47.2