target/arm: Tidy TBI handling in gen_a64_set_pc

We can perform this with fewer operations.

Backports commit 8733d762d5e089a017ac7c5bc71077a8d75d1b46 from qemu
This commit is contained in:
Richard Henderson 2019-01-22 16:45:23 -05:00 committed by Lioncash
parent 1939b28276
commit 8c14f0ea57
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -278,7 +278,7 @@ void gen_a64_set_pc_im(DisasContext *s, uint64_t val)
/* Load the PC from a generic TCG variable.
*
* If address tagging is enabled via the TCR TBI bits, then loading
* an address into the PC will clear out any tag in the it:
* an address into the PC will clear out any tag in it:
* + for EL2 and EL3 there is only one TBI bit, and if it is set
* then the address is zero-extended, clearing bits [63:56]
* + for EL0 and EL1, TBI0 controls addresses with bit 55 == 0
@ -298,54 +298,34 @@ static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src)
int tbi = s->tbii;
if (s->current_el <= 1) {
/* Test if NEITHER or BOTH TBI values are set. If so, no need to
* examine bit 55 of address, can just generate code.
* If mixed, then test via generated code
*/
if (tbi == 3) {
TCGv_i64 tmp_reg = tcg_temp_new_i64(tcg_ctx);
/* Both bits set, sign extension from bit 55 into [63:56] will
* cover both cases
*/
tcg_gen_shli_i64(tcg_ctx, tmp_reg, src, 8);
tcg_gen_sari_i64(tcg_ctx, tcg_ctx->cpu_pc, tmp_reg, 8);
tcg_temp_free_i64(tcg_ctx, tmp_reg);
} else if (tbi == 0) {
/* Neither bit set, just load it as-is */
tcg_gen_mov_i64(tcg_ctx, tcg_ctx->cpu_pc, src);
} else {
TCGv_i64 tcg_tmpval = tcg_temp_new_i64(tcg_ctx);
TCGv_i64 tcg_bit55 = tcg_temp_new_i64(tcg_ctx);
TCGv_i64 tcg_zero = tcg_const_i64(tcg_ctx, 0);
if (tbi != 0) {
/* Sign-extend from bit 55. */
tcg_gen_sextract_i64(tcg_ctx, tcg_ctx->cpu_pc, src, 0, 56);
tcg_gen_andi_i64(tcg_ctx, tcg_bit55, src, (1ull << 55));
if (tbi != 3) {
TCGv_i64 tcg_zero = tcg_const_i64(tcg_ctx, 0);
if (tbi == 1) {
/* tbi0==1, tbi1==0, so 0-fill upper byte if bit 55 = 0 */
tcg_gen_andi_i64(tcg_ctx, tcg_tmpval, src,
0x00FFFFFFFFFFFFFFull);
tcg_gen_movcond_i64(tcg_ctx, TCG_COND_EQ, tcg_ctx->cpu_pc,
tcg_bit55, tcg_zero, tcg_tmpval, src);
} else {
/* tbi0==0, tbi1==1, so 1-fill upper byte if bit 55 = 1 */
tcg_gen_ori_i64(tcg_ctx, tcg_tmpval, src,
0xFF00000000000000ull);
tcg_gen_movcond_i64(tcg_ctx, TCG_COND_NE, tcg_ctx->cpu_pc,
tcg_bit55, tcg_zero, tcg_tmpval, src);
/*
* The two TBI bits differ.
* If tbi0, then !tbi1: only use the extension if positive.
* if !tbi0, then tbi1: only use the extension if negative.
*/
tcg_gen_movcond_i64(tcg_ctx, tbi == 1 ? TCG_COND_GE : TCG_COND_LT,
tcg_ctx->cpu_pc, tcg_ctx->cpu_pc, tcg_zero, tcg_ctx->cpu_pc, src);
tcg_temp_free_i64(tcg_ctx, tcg_zero);
}
tcg_temp_free_i64(tcg_ctx, tcg_zero);
tcg_temp_free_i64(tcg_ctx, tcg_bit55);
tcg_temp_free_i64(tcg_ctx, tcg_tmpval);
return;
}
} else { /* EL > 1 */
} else {
if (tbi != 0) {
/* Force tag byte to all zero */
tcg_gen_andi_i64(tcg_ctx, tcg_ctx->cpu_pc, src, 0x00FFFFFFFFFFFFFFull);
} else {
/* Load unmodified address */
tcg_gen_mov_i64(tcg_ctx, tcg_ctx->cpu_pc, src);
tcg_gen_extract_i64(tcg_ctx, tcg_ctx->cpu_pc, src, 0, 56);
return;
}
}
/* Load unmodified address */
tcg_gen_mov_i64(tcg_ctx, tcg_ctx->cpu_pc, src);
}
typedef struct DisasCompare64 {