Message ID | 9f38711e7d93ded68cad15e5cdbeecbf2c9ae521.1261248772.git.rth@twiddle.net |
---|---|
State | New |
Headers | show |
On Sat, Dec 19, 2009 at 10:44:11AM -0800, Richard Henderson wrote: > There are places, like brcond2, where we know that the destination > of a forward branch will be within 127 bytes. > > Add the R_386_PC8 relocation type to support this. Add a flag to > tcg_out_jxx and tcg_out_brcond* to enable it. Set the flag in the > brcond2 label_next branches; pass along the input flag otherwise. This looks ok, though I would appreciate someone else to review it in details. > Signed-off-by: Richard Henderson <rth@twiddle.net> > --- > elf.h | 2 + > tcg/i386/tcg-target.c | 116 +++++++++++++++++++++++++++++++++---------------- > 2 files changed, 80 insertions(+), 38 deletions(-) > > diff --git a/elf.h b/elf.h > index 11674d7..c84c8ab 100644 > --- a/elf.h > +++ b/elf.h > @@ -243,6 +243,8 @@ typedef struct { > #define R_386_GOTOFF 9 > #define R_386_GOTPC 10 > #define R_386_NUM 11 > +/* Not a dynamic reloc, so not included in R_386_NUM. Used in TCG. */ > +#define R_386_PC8 23 > > #define R_MIPS_NONE 0 > #define R_MIPS_16 1 > diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c > index 972b102..4c42caf 100644 > --- a/tcg/i386/tcg-target.c > +++ b/tcg/i386/tcg-target.c > @@ -61,6 +61,12 @@ static void patch_reloc(uint8_t *code_ptr, int type, > case R_386_PC32: > *(uint32_t *)code_ptr = value - (long)code_ptr; > break; > + case R_386_PC8: > + value -= (long)code_ptr; > + if (value != (int8_t)value) > + tcg_abort(); > + *(uint8_t *)code_ptr = value; > + break; > default: > tcg_abort(); > } > @@ -305,7 +311,8 @@ static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) > tgen_arithi(s, ARITH_ADD, reg, val, 0); > } > > -static void tcg_out_jxx(TCGContext *s, int opc, int label_index) > +/* Use SMALL != 0 to force a short forward branch. */ > +static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small) > { > int32_t val, val1; > TCGLabel *l = &s->labels[label_index]; > @@ -314,12 +321,16 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index) > val = l->u.value - (tcg_target_long)s->code_ptr; > val1 = val - 2; > if ((int8_t)val1 == val1) { > - if (opc == -1) > + if (opc == -1) { > tcg_out8(s, 0xeb); > - else > + } else { > tcg_out8(s, 0x70 + opc); > + } > tcg_out8(s, val1); > } else { > + if (small) { > + tcg_abort(); > + } > if (opc == -1) { > tcg_out8(s, 0xe9); > tcg_out32(s, val - 5); > @@ -329,6 +340,14 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index) > tcg_out32(s, val - 6); > } > } > + } else if (small) { > + if (opc == -1) { > + tcg_out8(s, 0xeb); > + } else { > + tcg_out8(s, 0x70 + opc); > + } > + tcg_out_reloc(s, s->code_ptr, R_386_PC8, label_index, -1); > + s->code_ptr += 1; > } else { > if (opc == -1) { > tcg_out8(s, 0xe9); > @@ -343,7 +362,7 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index) > > static void tcg_out_brcond(TCGContext *s, int cond, > TCGArg arg1, TCGArg arg2, int const_arg2, > - int label_index) > + int label_index, int small) > { > if (const_arg2) { > if (arg2 == 0) { > @@ -355,64 +374,84 @@ static void tcg_out_brcond(TCGContext *s, int cond, > } else { > tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3), arg2, arg1); > } > - tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index); > + tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small); > } > > /* XXX: we implement it at the target level to avoid having to > handle cross basic blocks temporaries */ > -static void tcg_out_brcond2(TCGContext *s, > - const TCGArg *args, const int *const_args) > +static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, > + const int *const_args, int small) > { > int label_next; > label_next = gen_new_label(); > switch(args[4]) { > case TCG_COND_EQ: > - tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], label_next); > - tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], args[5]); > + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], > + label_next, small); > + tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], > + args[5], small); > break; > case TCG_COND_NE: > - tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], args[5]); > - tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], args[5]); > + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], > + args[5], small); > + tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], > + args[5], small); > break; > case TCG_COND_LT: > - tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_LE: > - tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_GT: > - tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_GE: > - tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_LTU: > - tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_LEU: > - tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_GTU: > - tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_GEU: > - tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], > + args[5], small); > break; > default: > tcg_abort(); > @@ -913,7 +952,7 @@ static inline void tcg_out_op(TCGContext *s, int opc, > } > break; > case INDEX_op_br: > - tcg_out_jxx(s, JCC_JMP, args[0]); > + tcg_out_jxx(s, JCC_JMP, args[0], 0); > break; > case INDEX_op_movi_i32: > tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); > @@ -1044,10 +1083,11 @@ static inline void tcg_out_op(TCGContext *s, int opc, > tcg_out_modrm(s, 0x01 | (ARITH_SBB << 3), args[5], args[1]); > break; > case INDEX_op_brcond_i32: > - tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]); > + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], > + args[3], 0); > break; > case INDEX_op_brcond2_i32: > - tcg_out_brcond2(s, args, const_args); > + tcg_out_brcond2(s, args, const_args, 0); > break; > > case INDEX_op_bswap16_i32: > -- > 1.6.5.2 > > > >
On Sat, Dec 19, 2009 at 7:44 PM, Richard Henderson <rth@twiddle.net> wrote: > There are places, like brcond2, where we know that the destination > of a forward branch will be within 127 bytes. > > Add the R_386_PC8 relocation type to support this. Add a flag to > tcg_out_jxx and tcg_out_brcond* to enable it. Set the flag in the > brcond2 label_next branches; pass along the input flag otherwise. > > Signed-off-by: Richard Henderson <rth@twiddle.net> > > --- > elf.h | 2 + > tcg/i386/tcg-target.c | 116 +++++++++++++++++++++++++++++++++---------------- > 2 files changed, 80 insertions(+), 38 deletions(-) > > diff --git a/elf.h b/elf.h > index 11674d7..c84c8ab 100644 > --- a/elf.h > +++ b/elf.h > @@ -243,6 +243,8 @@ typedef struct { > #define R_386_GOTOFF 9 > #define R_386_GOTPC 10 > #define R_386_NUM 11 > +/* Not a dynamic reloc, so not included in R_386_NUM. Used in TCG. */ > +#define R_386_PC8 23 > > #define R_MIPS_NONE 0 > #define R_MIPS_16 1 > diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c > index 972b102..4c42caf 100644 > --- a/tcg/i386/tcg-target.c > +++ b/tcg/i386/tcg-target.c > @@ -61,6 +61,12 @@ static void patch_reloc(uint8_t *code_ptr, int type, > case R_386_PC32: > *(uint32_t *)code_ptr = value - (long)code_ptr; > break; > + case R_386_PC8: > + value -= (long)code_ptr; > + if (value != (int8_t)value) > + tcg_abort(); > + *(uint8_t *)code_ptr = value; > + break; > default: > tcg_abort(); > } > @@ -305,7 +311,8 @@ static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) > tgen_arithi(s, ARITH_ADD, reg, val, 0); > } > > -static void tcg_out_jxx(TCGContext *s, int opc, int label_index) > +/* Use SMALL != 0 to force a short forward branch. */ > +static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small) > { > int32_t val, val1; > TCGLabel *l = &s->labels[label_index]; > @@ -314,12 +321,16 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index) > val = l->u.value - (tcg_target_long)s->code_ptr; > val1 = val - 2; > if ((int8_t)val1 == val1) { > - if (opc == -1) > + if (opc == -1) { > tcg_out8(s, 0xeb); > - else > + } else { > tcg_out8(s, 0x70 + opc); > + } > tcg_out8(s, val1); > } else { > + if (small) { > + tcg_abort(); > + } > if (opc == -1) { > tcg_out8(s, 0xe9); > tcg_out32(s, val - 5); > @@ -329,6 +340,14 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index) > tcg_out32(s, val - 6); > } > } > + } else if (small) { > + if (opc == -1) { > + tcg_out8(s, 0xeb); > + } else { > + tcg_out8(s, 0x70 + opc); > + } > + tcg_out_reloc(s, s->code_ptr, R_386_PC8, label_index, -1); > + s->code_ptr += 1; > } else { > if (opc == -1) { > tcg_out8(s, 0xe9); > @@ -343,7 +362,7 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index) > > static void tcg_out_brcond(TCGContext *s, int cond, > TCGArg arg1, TCGArg arg2, int const_arg2, > - int label_index) > + int label_index, int small) > { > if (const_arg2) { > if (arg2 == 0) { > @@ -355,64 +374,84 @@ static void tcg_out_brcond(TCGContext *s, int cond, > } else { > tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3), arg2, arg1); > } > - tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index); > + tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small); > } > > /* XXX: we implement it at the target level to avoid having to > handle cross basic blocks temporaries */ > -static void tcg_out_brcond2(TCGContext *s, > - const TCGArg *args, const int *const_args) > +static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, > + const int *const_args, int small) > { > int label_next; > label_next = gen_new_label(); > switch(args[4]) { > case TCG_COND_EQ: > - tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], label_next); > - tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], args[5]); > + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], > + label_next, small); Shouldn't it be 1 instead of small? The rest is OK. Laurent > + tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], > + args[5], small); > break; > case TCG_COND_NE: > - tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], args[5]); > - tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], args[5]); > + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], > + args[5], small); > + tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], > + args[5], small); > break; > case TCG_COND_LT: > - tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_LE: > - tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_GT: > - tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_GE: > - tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_LTU: > - tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_LEU: > - tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_GTU: > - tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], > + args[5], small); > break; > case TCG_COND_GEU: > - tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); > - tcg_out_jxx(s, JCC_JNE, label_next); > - tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); > + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], > + args[5], small); > + tcg_out_jxx(s, JCC_JNE, label_next, 1); > + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], > + args[5], small); > break; > default: > tcg_abort(); > @@ -913,7 +952,7 @@ static inline void tcg_out_op(TCGContext *s, int opc, > } > break; > case INDEX_op_br: > - tcg_out_jxx(s, JCC_JMP, args[0]); > + tcg_out_jxx(s, JCC_JMP, args[0], 0); > break; > case INDEX_op_movi_i32: > tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); > @@ -1044,10 +1083,11 @@ static inline void tcg_out_op(TCGContext *s, int opc, > tcg_out_modrm(s, 0x01 | (ARITH_SBB << 3), args[5], args[1]); > break; > case INDEX_op_brcond_i32: > - tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]); > + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], > + args[3], 0); > break; > case INDEX_op_brcond2_i32: > - tcg_out_brcond2(s, args, const_args); > + tcg_out_brcond2(s, args, const_args, 0); > break; > > case INDEX_op_bswap16_i32: > -- > 1.6.5.2 > > > >
On 12/19/2009 03:32 PM, Laurent Desnogues wrote: >> switch(args[4]) { >> case TCG_COND_EQ: >> - tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], label_next); >> - tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], args[5]); >> + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], >> + label_next, small); > > Shouldn't it be 1 instead of small? Sigh, yes indeed. r~
diff --git a/elf.h b/elf.h index 11674d7..c84c8ab 100644 --- a/elf.h +++ b/elf.h @@ -243,6 +243,8 @@ typedef struct { #define R_386_GOTOFF 9 #define R_386_GOTPC 10 #define R_386_NUM 11 +/* Not a dynamic reloc, so not included in R_386_NUM. Used in TCG. */ +#define R_386_PC8 23 #define R_MIPS_NONE 0 #define R_MIPS_16 1 diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 972b102..4c42caf 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -61,6 +61,12 @@ static void patch_reloc(uint8_t *code_ptr, int type, case R_386_PC32: *(uint32_t *)code_ptr = value - (long)code_ptr; break; + case R_386_PC8: + value -= (long)code_ptr; + if (value != (int8_t)value) + tcg_abort(); + *(uint8_t *)code_ptr = value; + break; default: tcg_abort(); } @@ -305,7 +311,8 @@ static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) tgen_arithi(s, ARITH_ADD, reg, val, 0); } -static void tcg_out_jxx(TCGContext *s, int opc, int label_index) +/* Use SMALL != 0 to force a short forward branch. */ +static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small) { int32_t val, val1; TCGLabel *l = &s->labels[label_index]; @@ -314,12 +321,16 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index) val = l->u.value - (tcg_target_long)s->code_ptr; val1 = val - 2; if ((int8_t)val1 == val1) { - if (opc == -1) + if (opc == -1) { tcg_out8(s, 0xeb); - else + } else { tcg_out8(s, 0x70 + opc); + } tcg_out8(s, val1); } else { + if (small) { + tcg_abort(); + } if (opc == -1) { tcg_out8(s, 0xe9); tcg_out32(s, val - 5); @@ -329,6 +340,14 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index) tcg_out32(s, val - 6); } } + } else if (small) { + if (opc == -1) { + tcg_out8(s, 0xeb); + } else { + tcg_out8(s, 0x70 + opc); + } + tcg_out_reloc(s, s->code_ptr, R_386_PC8, label_index, -1); + s->code_ptr += 1; } else { if (opc == -1) { tcg_out8(s, 0xe9); @@ -343,7 +362,7 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index) static void tcg_out_brcond(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, int const_arg2, - int label_index) + int label_index, int small) { if (const_arg2) { if (arg2 == 0) { @@ -355,64 +374,84 @@ static void tcg_out_brcond(TCGContext *s, int cond, } else { tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3), arg2, arg1); } - tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index); + tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small); } /* XXX: we implement it at the target level to avoid having to handle cross basic blocks temporaries */ -static void tcg_out_brcond2(TCGContext *s, - const TCGArg *args, const int *const_args) +static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, + const int *const_args, int small) { int label_next; label_next = gen_new_label(); switch(args[4]) { case TCG_COND_EQ: - tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], label_next); - tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], args[5]); + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], + label_next, small); + tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], + args[5], small); break; case TCG_COND_NE: - tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], args[5]); - tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], args[5]); + tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], + args[5], small); + tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], + args[5], small); break; case TCG_COND_LT: - tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); - tcg_out_jxx(s, JCC_JNE, label_next); - tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], + args[5], small); + tcg_out_jxx(s, JCC_JNE, label_next, 1); + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], + args[5], small); break; case TCG_COND_LE: - tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]); - tcg_out_jxx(s, JCC_JNE, label_next); - tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], + args[5], small); + tcg_out_jxx(s, JCC_JNE, label_next, 1); + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], + args[5], small); break; case TCG_COND_GT: - tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); - tcg_out_jxx(s, JCC_JNE, label_next); - tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], + args[5], small); + tcg_out_jxx(s, JCC_JNE, label_next, 1); + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], + args[5], small); break; case TCG_COND_GE: - tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]); - tcg_out_jxx(s, JCC_JNE, label_next); - tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], + args[5], small); + tcg_out_jxx(s, JCC_JNE, label_next, 1); + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], + args[5], small); break; case TCG_COND_LTU: - tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); - tcg_out_jxx(s, JCC_JNE, label_next); - tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], + args[5], small); + tcg_out_jxx(s, JCC_JNE, label_next, 1); + tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], + args[5], small); break; case TCG_COND_LEU: - tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]); - tcg_out_jxx(s, JCC_JNE, label_next); - tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], + args[5], small); + tcg_out_jxx(s, JCC_JNE, label_next, 1); + tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], + args[5], small); break; case TCG_COND_GTU: - tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); - tcg_out_jxx(s, JCC_JNE, label_next); - tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], + args[5], small); + tcg_out_jxx(s, JCC_JNE, label_next, 1); + tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], + args[5], small); break; case TCG_COND_GEU: - tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]); - tcg_out_jxx(s, JCC_JNE, label_next); - tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]); + tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], + args[5], small); + tcg_out_jxx(s, JCC_JNE, label_next, 1); + tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], + args[5], small); break; default: tcg_abort(); @@ -913,7 +952,7 @@ static inline void tcg_out_op(TCGContext *s, int opc, } break; case INDEX_op_br: - tcg_out_jxx(s, JCC_JMP, args[0]); + tcg_out_jxx(s, JCC_JMP, args[0], 0); break; case INDEX_op_movi_i32: tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); @@ -1044,10 +1083,11 @@ static inline void tcg_out_op(TCGContext *s, int opc, tcg_out_modrm(s, 0x01 | (ARITH_SBB << 3), args[5], args[1]); break; case INDEX_op_brcond_i32: - tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]); + tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], + args[3], 0); break; case INDEX_op_brcond2_i32: - tcg_out_brcond2(s, args, const_args); + tcg_out_brcond2(s, args, const_args, 0); break; case INDEX_op_bswap16_i32:
There are places, like brcond2, where we know that the destination of a forward branch will be within 127 bytes. Add the R_386_PC8 relocation type to support this. Add a flag to tcg_out_jxx and tcg_out_brcond* to enable it. Set the flag in the brcond2 label_next branches; pass along the input flag otherwise. Signed-off-by: Richard Henderson <rth@twiddle.net> --- elf.h | 2 + tcg/i386/tcg-target.c | 116 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 80 insertions(+), 38 deletions(-)