Skip to content

Commit 4de4a47

Browse files
milesg-githubnpiggin
authored andcommitted
target/ppc: Add recording of taken branches to BHRB
This commit continues adding support for the Branch History Rolling Buffer (BHRB) as is provided starting with the P8 processor and continuing with its successors. This commit is limited to the recording and filtering of taken branches. The following changes were made: - Enabled functionality on P10 processors only due to performance impact seen with P8 and P9 where it is not disabled for non problem state branches. - Added a BHRB buffer for storing branch instruction and target addresses for taken branches - Renamed gen_update_cfar to gen_update_branch_history and added a 'target' parameter to hold the branch target address and 'inst_type' parameter to use for filtering - Added TCG code to gen_update_branch_history that stores data to the BHRB and updates the BHRB offset. - Added BHRB resource initialization and reset functions Reviewed-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
1 parent a7138e2 commit 4de4a47

File tree

6 files changed

+185
-8
lines changed

6 files changed

+185
-8
lines changed

target/ppc/cpu.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,8 @@ FIELD(MSR, LE, MSR_LE, 1)
548548
MMCR2_FC4P0 | MMCR2_FC5P0 | MMCR2_FC6P0)
549549

550550
#define MMCRA_BHRBRD PPC_BIT(26) /* BHRB Recording Disable */
551+
#define MMCRA_IFM_MASK PPC_BITMASK(32, 33) /* BHRB Instruction Filtering */
552+
#define MMCRA_IFM_SHIFT PPC_BIT_NR(33)
551553

552554
#define MMCR1_EVT_SIZE 8
553555
/* extract64() does a right shift before extracting */
@@ -774,6 +776,8 @@ enum {
774776
POWERPC_FLAG_SMT = 0x00400000,
775777
/* Using "LPAR per core" mode (as opposed to per-thread) */
776778
POWERPC_FLAG_SMT_1LPAR = 0x00800000,
779+
/* Has BHRB */
780+
POWERPC_FLAG_BHRB = 0x01000000,
777781
};
778782

779783
/*
@@ -1215,6 +1219,9 @@ struct pnv_tod_tbst {
12151219
#define PPC_CPU_OPCODES_LEN 0x40
12161220
#define PPC_CPU_INDIRECT_OPCODES_LEN 0x20
12171221

1222+
#define BHRB_MAX_NUM_ENTRIES_LOG2 (5)
1223+
#define BHRB_MAX_NUM_ENTRIES (1 << BHRB_MAX_NUM_ENTRIES_LOG2)
1224+
12181225
struct CPUArchState {
12191226
/* Most commonly used resources during translated code execution first */
12201227
target_ulong gpr[32]; /* general purpose registers */
@@ -1311,6 +1318,16 @@ struct CPUArchState {
13111318
int dcache_line_size;
13121319
int icache_line_size;
13131320

1321+
#ifdef TARGET_PPC64
1322+
/* Branch History Rolling Buffer (BHRB) resources */
1323+
target_ulong bhrb_num_entries;
1324+
intptr_t bhrb_base;
1325+
target_ulong bhrb_filter;
1326+
target_ulong bhrb_offset;
1327+
target_ulong bhrb_offset_mask;
1328+
uint64_t bhrb[BHRB_MAX_NUM_ENTRIES];
1329+
#endif
1330+
13141331
/* These resources are used during exception processing */
13151332
/* CPU model definition */
13161333
target_ulong msr_mask;

target/ppc/cpu_init.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6142,6 +6142,28 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
61426142
pcc->l1_icache_size = 0x8000;
61436143
}
61446144

