mirror of
https://github.com/danog/ir.git
synced 2024-11-30 04:39:43 +01:00
Add VA_ARG nodes (JIT code generation is not supported yet)
This commit is contained in:
parent
e5b4c686df
commit
507175b228
2
TODO
2
TODO
@ -1,4 +1,3 @@
|
||||
- va_arg nodes
|
||||
? BSTART, BEND nodes (to free data allocated by ALLOCA) (now it's possible to do this through AFREE)
|
||||
- Full support for function prototypes ???
|
||||
(now we may only set "fastcall" calling convention for constants or for variables through BITCAST)
|
||||
@ -27,6 +26,7 @@
|
||||
- Try to avoid live-interval construction, see "Efficient Global Register Allocation" Ian Rogers
|
||||
|
||||
? code generation
|
||||
- VA_START, VA_END, VA_COPY, VA_ARG nodes
|
||||
- COND optimization
|
||||
- TAILCALL with stack arguments (tests/x86/tailcall_001.itr)
|
||||
- 32-bit x86 back-end 64-bit integers support
|
||||
|
25
ir.c
25
ir.c
@ -201,6 +201,7 @@ void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted
|
||||
#define ir_op_flag_s3 (ir_op_flag_s | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_x1 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_x2 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_x3 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_xN (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | IR_OP_FLAG_VAR_INPUTS)
|
||||
#define ir_op_flag_a2 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_ALLOC | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
|
||||
@ -2322,3 +2323,27 @@ check_aliasing:
|
||||
}
|
||||
ctx->control = ir_emit3(ctx, IR_STORE, ctx->control, addr, val);
|
||||
}
|
||||
|
||||
void _ir_VA_START(ir_ctx *ctx, ir_ref list)
|
||||
{
|
||||
IR_ASSERT(ctx->control);
|
||||
ctx->control = ir_emit2(ctx, IR_VA_START, ctx->control, list);
|
||||
}
|
||||
|
||||
void _ir_VA_END(ir_ctx *ctx, ir_ref list)
|
||||
{
|
||||
IR_ASSERT(ctx->control);
|
||||
ctx->control = ir_emit2(ctx, IR_VA_END, ctx->control, list);
|
||||
}
|
||||
|
||||
void _ir_VA_COPY(ir_ctx *ctx, ir_ref dst, ir_ref src)
|
||||
{
|
||||
IR_ASSERT(ctx->control);
|
||||
ctx->control = ir_emit3(ctx, IR_VA_COPY, ctx->control, dst, src);
|
||||
}
|
||||
|
||||
ir_ref _ir_VA_ARG(ir_ctx *ctx, ir_type type, ir_ref list)
|
||||
{
|
||||
IR_ASSERT(ctx->control);
|
||||
return ctx->control = ir_emit2(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list);
|
||||
}
|
||||
|
6
ir.h
6
ir.h
@ -302,6 +302,12 @@ typedef enum _ir_type {
|
||||
_(TRAP, x1, src, ___, ___) /* DebugBreak */ \
|
||||
/* memory reference ops (A, H, U, S, TMP, STR, NEW, X, V) ??? */ \
|
||||
\
|
||||
/* va_args */ \
|
||||
_(VA_START, x2, src, def, ___) /* va_start(va_list) */ \
|
||||
_(VA_END, x2, src, def, ___) /* va_end(va_list) */ \
|
||||
_(VA_COPY, x3, src, def, def) /* va_copy(dst, stc) */ \
|
||||
_(VA_ARG, x2, src, def, ___) /* va_arg(va_list) */ \
|
||||
\
|
||||
/* guards */ \
|
||||
_(GUARD, c3, src, def, def) /* IF without second successor */ \
|
||||
_(GUARD_NOT , c3, src, def, def) /* IF without second successor */ \
|
||||
|
@ -539,6 +539,11 @@ extern "C" {
|
||||
#define ir_TLS(_index, _offset) _ir_TLS(_ir_CTX, (_index), (_offset))
|
||||
#define ir_TRAP() do {_ir_CTX->control = ir_emit1(_ir_CTX, IR_TRAP, _ir_CTX->control);} while (0)
|
||||
|
||||
#define ir_VA_START(_list) _ir_VA_START(_ir_CTX, _list)
|
||||
#define ir_VA_END(_list) _ir_VA_END(_ir_CTX, _list)
|
||||
#define ir_VA_COPY(_dst, _src) _ir_VA_COPY(_ir_CTX, _dst, _src)
|
||||
#define ir_VA_ARG(_list, _type) _ir_VA_ARG(_ir_CTX, _type, _list)
|
||||
|
||||
#define ir_START() _ir_START(_ir_CTX)
|
||||
#define ir_ENTRY(_src, _num) _ir_ENTRY(_ir_CTX, (_src), (_num))
|
||||
#define ir_BEGIN(_src) _ir_BEGIN(_ir_CTX, (_src))
|
||||
@ -603,6 +608,10 @@ ir_ref _ir_RLOAD(ir_ctx *ctx, ir_type type, ir_ref reg);
|
||||
void _ir_RSTORE(ir_ctx *ctx, ir_ref reg, ir_ref val);
|
||||
ir_ref _ir_LOAD(ir_ctx *ctx, ir_type type, ir_ref addr);
|
||||
void _ir_STORE(ir_ctx *ctx, ir_ref addr, ir_ref val);
|
||||
void _ir_VA_START(ir_ctx *ctx, ir_ref list);
|
||||
void _ir_VA_END(ir_ctx *ctx, ir_ref list);
|
||||
void _ir_VA_COPY(ir_ctx *ctx, ir_ref dst, ir_ref src);
|
||||
ir_ref _ir_VA_ARG(ir_ctx *ctx, ir_type type, ir_ref list);
|
||||
void _ir_START(ir_ctx *ctx);
|
||||
void _ir_ENTRY(ir_ctx *ctx, ir_ref src, ir_ref num);
|
||||
void _ir_BEGIN(ir_ctx *ctx, ir_ref src);
|
||||
|
34
ir_emit_c.c
34
ir_emit_c.c
@ -719,6 +719,17 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f)
|
||||
fprintf(f, "%s %s", ir_type_cname[insn->type], ir_get_str(ctx, insn->op2));
|
||||
}
|
||||
}
|
||||
if (ctx->flags & IR_VARARG_FUNC) {
|
||||
if (first) {
|
||||
first = 0;
|
||||
} else {
|
||||
fprintf(f, ", ");
|
||||
}
|
||||
fprintf(f, "...");
|
||||
}
|
||||
if (first) {
|
||||
fprintf(f, "void");
|
||||
}
|
||||
fprintf(f, ")\n{\n");
|
||||
|
||||
/* Emit declarations for local variables */
|
||||
@ -968,6 +979,29 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f)
|
||||
case IR_STORE:
|
||||
ir_emit_store(ctx, f, insn);
|
||||
break;
|
||||
case IR_VA_START:
|
||||
fprintf(f, "\tva_start(");
|
||||
ir_emit_ref(ctx, f, insn->op2);
|
||||
fprintf(f, ");\n");
|
||||
break;
|
||||
case IR_VA_END:
|
||||
fprintf(f, "\tva_end(");
|
||||
ir_emit_ref(ctx, f, insn->op2);
|
||||
fprintf(f, ");\n");
|
||||
break;
|
||||
case IR_VA_COPY:
|
||||
fprintf(f, "\tva_copy(");
|
||||
ir_emit_ref(ctx, f, insn->op2);
|
||||
fprintf(f, ", ");
|
||||
ir_emit_ref(ctx, f, insn->op3);
|
||||
fprintf(f, ");\n");
|
||||
break;
|
||||
case IR_VA_ARG:
|
||||
ir_emit_def_ref(ctx, f, i);
|
||||
fprintf(f, "va_arg(");
|
||||
ir_emit_ref(ctx, f, insn->op2);
|
||||
fprintf(f, ", %s)\n", ir_type_cname[insn->type]);
|
||||
break;
|
||||
default:
|
||||
IR_ASSERT(0 && "NIY instruction");
|
||||
ctx->status = IR_ERROR_UNSUPPORTED_CODE_RULE;
|
||||
|
@ -667,6 +667,14 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f)
|
||||
fprintf(f, "%s %%d%d", ir_type_llvm_name[insn->type], use);
|
||||
}
|
||||
}
|
||||
if (ctx->flags & IR_VARARG_FUNC) {
|
||||
if (first) {
|
||||
first = 0;
|
||||
} else {
|
||||
fprintf(f, ", ");
|
||||
}
|
||||
fprintf(f, "...");
|
||||
}
|
||||
fprintf(f, ")\n{\n");
|
||||
|
||||
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||
@ -898,6 +906,29 @@ static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f)
|
||||
case IR_VSTORE:
|
||||
ir_emit_store(ctx, f, insn);
|
||||
break;
|
||||
case IR_VA_START:
|
||||
fprintf(f, "\tcall void @llvm.va_start(ptr ");
|
||||
ir_emit_ref(ctx, f, insn->op2);
|
||||
fprintf(f, ")\n");
|
||||
break;
|
||||
case IR_VA_END:
|
||||
fprintf(f, "\tcall void @llvm.va_end(ptr ");
|
||||
ir_emit_ref(ctx, f, insn->op2);
|
||||
fprintf(f, ")\n");
|
||||
break;
|
||||
case IR_VA_COPY:
|
||||
fprintf(f, "\tcall void @llvm.va_copy(ptr");
|
||||
ir_emit_ref(ctx, f, insn->op2);
|
||||
fprintf(f, ", ptr ");
|
||||
ir_emit_ref(ctx, f, insn->op3);
|
||||
fprintf(f, ")\n");
|
||||
break;
|
||||
case IR_VA_ARG:
|
||||
ir_emit_def_ref(ctx, f, i);
|
||||
fprintf(f, "va_arg ptr ");
|
||||
ir_emit_ref(ctx, f, insn->op2);
|
||||
fprintf(f, ", %s\n", ir_type_cname[insn->type]);
|
||||
break;
|
||||
case IR_TRAP:
|
||||
fprintf(f, "\tcall void @llvm.debugtrap()\n");
|
||||
break;
|
||||
|
@ -471,6 +471,13 @@ static ir_type llvm2ir_overflow_type(LLVMTypeRef stype)
|
||||
return type;
|
||||
}
|
||||
|
||||
static void llvm2ir_va_arg(ir_ctx *ctx, LLVMValueRef insn)
|
||||
{
|
||||
ir_type type = llvm2ir_type(LLVMTypeOf(insn));
|
||||
ir_ref ref = ir_VA_ARG(type, llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type));
|
||||
ir_addrtab_add(ctx->binding, (uintptr_t)insn, ref);
|
||||
}
|
||||
|
||||
#define STR_START(name, name_len, str) (name_len >= strlen(str) && memcmp(name, str, strlen(str)) == 0)
|
||||
#define STR_EQUAL(name, name_len, str) (name_len == strlen(str) && memcmp(name, str, strlen(str)) == 0)
|
||||
|
||||
@ -751,11 +758,19 @@ static ir_ref llvm2ir_intrinsic(ir_ctx *ctx, LLVMValueRef insn, LLVMTypeRef ftyp
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 0), type),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 2), type));
|
||||
} else if (STR_EQUAL(name, name_len, "llvm.va_start")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
ir_VA_START(llvm2ir_op(ctx, LLVMGetOperand(insn, 0), IR_ADDR));
|
||||
return IR_NULL;
|
||||
} else if (STR_EQUAL(name, name_len, "llvm.va_end")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 1);
|
||||
ir_VA_END(llvm2ir_op(ctx, LLVMGetOperand(insn, 0), IR_ADDR));
|
||||
return IR_NULL;
|
||||
} else if (STR_EQUAL(name, name_len, "llvm.va_copy")) {
|
||||
// TODO:
|
||||
IR_ASSERT(count == 2);
|
||||
ir_VA_COPY(
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 0), IR_ADDR),
|
||||
llvm2ir_op(ctx, LLVMGetOperand(insn, 1), IR_ADDR));
|
||||
return IR_NULL;
|
||||
} else if (STR_START(name, name_len, "llvm.ctpop.")) {
|
||||
// TODO:
|
||||
} else if (STR_START(name, name_len, "llvm.ctlz.")) {
|
||||
@ -1687,6 +1702,9 @@ static int llvm2ir_func(ir_ctx *ctx, LLVMValueRef func)
|
||||
case LLVMFreeze:
|
||||
llvm2ir_freeze(ctx, insn);
|
||||
break;
|
||||
case LLVMVAArg:
|
||||
llvm2ir_va_arg(ctx, insn);
|
||||
break;
|
||||
case LLVMExtractValue:
|
||||
if (llvm2ir_extract(ctx, insn)) {
|
||||
break;
|
||||
|
@ -546,6 +546,11 @@ static bool ir_loader_func_process(ir_loader *loader, ir_ctx *ctx, const char *n
|
||||
fprintf(l->dump_file, ", %s", ir_type_cname[insn->type]);
|
||||
insn++;;
|
||||
}
|
||||
if (ctx->flags & IR_VARARG_FUNC) {
|
||||
fprintf(l->dump_file, ", ...");
|
||||
}
|
||||
} else if (ctx->flags & IR_VARARG_FUNC) {
|
||||
fprintf(l->dump_file, "...");
|
||||
} else {
|
||||
fprintf(l->dump_file, "void");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user