Initial support for ALLOCA, LOAD and STORE (incomplete)

This commit is contained in:
Dmitry Stogov 2022-04-19 23:42:05 +03:00
parent 016a7c14d7
commit 51daf5556c
5 changed files with 150 additions and 13 deletions

2
TODO
View File

@ -60,7 +60,7 @@
- POW, NEG (fp), ABS, OVERFLOW, MIN, MAX, COND
+ TAILCALL
+ VLOAD, VSTORE
- ALLOCA, LOAD, STORE
? ALLOCA, LOAD, STORE
+ SWITCH
- ir_last_use
- binop_int $imm, mem

2
ir.c
View File

@ -93,7 +93,7 @@ void ir_print_const(ir_ctx *ctx, ir_insn *insn, FILE *f)
#define ir_op_flag_s2 (ir_op_flag_s | 2 | (2 << IR_OP_FLAG_OPERANS_SHIFT))
#define ir_op_flag_s3 (ir_op_flag_s | 3 | (3 << IR_OP_FLAG_OPERANS_SHIFT))
#define ir_op_flag_xN (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 4 | (4 << IR_OP_FLAG_OPERANS_SHIFT))
#define ir_op_flag_a1X1 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_ALLOC | 1 | (2 << IR_OP_FLAG_OPERANS_SHIFT))
#define ir_op_flag_a2 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_ALLOC | 2 | (2 << IR_OP_FLAG_OPERANS_SHIFT))
#define ir_op_kind____ IR_OPND_UNUSED
#define ir_op_kind_def IR_OPND_DATA

2
ir.h
View File

@ -245,7 +245,7 @@ int ir_mem_flush(void *ptr, size_t size);
_(TAILCALL, xN, src, def, def) /* CALL+RETURN */ \
\
/* memory reference and load/store ops */ \
_(ALLOCA, a1X1, src, num, ___) /* alloca(num) */ \
_(ALLOCA, a2, src, def, ___) /* alloca(def) */ \
_(VLOAD, l2, src, var, ___) /* load value of local var */ \
_(VSTORE, s3, src, var, def) /* store value to local var */ \
_(LOAD, l2, src, ref, ___) /* load from memory */ \

View File

@ -400,7 +400,9 @@ static void ir_emit_tailcall(ir_ctx *ctx, FILE *f, ir_insn *insn)
static void ir_emit_alloca(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn)
{
ir_emit_def_ref(ctx, f, def);
fprintf(f, "alloca(%d);\n", insn->op2);
fprintf(f, "alloca(");
ir_emit_ref(ctx, f, insn->op2);
fprintf(f, ");\n");
}
static void ir_emit_vstore(ir_ctx *ctx, FILE *f, ir_insn *insn)

View File

