@samitouri / QOSamiQemu / commits / 3d3f630963

target/ppc: move various conditional branch insns to decodetree

Convert the following instructions to decodetree specification: bc bca bcl bcla bclr bclrl bcctr bcctrl bctar bctarl The branch was tested by comparing the qemu -D log -d op,in_asm output for each instruction and also for the various combinations of branch option (BO) bits for the conditional branch instructions. Additionally, gdb was used to confirm the LR and other register's behavior is consistent to legacy behavior. Further, the changes also pass a boot test into Fedora distro. Signed-off-by: Ojaswin Mujoo <ojaswin@linux.ibm.com> Reviewed-by: Glenn Miles <milesg@linux.ibm.com> Reviewed-by: Amit Machhiwal <amachhiw@linux.ibm.com> Signed-off-by: Chinmay Rath <rathc@linux.ibm.com> Tested-by: Aniket Sahu <asahu1x@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20260827133010.278889-16-rathc@linux.ibm.com Signed-off-by: Harsh Prateek Bora <harshpb@linux.ibm.com>

Ojaswin Mujoo committed Aug 27, 2026 at 18:59 UTC 3d3f63096333b18506366ea0f6b57d0c29803d38
3 files changed +169 -148
target/ppc/insn32.decode
+13
@@ -1493,6 +1493,19 @@ CLRBHRB 011111 ----- ----- ----- 0110101110 -
1493
1494 B 010010 ........................ . . @I_b
1495
1496 +%bd 2:14 !function=times_4
1497 +&bcond bo:uint32_t bi bd aa:bool lk:bool
1498 +@B_bcond ...... bo:5 bi:5 .............. aa:1 lk:1 &bcond bd=%bd
1499 +
1500 +BC 010000 ..... ..... .............. . . @B_bcond
1501 +
1502 +&bclr bo bi bh lk:bool
1503 +@XL_bclr ...... bo:5 bi:5 --- bh:2 .......... lk:1 &bclr
1504 +
1505 +BCLR 010011 ..... ..... ---.. 0000010000 . @XL_bclr
1506 +BCCTR 010011 ..... ..... ---.. 1000010000 . @XL_bclr
1507 +BCTAR 010011 ..... ..... ---.. 1000110000 . @XL_bclr
1508 +
1509 ## Misc POWER instructions
1510
1511 ATTN 000000 00000 00000 00000 0100000000 0
target/ppc/translate.c
-148
@@ -3089,150 +3089,6 @@ static inline void gen_setlr(DisasContext *ctx, target_ulong nip)
3089 tcg_gen_movi_tl(cpu_lr, nip);
3090 }
3091
3092 -#define BCOND_IM 0
3093 -#define BCOND_LR 1
3094 -#define BCOND_CTR 2
3095 -#define BCOND_TAR 3
3096 -
3097 -static void gen_bcond(DisasContext *ctx, int type)
3098 -{
3099 - uint32_t bo = BO(ctx->opcode);
3100 - TCGLabel *l1;
3101 - TCGv target;
3102 - target_long bhrb_type = BHRB_TYPE_OTHER;
3103 -
3104 - if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) {
3105 - target = tcg_temp_new();
3106 - if (type == BCOND_CTR) {
3107 - tcg_gen_mov_tl(target, cpu_ctr);
3108 - } else if (type == BCOND_TAR) {
3109 - gen_load_spr(target, SPR_TAR);
3110 - } else {
3111 - tcg_gen_mov_tl(target, cpu_lr);
3112 - }
3113 - if (!LK(ctx->opcode)) {
3114 - bhrb_type |= BHRB_TYPE_INDIRECT;
3115 - }
3116 - bhrb_type |= BHRB_TYPE_XL_FORM;
3117 - } else {
3118 - target = NULL;
3119 - }
3120 - if (LK(ctx->opcode)) {
3121 - gen_setlr(ctx, ctx->base.pc_next);
3122 - bhrb_type |= BHRB_TYPE_CALL;
3123 - }
3124 - l1 = gen_new_label();
3125 - if ((bo & 0x4) == 0) {
3126 - /* Decrement and test CTR */
3127 - TCGv temp = tcg_temp_new();
3128 -
3129 - if (type == BCOND_CTR) {
3130 - /*
3131 - * All ISAs up to v3 describe this form of bcctr as invalid but
3132 - * some processors, ie. 64-bit server processors compliant with
3133 - * arch 2.x, do implement a "test and decrement" logic instead,
3134 - * as described in their respective UMs. This logic involves CTR
3135 - * to act as both the branch target and a counter, which makes
3136 - * it basically useless and thus never used in real code.
3137 - *
3138 - * This form was hence chosen to trigger extra micro-architectural
3139 - * side-effect on real HW needed for the Spectre v2 workaround.
3140 - * It is up to guests that implement such workaround, ie. linux, to
3141 - * use this form in a way it just triggers the side-effect without
3142 - * doing anything else harmful.
3143 - */
3144 - if (unlikely(!is_book3s_arch2x(ctx))) {
3145 - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
3146 - return;
3147 - }
3148 -
3149 - if (NARROW_MODE(ctx)) {
3150 - tcg_gen_ext32u_tl(temp, cpu_ctr);
3151 - } else {
3152 - tcg_gen_mov_tl(temp, cpu_ctr);
3153 - }
3154 - if (bo & 0x2) {
3155 - tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1);
3156 - } else {
3157 - tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1);
3158 - }
3159 - tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
3160 - } else {
3161 - tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
3162 - if (NARROW_MODE(ctx)) {
3163 - tcg_gen_ext32u_tl(temp, cpu_ctr);
3164 - } else {
3165 - tcg_gen_mov_tl(temp, cpu_ctr);
3166 - }
3167 - if (bo & 0x2) {
3168 - tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1);
3169 - } else {
3170 - tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1);
3171 - }
3172 - }
3173 - bhrb_type |= BHRB_TYPE_COND;
3174 - }
3175 - if ((bo & 0x10) == 0) {
3176 - /* Test CR */
3177 - uint32_t bi = BI(ctx->opcode);
3178 - uint32_t mask = 0x08 >> (bi & 0x03);
3179 - TCGv_i32 temp = tcg_temp_new_i32();
3180 -
3181 - if (bo & 0x8) {
3182 - tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
3183 - tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l1);
3184 - } else {
3185 - tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
3186 - tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1);
3187 - }
3188 - bhrb_type |= BHRB_TYPE_COND;
3189 - }
3190 -
3191 - gen_update_branch_history(ctx, ctx->cia, target, bhrb_type);
3192 -
3193 - if (type == BCOND_IM) {
3194 - target_ulong li = (target_long)((int16_t)(BD(ctx->opcode)));
3195 - if (likely(AA(ctx->opcode) == 0)) {
3196 - gen_goto_tb(ctx, 0, ctx->cia + li);
3197 - } else {
3198 - gen_goto_tb(ctx, 0, li);
3199 - }
3200 - } else {
3201 - if (NARROW_MODE(ctx)) {
3202 - tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3);
3203 - } else {
3204 - tcg_gen_andi_tl(cpu_nip, target, ~3);
3205 - }
3206 - gen_lookup_and_goto_ptr(ctx);
3207 - }
3208 - if ((bo & 0x14) != 0x14) {
3209 - /* fallthrough case */
3210 - gen_set_label(l1);
3211 - gen_goto_tb(ctx, 1, ctx->base.pc_next);
3212 - }
3213 - ctx->base.is_jmp = DISAS_NORETURN;
3214 -}
3215 -
3216 -static void gen_bc(DisasContext *ctx)
3217 -{
3218 - gen_bcond(ctx, BCOND_IM);
3219 -}
3220 -
3221 -static void gen_bcctr(DisasContext *ctx)
3222 -{
3223 - gen_bcond(ctx, BCOND_CTR);
3224 -}
3225 -
3226 -static void gen_bclr(DisasContext *ctx)
3227 -{
3228 - gen_bcond(ctx, BCOND_LR);
3229 -}
3230 -
3231 -static void gen_bctar(DisasContext *ctx)
3232 -{
3233 - gen_bcond(ctx, BCOND_TAR);
3234 -}
3235 -
3092 /*** Condition register logical ***/
3093 #define GEN_CRLOGIC(name, tcg_op, opc) \
3094 static void glue(gen_, name)(DisasContext *ctx) \
@@ -5330,10 +5186,6 @@ GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING),
5186 /* ISA v3.0 changed the extended opcode from 62 to 30 */
5187 GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x039FF801, PPC_WAIT),
5188 GEN_HANDLER_E(wait, 0x1F, 0x1E, 0x00, 0x039CF801, PPC_NONE, PPC2_ISA300),
5333 -GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
5334 -GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW),
5335 -GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW),
5336 -GEN_HANDLER_E(bctar, 0x13, 0x10, 0x11, 0x0000E000, PPC_NONE, PPC2_BCTAR_ISA207),
5189 GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW),
5190 #if defined(TARGET_PPC64)
5191 GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B),
target/ppc/translate/branch-impl.c.inc
+156
@@ -55,3 +55,159 @@ static bool trans_B(DisasContext *ctx, arg_I_b *a)
55
56 return true;
57 }
58 +
59 +#define BCOND_IM 0
60 +#define BCOND_LR 1
61 +#define BCOND_CTR 2
62 +#define BCOND_TAR 3
63 +
64 +static bool bcond_helper(DisasContext *ctx, int type, uint32_t bo, int bi,
65 + int bd, int bh, bool aa, bool lk)
66 +{
67 + TCGLabel *l1;
68 + TCGv target;
69 + target_long bhrb_type = BHRB_TYPE_OTHER;
70 +
71 + if (type == BCOND_IM && bh != -1) {
72 + /* BCOND_IM should never use bh */
73 + return false;
74 + } else if (type != BCOND_IM && (bd != -1 || aa != 0)) {
75 + /* Other BCOND types should never use bd or aa */
76 + return false;
77 + }
78 +
79 + if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) {
80 + target = tcg_temp_new();
81 + if (type == BCOND_CTR) {
82 + tcg_gen_mov_tl(target, cpu_ctr);
83 + } else if (type == BCOND_TAR) {
84 + gen_load_spr(target, SPR_TAR);
85 + } else {
86 + tcg_gen_mov_tl(target, cpu_lr);
87 + }
88 + if (!lk) {
89 + bhrb_type |= BHRB_TYPE_INDIRECT;
90 + }
91 + bhrb_type |= BHRB_TYPE_XL_FORM;
92 + } else {
93 + target = NULL;
94 + }
95 + if (lk) {
96 + gen_setlr(ctx, ctx->base.pc_next);
97 + bhrb_type |= BHRB_TYPE_CALL;
98 + }
99 + l1 = gen_new_label();
100 + if ((bo & 0x4) == 0) {
101 + /* Decrement and test CTR */
102 + TCGv temp = tcg_temp_new();
103 +
104 + if (type == BCOND_CTR) {
105 + /*
106 + * All ISAs up to v3 describe this form of bcctr as invalid but
107 + * some processors, ie. 64-bit server processors compliant with
108 + * arch 2.x, do implement a "test and decrement" logic instead,
109 + * as described in their respective UMs. This logic involves CTR
110 + * to act as both the branch target and a counter, which makes
111 + * it basically useless and thus never used in real code.
112 + *
113 + * This form was hence chosen to trigger extra micro-architectural
114 + * side-effect on real HW needed for the Spectre v2 workaround.
115 + * It is up to guests that implement such workaround, ie. linux, to
116 + * use this form in a way it just triggers the side-effect without
117 + * doing anything else harmful.
118 + */
119 + if (unlikely(!is_book3s_arch2x(ctx))) {
120 + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
121 + return true;
122 + }
123 +
124 + if (NARROW_MODE(ctx)) {
125 + tcg_gen_ext32u_tl(temp, cpu_ctr);
126 + } else {
127 + tcg_gen_mov_tl(temp, cpu_ctr);
128 + }
129 + if (bo & 0x2) {
130 + tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1);
131 + } else {
132 + tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1);
133 + }
134 + tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
135 + } else {
136 + tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
137 + if (NARROW_MODE(ctx)) {
138 + tcg_gen_ext32u_tl(temp, cpu_ctr);
139 + } else {
140 + tcg_gen_mov_tl(temp, cpu_ctr);
141 + }
142 + if (bo & 0x2) {
143 + tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1);
144 + } else {
145 + tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1);
146 + }
147 + }
148 + bhrb_type |= BHRB_TYPE_COND;
149 + }
150 + if ((bo & 0x10) == 0) {
151 + /* Test CR */
152 + uint32_t mask = 0x08 >> (bi & 0x03);
153 + TCGv_i32 temp = tcg_temp_new_i32();
154 +
155 + if (bo & 0x8) {
156 + tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
157 + tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l1);
158 + } else {
159 + tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
160 + tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1);
161 + }
162 + bhrb_type |= BHRB_TYPE_COND;
163 + }
164 +
165 + gen_update_branch_history(ctx, ctx->cia, target, bhrb_type);
166 +
167 + if (type == BCOND_IM) {
168 + target_ulong li = (target_long)((int16_t)(bd));
169 + if (likely(aa == 0)) {
170 + gen_goto_tb(ctx, 0, ctx->cia + li);
171 + } else {
172 + gen_goto_tb(ctx, 0, li);
173 + }
174 + } else {
175 + if (NARROW_MODE(ctx)) {
176 + tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3);
177 + } else {
178 + tcg_gen_andi_tl(cpu_nip, target, ~3);
179 + }
180 + gen_lookup_and_goto_ptr(ctx);
181 + }
182 + if ((bo & 0x14) != 0x14) {
183 + /* fallthrough case */
184 + gen_set_label(l1);
185 + gen_goto_tb(ctx, 1, ctx->base.pc_next);
186 + }
187 + ctx->base.is_jmp = DISAS_NORETURN;
188 +
189 + return true;
190 +}
191 +
192 +static bool trans_BC(DisasContext *ctx, arg_bcond *a)
193 +{
194 + /*
195 + * bh is not used for bc variants hence we pass -1
196 + */
197 + return bcond_helper(ctx, BCOND_IM, a->bo, a->bi, a->bd, -1, a->aa, a->lk);
198 +}
199 +
200 +/*
201 + * This helper is shared by bclr, bcctr and bctar.
202 + */
203 +static bool bclr_helper(DisasContext *ctx, arg_bclr *a, int type)
204 +{
205 + /*
206 + * bd and aa is not used for bc variants hence we pass -1 and 0 respectively
207 + */
208 + return bcond_helper(ctx, type, a->bo, a->bi, -1, a->bh, 0, a->lk);
209 +}
210 +
211 +TRANS(BCLR, bclr_helper, BCOND_LR)
212 +TRANS(BCCTR, bclr_helper, BCOND_CTR)
213 +TRANS_FLAGS2(BCTAR_ISA207, BCTAR, bclr_helper, BCOND_TAR)