6145+
static void bhrb_init_state(CPUPPCState *env, target_long num_entries_log2)
6146+
{
6147+
if (env->flags & POWERPC_FLAG_BHRB) {
6148+
if (num_entries_log2 > BHRB_MAX_NUM_ENTRIES_LOG2) {
6149+
num_entries_log2 = BHRB_MAX_NUM_ENTRIES_LOG2;
6150+
}
6151+
env->bhrb_num_entries = 1 << num_entries_log2;
6152+
env->bhrb_base = (intptr_t)&env->bhrb[0];
6153+
env->bhrb_offset_mask = (env->bhrb_num_entries * sizeof(uint64_t)) - 1;
6154+
}
6155+
}
6156+
6157+
static void bhrb_reset_state(CPUPPCState *env)
6158+
{
6159+
if (env->flags & POWERPC_FLAG_BHRB) {
6160+
env->bhrb_offset = 0;
6161+
env->bhrb_filter = 0;
6162+
memset(env->bhrb, 0, sizeof(env->bhrb));
6163+
}
6164+
}
6165+
6166+
#define POWER8_BHRB_ENTRIES_LOG2 5
61456167
static void init_proc_POWER8(CPUPPCState *env)
61466168
{
61476169
/* Common Registers */
@@ -6183,6 +6205,8 @@ static void init_proc_POWER8(CPUPPCState *env)
61836205
env->dcache_line_size = 128;
61846206
env->icache_line_size = 128;
61856207

6208+
bhrb_init_state(env, POWER8_BHRB_ENTRIES_LOG2);
6209+
61866210
/* Allocate hardware IRQ controller */
61876211
init_excp_POWER8(env);
61886212
ppcPOWER7_irq_init(env_archcpu(env));
@@ -6307,6 +6331,7 @@ static struct ppc_radix_page_info POWER9_radix_page_info = {
63076331
};
63086332
#endif /* CONFIG_USER_ONLY */
63096333

6334+
#define POWER9_BHRB_ENTRIES_LOG2 5
63106335
static void init_proc_POWER9(CPUPPCState *env)
63116336
{
63126337
/* Common Registers */
@@ -6357,6 +6382,8 @@ static void init_proc_POWER9(CPUPPCState *env)
63576382
env->dcache_line_size = 128;
63586383
env->icache_line_size = 128;
63596384

6385+
bhrb_init_state(env, POWER9_BHRB_ENTRIES_LOG2);
6386+
63606387
/* Allocate hardware IRQ controller */
63616388
init_excp_POWER9(env);
63626389
ppcPOWER9_irq_init(env_archcpu(env));
@@ -6497,6 +6524,7 @@ static struct ppc_radix_page_info POWER10_radix_page_info = {
64976524
};
64986525
#endif /* !CONFIG_USER_ONLY */
64996526

6527+
#define POWER10_BHRB_ENTRIES_LOG2 5
65006528
static void init_proc_POWER10(CPUPPCState *env)
65016529
{
65026530
/* Common Registers */
@@ -6546,6 +6574,8 @@ static void init_proc_POWER10(CPUPPCState *env)
65466574
env->dcache_line_size = 128;
65476575
env->icache_line_size = 128;
65486576

6577+
bhrb_init_state(env, POWER10_BHRB_ENTRIES_LOG2);
6578+
65496579
/* Allocate hardware IRQ controller */
65506580
init_excp_POWER10(env);
65516581
ppcPOWER9_irq_init(env_archcpu(env));
@@ -6650,7 +6680,8 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
66506680
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
66516681
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
66526682
POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR |
6653-
POWERPC_FLAG_VSX | POWERPC_FLAG_SCV;
6683+
POWERPC_FLAG_VSX | POWERPC_FLAG_SCV |
6684+
POWERPC_FLAG_BHRB;
66546685
pcc->l1_dcache_size = 0x8000;
66556686
pcc->l1_icache_size = 0x8000;
66566687
}
@@ -7222,6 +7253,10 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
72227253
}
72237254
env->spr[i] = spr->default_value;
72247255
}
7256+
7257+
#if defined(TARGET_PPC64)
7258+
bhrb_reset_state(env);
7259+
#endif
72257260
}
72267261

72277262
#ifndef CONFIG_USER_ONLY

