Implement IJMP instruction (indirect jump or computed goto)

This commit is contained in:
Dmitry Stogov 2022-05-19 18:56:48 +03:00
parent bae7df6a5f
commit 911219493d
8 changed files with 66 additions and 5 deletions

1
TODO
View File

@ -2,7 +2,6 @@
- va_arg nodes
- BSTART, BEND nodes (to free data allocated by ALLOCA)
- ENTRY node for multy-entry units
- IJMP
- guards
- variable name binding

5
ir.h
View File

@ -272,7 +272,7 @@ int ir_mem_flush(void *ptr, size_t size);
_(LOOP_BEGIN, c2, src, src, ___) /* loop start */ \
_(LOOP_END, c1X1, src, beg, ___) /* loop end */ \
_(LOOP_EXIT, c1X1, src, beg, ___) /* loop exit */ \
/* (IJMP) */ \
_(IJMP, c2X1, src, def, ret) /* computed goto */ \
\
/* guards (floating or not) ??? */ \
_(GUARD_TRUE, c2, src, def, ___) /* IF without second successor */ \
@ -436,7 +436,8 @@ typedef struct _ir_strtab {
((op) == IR_MERGE || (op) == IR_LOOP_BEGIN)
#define IR_IS_BB_END(op) \
((op) == IR_RETURN || (op) == IR_END || (op) == IR_LOOP_END || (op) == IR_IF || (op) == IR_SWITCH)
((op) == IR_RETURN || (op) == IR_END || (op) == IR_LOOP_END || (op) == IR_IF || \
(op) == IR_SWITCH || (op) == IR_IJMP || (op) == IR_UNREACHABLE)
#define IR_BB_UNREACHABLE (1<<0)
#define IR_BB_LOOP_HEADER (1<<1)

View File

@ -68,7 +68,7 @@ void ir_dump_dot(ir_ctx *ctx, FILE *f)
if (flags & IR_OP_FLAG_CONTROL) {
if (insn->op == IR_START) {
fprintf(f, "\t{rank=min; n%d [label=\"%d: %s\",shape=box,style=\"rounded,filled\",fillcolor=red,rank=min];}\n", i, i, ir_op_name[insn->op]);
} else if (insn->op == IR_RETURN || insn->op == IR_UNREACHABLE) {
} else if (insn->op == IR_RETURN || insn->op == IR_UNREACHABLE || IR_IJMP) {
fprintf(f, "\t{rank=max; n%d [label=\"%d: %s\",shape=box,style=\"rounded,filled\",fillcolor=red,rank=max];}\n", i, i, ir_op_name[insn->op]);
} else if (flags & IR_OP_FLAG_MEM) {
fprintf(f, "\tn%d [label=\"%d: %s\",shape=box,style=filled,fillcolor=pink];\n", i, i, ir_op_name[insn->op]);

View File

@ -424,6 +424,13 @@ static void ir_emit_tailcall(ir_ctx *ctx, FILE *f, ir_insn *insn)
}
}
static void ir_emit_ijmp(ir_ctx *ctx, FILE *f, ir_insn *insn)
{
fprintf(f, "\tgoto *(void**)(");
ir_emit_ref(ctx, f, insn->op2);
fprintf(f, ");\n");
}
static void ir_emit_alloca(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn)
{
ir_emit_def_ref(ctx, f, def);
@ -767,6 +774,9 @@ static int ir_emit_func(ir_ctx *ctx, FILE *f)
case IR_TAILCALL:
ir_emit_tailcall(ctx, f, insn);
break;
case IR_IJMP:
ir_emit_ijmp(ctx, f, insn);
break;
case IR_ALLOCA:
ir_emit_alloca(ctx, f, i, insn);
break;

View File

@ -628,7 +628,7 @@ int ir_sccp(ir_ctx *ctx)
ir_sccp_replace_insn(ctx, _values, i, IR_UNUSED);
}
} else {
if (insn->op == IR_RETURN || insn->op == IR_UNREACHABLE) {
if (insn->op == IR_RETURN || insn->op == IR_UNREACHABLE || insn->op == IR_IJMP) {
ir_ref ref = ctx->ir_base[1].op1;
if (ref == i) {
ctx->ir_base[1].op1 = insn->op3;

View File

@ -4506,6 +4506,25 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn)
}
}
static void ir_emit_ijmp(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
dasm_State **Dst = &data->dasm_state;
ir_reg op2_reg = ctx->regs[def][2];
if (op2_reg != IR_REG_NONE) {
if (op2_reg & IR_REG_SPILL_LOAD) {
op2_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2);
}
| jmp Ra(op2_reg)
} else {
int32_t offset = ir_ref_spill_slot(ctx, insn->op2);
ir_reg fp = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_RBP : IR_REG_RSP;
| jmp aword [Ra(fp)+offset]
}
}
static int ir_emit_dessa_move(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to)
{
ir_backend_data *data = ctx->data;
@ -5796,6 +5815,9 @@ void *ir_emit(ir_ctx *ctx, size_t *size)
case IR_TAILCALL:
ir_emit_tailcall(ctx, i, insn);
break;
case IR_IJMP:
ir_emit_ijmp(ctx, i, insn);
break;
case IR_MEM_OP_INT:
case IR_MEM_INC:
case IR_MEM_DEC:

16
tests/c/ijmp_001.irt Normal file
View File

@ -0,0 +1,16 @@
--TEST--
001: IJMP - computed goto
--ARGS--
--emit-c
--CODE--
{
l_1 = START(l_2);
uintptr_t p = PARAM(l_1, "p", 1);
l_2 = IJMP(l_1, p);
}
--EXPECT--
void test(uintptr_t p)
{
uintptr_t d_1 = p;
goto *(void**)(d_1);
}

13
tests/debug/ijmp_001.irt Normal file
View File

@ -0,0 +1,13 @@
--TEST--
001: IJMP - computed goto
--ARGS--
-S
--CODE--
{
l_1 = START(l_2);
uintptr_t p = PARAM(l_1, "p", 1);
l_2 = IJMP(l_1, p);
}
--EXPECT--
test:
jmpq *%rdi