See ISA, 4.7.1.3 for details. Window check is inserted before commands that push "used register watermark" beyond its current level. Used register watermark is reset on instructions that change WINDOW_BASE/WINDOW_START SRs.
Signed-off-by: Max Filippov <[email protected]> --- v1 -> v2 changes: - dc->used_window is updated as necessary in the gen_window_check1; --- target-xtensa/translate.c | 110 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 110 insertions(+), 0 deletions(-) diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index e947766..6d6ad1b 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -60,6 +60,7 @@ typedef struct DisasContext { TCGv_i32 sar_m32; uint32_t ccount_delta; + unsigned used_window; } DisasContext; static TCGv_ptr cpu_env; @@ -225,6 +226,11 @@ static void gen_advance_ccount(DisasContext *dc) } } +static void reset_used_window(DisasContext *dc) +{ + dc->used_window = 0; +} + static void gen_exception(DisasContext *dc, int excp) { TCGv_i32 tmp = tcg_const_i32(excp); @@ -418,6 +424,13 @@ static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s) static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v) { gen_helper_wsr_windowbase(v); + reset_used_window(dc); +} + +static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + tcg_gen_mov_i32(cpu_SR[sr], v); + reset_used_window(dc); } static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v) @@ -429,6 +442,7 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v) mask |= PS_RING; } tcg_gen_andi_i32(cpu_SR[sr], v, mask); + reset_used_window(dc); /* This can change mmu index and tb->flags, so exit tb */ gen_jumpi_check_loop_end(dc, -1); } @@ -453,6 +467,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) [SAR] = gen_wsr_sar, [LITBASE] = gen_wsr_litbase, [WINDOW_BASE] = gen_wsr_windowbase, + [WINDOW_START] = gen_wsr_windowstart, [PS] = gen_wsr_ps, [CCOMPARE] = gen_wsr_ccompare, [CCOMPARE + 1] = gen_wsr_ccompare, @@ -497,6 +512,36 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4) tcg_temp_free(intlevel); } +static void gen_window_check1(DisasContext *dc, unsigned r1) +{ + if (dc->tb->flags & XTENSA_TBFLAG_EXCM) { + return; + } + if (option_enabled(dc, XTENSA_OPTION_WINDOWED_REGISTER) && + r1 / 4 > dc->used_window) { + TCGv_i32 pc = tcg_const_i32(dc->pc); + TCGv_i32 w = tcg_const_i32(r1 / 4); + + dc->used_window = r1 / 4; + gen_advance_ccount(dc); + gen_helper_window_check(pc, w); + + tcg_temp_free(w); + tcg_temp_free(pc); + } +} + +static void gen_window_check2(DisasContext *dc, unsigned r1, unsigned r2) +{ + gen_window_check1(dc, r1 > r2 ? r1 : r2); +} + +static void gen_window_check3(DisasContext *dc, unsigned r1, unsigned r2, + unsigned r3) +{ + gen_window_check2(dc, r1, r2 > r3 ? r2 : r3); +} + static void disas_xtensa_insn(DisasContext *dc) { #define HAS_OPTION(opt) do { \ @@ -626,6 +671,7 @@ static void disas_xtensa_insn(DisasContext *dc) switch (CALLX_N) { case 0: /*RET*/ case 2: /*JX*/ + gen_window_check1(dc, CALLX_S); gen_jump(dc, cpu_R[CALLX_S]); break; @@ -647,6 +693,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 3: /*CALLX*/ + gen_window_check2(dc, CALLX_S, CALLX_N << 2); switch (CALLX_N) { case 0: /*CALLX0*/ { @@ -677,6 +724,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 1: /*MOVSPw*/ HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + gen_window_check2(dc, RRR_T, RRR_S); { TCGv_i32 pc = tcg_const_i32(dc->pc); gen_advance_ccount(dc); @@ -821,6 +869,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 6: /*RSILx*/ HAS_OPTION(XTENSA_OPTION_INTERRUPT); gen_check_privilege(dc); + gen_window_check1(dc, RRR_T); tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]); tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL); tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S); @@ -860,28 +909,34 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 1: /*AND*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); break; case 2: /*OR*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); break; case 3: /*XOR*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); break; case 4: /*ST1*/ switch (RRR_R) { case 0: /*SSR*/ + gen_window_check1(dc, RRR_S); gen_right_shift_sar(dc, cpu_R[RRR_S]); break; case 1: /*SSL*/ + gen_window_check1(dc, RRR_S); gen_left_shift_sar(dc, cpu_R[RRR_S]); break; case 2: /*SSA8L*/ + gen_window_check1(dc, RRR_S); { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3); @@ -891,6 +946,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 3: /*SSA8B*/ + gen_window_check1(dc, RRR_S); { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3); @@ -924,16 +980,19 @@ static void disas_xtensa_insn(DisasContext *dc) RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0)); gen_helper_rotw(tmp); tcg_temp_free(tmp); + reset_used_window(dc); } break; case 14: /*NSAu*/ HAS_OPTION(XTENSA_OPTION_MISC_OP); + gen_window_check2(dc, RRR_S, RRR_T); gen_helper_nsa(cpu_R[RRR_T], cpu_R[RRR_S]); break; case 15: /*NSAUu*/ HAS_OPTION(XTENSA_OPTION_MISC_OP); + gen_window_check2(dc, RRR_S, RRR_T); gen_helper_nsau(cpu_R[RRR_T], cpu_R[RRR_S]); break; @@ -948,6 +1007,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 6: /*RT0*/ + gen_window_check2(dc, RRR_R, RRR_T); switch (RRR_S) { case 0: /*NEG*/ tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]); @@ -975,12 +1035,14 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 8: /*ADD*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); break; case 9: /*ADD**/ case 10: case 11: + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_shli_i32(tmp, cpu_R[RRR_S], _OP2 - 8); @@ -990,12 +1052,14 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 12: /*SUB*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); break; case 13: /*SUB**/ case 14: case 15: + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_shli_i32(tmp, cpu_R[RRR_S], _OP2 - 12); @@ -1010,17 +1074,20 @@ static void disas_xtensa_insn(DisasContext *dc) switch (_OP2) { case 0: /*SLLI*/ case 1: + gen_window_check2(dc, RRR_R, RRR_S); tcg_gen_shli_i32(cpu_R[RRR_R], cpu_R[RRR_S], 32 - (RRR_T | ((_OP2 & 1) << 4))); break; case 2: /*SRAI*/ case 3: + gen_window_check2(dc, RRR_R, RRR_T); tcg_gen_sari_i32(cpu_R[RRR_R], cpu_R[RRR_T], RRR_S | ((_OP2 & 1) << 4)); break; case 4: /*SRLI*/ + gen_window_check2(dc, RRR_R, RRR_T); tcg_gen_shri_i32(cpu_R[RRR_R], cpu_R[RRR_T], RRR_S); break; @@ -1030,6 +1097,7 @@ static void disas_xtensa_insn(DisasContext *dc) if (RSR_SR >= 64) { gen_check_privilege(dc); } + gen_window_check1(dc, RRR_T); tcg_gen_mov_i32(tmp, cpu_R[RRR_T]); gen_rsr(dc, cpu_R[RRR_T], RSR_SR); gen_wsr(dc, RSR_SR, tmp); @@ -1056,6 +1124,7 @@ static void disas_xtensa_insn(DisasContext *dc) #define gen_shift(cmd) gen_shift_reg(cmd, cpu_SR[SAR]) case 8: /*SRC*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); { TCGv_i64 v = tcg_temp_new_i64(); tcg_gen_concat_i32_i64(v, cpu_R[RRR_T], cpu_R[RRR_S]); @@ -1064,6 +1133,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 9: /*SRL*/ + gen_window_check2(dc, RRR_R, RRR_T); if (dc->sar_5bit) { tcg_gen_shr_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]); } else { @@ -1074,6 +1144,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 10: /*SLL*/ + gen_window_check2(dc, RRR_R, RRR_S); if (dc->sar_m32_5bit) { tcg_gen_shl_i32(cpu_R[RRR_R], cpu_R[RRR_S], dc->sar_m32); } else { @@ -1088,6 +1159,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 11: /*SRA*/ + gen_window_check2(dc, RRR_R, RRR_T); if (dc->sar_5bit) { tcg_gen_sar_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]); } else { @@ -1101,6 +1173,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 12: /*MUL16U*/ HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL); + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); { TCGv_i32 v1 = tcg_temp_new_i32(); TCGv_i32 v2 = tcg_temp_new_i32(); @@ -1114,6 +1187,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 13: /*MUL16S*/ HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL); + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); { TCGv_i32 v1 = tcg_temp_new_i32(); TCGv_i32 v2 = tcg_temp_new_i32(); @@ -1132,6 +1206,8 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 2: /*RST2*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); + if (_OP2 >= 12) { HAS_OPTION(XTENSA_OPTION_32_BIT_IDIV); int label = gen_new_label(); @@ -1199,6 +1275,7 @@ static void disas_xtensa_insn(DisasContext *dc) if (RSR_SR >= 64) { gen_check_privilege(dc); } + gen_window_check1(dc, RRR_T); gen_rsr(dc, cpu_R[RRR_T], RSR_SR); if (!sregnames[RSR_SR]) { TBD(); @@ -1209,6 +1286,7 @@ static void disas_xtensa_insn(DisasContext *dc) if (RSR_SR >= 64) { gen_check_privilege(dc); } + gen_window_check1(dc, RRR_T); gen_wsr(dc, RSR_SR, cpu_R[RRR_T]); if (!sregnames[RSR_SR]) { TBD(); @@ -1217,6 +1295,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 2: /*SEXTu*/ HAS_OPTION(XTENSA_OPTION_MISC_OP); + gen_window_check2(dc, RRR_R, RRR_S); { int shift = 24 - RRR_T; @@ -1235,6 +1314,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 3: /*CLAMPSu*/ HAS_OPTION(XTENSA_OPTION_MISC_OP); + gen_window_check2(dc, RRR_R, RRR_S); { TCGv_i32 tmp1 = tcg_temp_new_i32(); TCGv_i32 tmp2 = tcg_temp_new_i32(); @@ -1262,6 +1342,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 6: /*MINUu*/ case 7: /*MAXUu*/ HAS_OPTION(XTENSA_OPTION_MISC_OP); + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); { static const TCGCond cond[] = { TCG_COND_LE, @@ -1289,6 +1370,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 9: /*MOVNEZ*/ case 10: /*MOVLTZ*/ case 11: /*MOVGEZ*/ + gen_window_check3(dc, RRR_R, RRR_S, RRR_T); { static const TCGCond cond[] = { TCG_COND_NE, @@ -1314,6 +1396,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 14: /*RUR*/ + gen_window_check1(dc, RRR_R); { int st = (RRR_S << 4) + RRR_T; if (uregnames[st]) { @@ -1326,6 +1409,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 15: /*WUR*/ + gen_window_check1(dc, RRR_T); { if (uregnames[RSR_SR]) { tcg_gen_mov_i32(cpu_UR[RSR_SR], cpu_R[RRR_T]); @@ -1341,6 +1425,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 4: /*EXTUI*/ case 5: + gen_window_check2(dc, RRR_R, RRR_T); { int shiftimm = RRR_S | (_OP1 << 4); int maskimm = (1 << (_OP2 + 1)) - 1; @@ -1366,6 +1451,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 9: /*LSC4*/ + gen_window_check2(dc, RRR_S, RRR_T); switch (_OP2) { case 0: /*L32E*/ HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); @@ -1414,6 +1500,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 1: /*L32R*/ + gen_window_check1(dc, RRR_T); { TCGv_i32 tmp = tcg_const_i32( ((dc->tb->flags & XTENSA_TBFLAG_LITBASE) ? @@ -1431,6 +1518,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 2: /*LSAI*/ #define gen_load_store(type, shift) do { \ TCGv_i32 addr = tcg_temp_new_i32(); \ + gen_window_check2(dc, RRI8_S, RRI8_T); \ tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << shift); \ if (shift) { \ gen_load_store_alignment(dc, shift, addr, false); \ @@ -1567,6 +1655,7 @@ static void disas_xtensa_insn(DisasContext *dc) #undef gen_load_store case 10: /*MOVI*/ + gen_window_check1(dc, RRI8_T); tcg_gen_movi_i32(cpu_R[RRI8_T], RRI8_IMM8 | (RRI8_S << 8) | ((RRI8_S & 0x8) ? 0xfffff000 : 0)); @@ -1574,6 +1663,7 @@ static void disas_xtensa_insn(DisasContext *dc) #define gen_load_store_no_hw_align(type) do { \ TCGv_i32 addr = tcg_temp_local_new_i32(); \ + gen_window_check2(dc, RRI8_S, RRI8_T); \ tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); \ gen_load_store_alignment(dc, 2, addr, true); \ tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \ @@ -1586,15 +1676,18 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 12: /*ADDI*/ + gen_window_check2(dc, RRI8_S, RRI8_T); tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE); break; case 13: /*ADDMI*/ + gen_window_check2(dc, RRI8_S, RRI8_T); tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE << 8); break; case 14: /*S32C1Iy*/ HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO); + gen_window_check2(dc, RRI8_S, RRI8_T); { int label = gen_new_label(); TCGv_i32 tmp = tcg_temp_local_new_i32(); @@ -1648,6 +1741,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 2: /*CALL8w*/ case 3: /*CALL12w*/ HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); + gen_window_check1(dc, CALL_N << 2); gen_callwi(dc, CALL_N, (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0); break; @@ -1661,6 +1755,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 1: /*BZ*/ + gen_window_check1(dc, BRI12_S); { static const TCGCond cond[] = { TCG_COND_EQ, /*BEQZ*/ @@ -1675,6 +1770,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 2: /*BI0*/ + gen_window_check1(dc, BRI8_S); { static const TCGCond cond[] = { TCG_COND_EQ, /*BEQI*/ @@ -1701,6 +1797,7 @@ static void disas_xtensa_insn(DisasContext *dc) tcg_temp_free(imm); tcg_temp_free(s); tcg_temp_free(pc); + reset_used_window(dc); } break; @@ -1720,6 +1817,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 9: /*LOOPNEZ*/ case 10: /*LOOPGTZ*/ HAS_OPTION(XTENSA_OPTION_LOOP); + gen_window_check1(dc, RRI8_S); { uint32_t lend = dc->pc + RRI8_IMM8 + 4; TCGv_i32 tmp = tcg_const_i32(lend); @@ -1751,6 +1849,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 2: /*BLTUI*/ case 3: /*BGEUI*/ + gen_window_check1(dc, BRI8_S); gen_brcondi(dc, BRI8_M == 2 ? TCG_COND_LTU : TCG_COND_GEU, cpu_R[BRI8_S], B4CONSTU[BRI8_R], 4 + BRI8_IMM8_SE); break; @@ -1766,6 +1865,7 @@ static void disas_xtensa_insn(DisasContext *dc) switch (RRI8_R & 7) { case 0: /*BNONE*/ /*BANY*/ + gen_window_check2(dc, RRI8_S, RRI8_T); { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]); @@ -1777,6 +1877,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 1: /*BEQ*/ /*BNE*/ case 2: /*BLT*/ /*BGE*/ case 3: /*BLTU*/ /*BGEU*/ + gen_window_check2(dc, RRI8_S, RRI8_T); { static const TCGCond cond[] = { [1] = TCG_COND_EQ, @@ -1792,6 +1893,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 4: /*BALL*/ /*BNALL*/ + gen_window_check2(dc, RRI8_S, RRI8_T); { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]); @@ -1802,6 +1904,7 @@ static void disas_xtensa_insn(DisasContext *dc) break; case 5: /*BBC*/ /*BBS*/ + gen_window_check2(dc, RRI8_S, RRI8_T); { TCGv_i32 bit = tcg_const_i32(1); TCGv_i32 tmp = tcg_temp_new_i32(); @@ -1816,6 +1919,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 6: /*BBCI*/ /*BBSI*/ case 7: + gen_window_check1(dc, RRI8_S); { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_andi_i32(tmp, cpu_R[RRI8_S], @@ -1831,6 +1935,7 @@ static void disas_xtensa_insn(DisasContext *dc) #define gen_narrow_load_store(type) do { \ TCGv_i32 addr = tcg_temp_new_i32(); \ + gen_window_check2(dc, RRRN_S, RRRN_T); \ tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \ gen_load_store_alignment(dc, 2, addr, false); \ tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, dc->cring); \ @@ -1847,14 +1952,17 @@ static void disas_xtensa_insn(DisasContext *dc) #undef gen_narrow_load_store case 10: /*ADD.Nn*/ + gen_window_check3(dc, RRRN_R, RRRN_S, RRRN_T); tcg_gen_add_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], cpu_R[RRRN_T]); break; case 11: /*ADDI.Nn*/ + gen_window_check2(dc, RRRN_R, RRRN_S); tcg_gen_addi_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], RRRN_T ? RRRN_T : -1); break; case 12: /*ST2n*/ + gen_window_check1(dc, RRRN_S); if (RRRN_T < 8) { /*MOVI.Nn*/ tcg_gen_movi_i32(cpu_R[RRRN_S], RRRN_R | (RRRN_T << 4) | @@ -1870,6 +1978,7 @@ static void disas_xtensa_insn(DisasContext *dc) case 13: /*ST3n*/ switch (RRRN_R) { case 0: /*MOV.Nn*/ + gen_window_check2(dc, RRRN_S, RRRN_T); tcg_gen_mov_i32(cpu_R[RRRN_T], cpu_R[RRRN_S]); break; @@ -1973,6 +2082,7 @@ static void gen_intermediate_code_internal( init_litbase(&dc); init_sar_tracker(&dc); + reset_used_window(&dc); gen_icount_start(); -- 1.7.3.4