@ -745,6 +745,10 @@ typedef enum _ir_rule {
IR_VLOAD_FP,
IR_VSTORE_INT,
IR_VSTORE_FP,
IR_LOAD_INT,
IR_LOAD_FP,
IR_STORE_INT,
IR_STORE_FP,
IR_IF_INT, // op1=reg(GP)|mem
IR_RETURN_VOID, //
IR_RETURN_INT, // op1=reg(GP, hint=%rax)|mem|imm
@ -1154,8 +1158,16 @@ static uint32_t ir_match_insn(ir_ctx *ctx, ir_ref ref, ir_block *bb)
ctx->flags |= IR_HAS_CALLS;
return IR_CALL;
// case IR_TAILCALL:
// case IR_ALLOCA:
case IR_VAR:
if (ctx->use_lists[ref].count > 0) {
return IR_VAR;
} else {
return IR_SKIP;
}
break;
case IR_ALLOCA:
ctx->flags |= IR_USE_FRAME_POINTER;
return IR_ALLOCA;
case IR_VLOAD:
if (IR_IS_TYPE_INT(insn->type)) {
return IR_VLOAD_INT;
@ -1170,14 +1182,18 @@ static uint32_t ir_match_insn(ir_ctx *ctx, ir_ref ref, ir_block *bb)
return IR_VSTORE_FP;
}
break;
// case IR_LOAD:
// case IR_STORE:
case IR_VAR:
if (ctx->use_lists[ref].count > 0) {
return IR_VAR;
case IR_LOAD:
if (IR_IS_TYPE_INT(ctx->ir_base[insn->op3].type)) {
return IR_LOAD_INT;
} else {
return IR_SKIP;
return IR_LOAD_FP;
}
break;
case IR_STORE:
if (IR_IS_TYPE_INT(ctx->ir_base[insn->op3].type)) {
return IR_STORE_INT;
} else {
return IR_STORE_FP;
}
break;
case IR_START:
@ -2695,6 +2711,110 @@ static void ir_emit_vstore_fp(ir_ctx *ctx, ir_insn *insn)
| ASM_FP_VREG_REG_MOV type, ctx->vregs[insn->op2], reg
}
static void ir_emit_load_int(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
dasm_State **Dst = &data->dasm_state;
ir_ref type = insn->type;
ir_reg op2_reg = ir_ref_reg(ctx, insn->op2);
ir_reg def_reg = ir_ref_reg(ctx, def);
ir_reg reg;
if (def_reg >= 0) {
reg = def_reg;
} else {
reg = IR_REG_RAX; // TODO: temporary register
}
if (op2_reg < 0) {
op2_reg = IR_REG_RAX; // TODO: temporary register
ir_emit_load(ctx, type, insn->op2, op2_reg);
}
| ASM_REG_MEM_OP mov, type, reg, [Ra(op2_reg)]
if (def_reg != reg) {
ir_emit_store(ctx, type, reg, def);
}
}
static void ir_emit_load_fp(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
dasm_State **Dst = &data->dasm_state;
ir_ref type = insn->type;
ir_reg op2_reg = ir_ref_reg(ctx, insn->op2);
ir_reg def_reg = ir_ref_reg(ctx, def);
ir_reg reg;
if (def_reg >= 0) {
reg = def_reg;
} else {
reg = IR_REG_XMM7; // TODO: temporary register
}
if (op2_reg < 0) {
op2_reg = IR_REG_RAX; // TODO: temporary register
ir_emit_load(ctx, type, insn->op2, op2_reg);
}
| ASM_FP_REG_MEM_OP movss, movsd, vmovss, vmovsd, type, reg, [Ra(op2_reg)]
if (def_reg != reg) {
ir_emit_fp_store(ctx, type, reg, def);
}
}
static void ir_emit_store_int(ir_ctx *ctx, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
dasm_State **Dst = &data->dasm_state;
ir_ref type = ctx->ir_base[insn->op3].type;
ir_reg op2_reg = ir_ref_reg(ctx, insn->op2);
ir_reg op3_reg = ir_ref_reg(ctx, insn->op3);
ir_reg reg;
if (op3_reg >= 0) {
reg = op3_reg;
} else {
reg = IR_REG_RAX; // TODO: temporary register
ir_emit_load(ctx, type, insn->op3, reg);
}
if (op2_reg < 0) {
op2_reg = IR_REG_RAX; // TODO: temporary register
ir_emit_load(ctx, type, insn->op2, op2_reg);
}
| ASM_MEM_REG_OP mov, type, [Ra(op2_reg)], reg
}
static void ir_emit_store_fp(ir_ctx *ctx, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
dasm_State **Dst = &data->dasm_state;
ir_ref type = ctx->ir_base[insn->op3].type;
ir_reg op2_reg = ir_ref_reg(ctx, insn->op2);
ir_reg op3_reg = ir_ref_reg(ctx, insn->op3);
ir_reg reg;
if (op3_reg >= 0) {
reg = op3_reg;
} else {
reg = IR_REG_XMM7; // TODO: temporary register
ir_emit_fp_load(ctx, type, insn->op3, reg);
}
if (op2_reg < 0) {
op2_reg = IR_REG_RAX; // TODO: temporary register
ir_emit_load(ctx, type, insn->op2, op2_reg);
}
IR_ASSERT(ctx->vregs[insn->op2]);
| ASM_FP_MEM_REG_OP movss, movsd, vmovss, vmovsd, type, [Ra(op2_reg)], reg
}
static void ir_emit_alloca(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
dasm_State **Dst = &data->dasm_state;
// TODO: alignment
| ASM_REG_REF_OP sub, IR_ADDR, IR_REG_RSP, insn->op2
ir_emit_store(ctx, IR_ADDR, IR_REG_RSP, def);
// TODO: stack frame alignment
}
static void ir_emit_switch(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
@ -3946,6 +4066,21 @@ void *ir_emit(ir_ctx *ctx, size_t *size)
case IR_VSTORE_FP:
ir_emit_vstore_fp(ctx, insn);
break;
case IR_LOAD_INT:
ir_emit_load_int(ctx, i, insn);
break;
case IR_LOAD_FP:
ir_emit_load_fp(ctx, i, insn);
break;
case IR_STORE_INT:
ir_emit_store_int(ctx, insn);
break;
case IR_STORE_FP:
ir_emit_store_fp(ctx, insn);
break;
case IR_ALLOCA:
ir_emit_alloca(ctx, i, insn);
break;
default:
IR_ASSERT(0 && "NIY rule/insruction");
break;