target/ppc/power8-pmu.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,37 @@ static void pmu_update_summaries(CPUPPCState *env)
8282
env->pmc_cyc_cnt = cyc_cnt;
8383
}
8484

85+
static void hreg_bhrb_filter_update(CPUPPCState *env)
86+
{
87+
target_long ifm;
88+
89+
if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE)) {
90+
/* disable recording to BHRB */
91+
env->bhrb_filter = BHRB_TYPE_NORECORD;
92+
return;
93+
}
94+
95+
ifm = (env->spr[SPR_POWER_MMCRA] & MMCRA_IFM_MASK) >> MMCRA_IFM_SHIFT;
96+
switch (ifm) {
97+
case 0:
98+
/* record all branches */
99+
env->bhrb_filter = -1;
100+
break;
101+
case 1:
102+
/* only record calls (LK = 1) */
103+
env->bhrb_filter = BHRB_TYPE_CALL;
104+
break;
105+
case 2:
106+
/* only record indirect branches */
107+
env->bhrb_filter = BHRB_TYPE_INDIRECT;
108+
break;
109+
case 3:
110+
/* only record conditional branches */
111+
env->bhrb_filter = BHRB_TYPE_COND;
112+
break;
113+
}
114+
}
115+
85116
void pmu_mmcr01a_updated(CPUPPCState *env)
86117
{
87118
PowerPCCPU *cpu = env_archcpu(env);
@@ -95,6 +126,8 @@ void pmu_mmcr01a_updated(CPUPPCState *env)
95126
ppc_set_irq(cpu, PPC_INTERRUPT_PERFM, 0);
96127
}
97128

129+
hreg_bhrb_filter_update(env);
130+
98131
/*
99132
* Should this update overflow timers (if mmcr0 is updated) so they
100133
* get set in cpu_post_load?

target/ppc/power8-pmu.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
#ifndef POWER8_PMU_H
1414
#define POWER8_PMU_H
1515

16+
#define BHRB_TYPE_NORECORD 0x00
17+
#define BHRB_TYPE_CALL 0x01
18+
#define BHRB_TYPE_INDIRECT 0x02
19+
#define BHRB_TYPE_COND 0x04
20+
#define BHRB_TYPE_OTHER 0x08
21+
#define BHRB_TYPE_XL_FORM 0x10
22+
1623
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
1724

1825
#define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL

target/ppc/translate.c

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ struct DisasContext {
180180
#if defined(TARGET_PPC64)
181181
bool sf_mode;
182182
bool has_cfar;
183+
bool has_bhrb;
183184
#endif
184185
bool fpu_enabled;
185186
bool altivec_enabled;
@@ -3371,14 +3372,85 @@ static void gen_rvwinkle(DisasContext *ctx)
33713372
gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next);
33723373
#endif /* defined(CONFIG_USER_ONLY) */
33733374
}
3375+
3376+
static inline TCGv gen_write_bhrb(TCGv_ptr base, TCGv offset, TCGv mask, TCGv value)
3377+
{
3378+
TCGv_ptr tmp = tcg_temp_new_ptr();
3379+
3380+
/* add base and offset to get address of bhrb entry */
3381+
tcg_gen_add_ptr(tmp, base, (TCGv_ptr)offset);
3382+
3383+
/* store value into bhrb at bhrb_offset */
3384+
tcg_gen_st_i64(value, tmp, 0);
3385+
3386+
/* add 8 to current bhrb_offset */
3387+
tcg_gen_addi_tl(offset, offset, 8);
3388+
3389+
/* apply offset mask */
3390+
tcg_gen_and_tl(offset, offset, mask);
3391+
3392+
return offset;
3393+
}
33743394
#endif /* #if defined(TARGET_PPC64) */
33753395

3376-
static inline void gen_update_cfar(DisasContext *ctx, target_ulong nip)
3396+
static inline void gen_update_branch_history(DisasContext *ctx,
3397+
target_ulong nip,
3398+
TCGv target,
3399+
target_long inst_type)
33773400
{
33783401
#if defined(TARGET_PPC64)
3402+
TCGv_ptr base;
3403+
TCGv tmp;
3404+
TCGv offset;
3405+
TCGv mask;
3406+
TCGLabel *no_update;
3407+
33793408
if (ctx->has_cfar) {
33803409
tcg_gen_movi_tl(cpu_cfar, nip);
33813410
}
3411+
3412+
if (!ctx->has_bhrb ||
3413+
!ctx->bhrb_enable ||
3414+
inst_type == BHRB_TYPE_NORECORD) {
3415+
return;
3416+
}
3417+
3418+
tmp = tcg_temp_new();
3419+
no_update = gen_new_label();
3420+
3421+
/* check for bhrb filtering */
3422+
tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPUPPCState, bhrb_filter));
3423+
tcg_gen_andi_tl(tmp, tmp, inst_type);
3424+
tcg_gen_brcondi_tl(TCG_COND_EQ, tmp, 0, no_update);
3425+
3426+
base = tcg_temp_new_ptr();
3427+
offset = tcg_temp_new();
3428+
mask = tcg_temp_new();
3429+
3430+
/* load bhrb base address */
3431+
tcg_gen_ld_ptr(base, tcg_env, offsetof(CPUPPCState, bhrb_base));
3432+
3433+
/* load current bhrb_offset */
3434+
tcg_gen_ld_tl(offset, tcg_env, offsetof(CPUPPCState, bhrb_offset));
3435+
3436+
/* load a BHRB offset mask */
3437+
tcg_gen_ld_tl(mask, tcg_env, offsetof(CPUPPCState, bhrb_offset_mask));
3438+
3439+
offset = gen_write_bhrb(base, offset, mask, tcg_constant_i64(nip));
3440+
3441+
/* Also record the target address for XL-Form branches */
3442+
if (inst_type & BHRB_TYPE_XL_FORM) {
3443+
3444+
/* Set the 'T' bit for target entries */
3445+
tcg_gen_ori_tl(tmp, target, 0x2);
3446+
3447+
offset = gen_write_bhrb(base, offset, mask, tmp);
3448+
}
3449+
3450+
/* save updated bhrb_offset for next time */
3451+
tcg_gen_st_tl(offset, tcg_env, offsetof(CPUPPCState, bhrb_offset));
3452+
3453+
gen_set_label(no_update);
33823454
#endif
33833455
}
33843456

@@ -3508,8 +3580,10 @@ static void gen_b(DisasContext *ctx)
35083580
}
35093581
if (LK(ctx->opcode)) {
35103582
gen_setlr(ctx, ctx->base.pc_next);
3583+
gen_update_branch_history(ctx, ctx->cia, NULL, BHRB_TYPE_CALL);
3584+
} else {
3585+
gen_update_branch_history(ctx, ctx->cia, NULL, BHRB_TYPE_OTHER);
35113586
}
3512-
gen_update_cfar(ctx, ctx->cia);
35133587
gen_goto_tb(ctx, 0, target);
35143588
ctx->base.is_jmp = DISAS_NORETURN;
35153589
}
@@ -3524,6 +3598,7 @@ static void gen_bcond(DisasContext *ctx, int type)
35243598
uint32_t bo = BO(ctx->opcode);
35253599
TCGLabel *l1;
35263600
TCGv target;
3601+
target_long bhrb_type = BHRB_TYPE_OTHER;
35273602

35283603
if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) {
35293604
target = tcg_temp_new();
@@ -3534,11 +3609,16 @@ static void gen_bcond(DisasContext *ctx, int type)
35343609
} else {
35353610
tcg_gen_mov_tl(target, cpu_lr);
35363611
}
3612+
if (!LK(ctx->opcode)) {
3613+
bhrb_type |= BHRB_TYPE_INDIRECT;
3614+
}
3615+
bhrb_type |= BHRB_TYPE_XL_FORM;
35373616
} else {
35383617
target = NULL;
35393618
}
35403619
if (LK(ctx->opcode)) {
35413620
gen_setlr(ctx, ctx->base.pc_next);
3621+
bhrb_type |= BHRB_TYPE_CALL;
35423622
}
35433623
l1 = gen_new_label();
35443624
if ((bo & 0x4) == 0) {
@@ -3589,6 +3669,7 @@ static void gen_bcond(DisasContext *ctx, int type)
35893669
tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1);
35903670
}
35913671
}
3672+
bhrb_type |= BHRB_TYPE_COND;
35923673
}
35933674
if ((bo & 0x10) == 0) {
35943675
/* Test CR */
@@ -3603,8 +3684,11 @@ static void gen_bcond(DisasContext *ctx, int type)
36033684
tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
36043685
tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1);
36053686
}
3687+
bhrb_type |= BHRB_TYPE_COND;
36063688
}
3607-
gen_update_cfar(ctx, ctx->cia);
3689+
3690+
gen_update_branch_history(ctx, ctx->cia, target, bhrb_type);
3691+
36083692
if (type == BCOND_IM) {
36093693
target_ulong li = (target_long)((int16_t)(BD(ctx->opcode)));
36103694
if (likely(AA(ctx->opcode) == 0)) {
@@ -3720,7 +3804,7 @@ static void gen_rfi(DisasContext *ctx)
37203804
/* Restore CPU state */
37213805
CHK_SV(ctx);
37223806
translator_io_start(&ctx->base);
3723-
gen_update_cfar(ctx, ctx->cia);
3807+
gen_update_branch_history(ctx, ctx->cia, NULL, BHRB_TYPE_NORECORD);
37243808
gen_helper_rfi(tcg_env);
37253809
ctx->base.is_jmp = DISAS_EXIT;
37263810
#endif
@@ -3735,7 +3819,7 @@ static void gen_rfid(DisasContext *ctx)
37353819
/* Restore CPU state */
37363820
CHK_SV(ctx);
37373821
translator_io_start(&ctx->base);
3738-
gen_update_cfar(ctx, ctx->cia);
3822+
gen_update_branch_history(ctx, ctx->cia, NULL, BHRB_TYPE_NORECORD);
37393823
gen_helper_rfid(tcg_env);
37403824
ctx->base.is_jmp = DISAS_EXIT;
37413825
#endif
@@ -3750,7 +3834,7 @@ static void gen_rfscv(DisasContext *ctx)
37503834
/* Restore CPU state */
37513835
CHK_SV(ctx);
37523836
translator_io_start(&ctx->base);
3753-
gen_update_cfar(ctx, ctx->cia);
3837+
gen_update_branch_history(ctx, ctx->cia, NULL, BHRB_TYPE_NORECORD);
37543838
gen_helper_rfscv(tcg_env);
37553839
ctx->base.is_jmp = DISAS_EXIT;
37563840
#endif
@@ -6330,6 +6414,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
63306414
#if defined(TARGET_PPC64)
63316415
ctx->sf_mode = (hflags >> HFLAGS_64) & 1;
63326416
ctx->has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
6417+
ctx->has_bhrb = !!(env->flags & POWERPC_FLAG_BHRB);
63336418
#endif
63346419
ctx->lazy_tlb_flush = env->mmu_model == POWERPC_MMU_32B
63356420
|| env->mmu_model & POWERPC_MMU_64;

target/ppc/translate/branch-impl.c.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ static bool trans_RFEBB(DisasContext *ctx, arg_XL_s *arg)
1717
REQUIRE_INSNS_FLAGS2(ctx, ISA207S);
1818

1919
translator_io_start(&ctx->base);
20-
gen_update_cfar(ctx, ctx->cia);
20+
gen_update_branch_history(ctx, ctx->cia, NULL, BHRB_TYPE_NORECORD);
2121
gen_helper_rfebb(tcg_env, cpu_gpr[arg->s]);
2222

2323
ctx->base.is_jmp = DISAS_CHAIN;

0 commit comments

Comments
 (0)