diff --git a/Makefile b/Makefile index 26563ac6..ba4617ee 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ OBJS_COMMON = $(BUILD_DIR)/ir.o $(BUILD_DIR)/ir_strtab.o $(BUILD_DIR)/ir_cfg.o \ $(BUILD_DIR)/ir_sccp.o $(BUILD_DIR)/ir_gcm.o $(BUILD_DIR)/ir_ra.o $(BUILD_DIR)/ir_emit.o \ $(BUILD_DIR)/ir_load.o $(BUILD_DIR)/ir_save.o $(BUILD_DIR)/ir_emit_c.o $(BUILD_DIR)/ir_dump.o \ $(BUILD_DIR)/ir_disasm.o $(BUILD_DIR)/ir_gdb.o $(BUILD_DIR)/ir_perf.o $(BUILD_DIR)/ir_check.o \ - $(BUILD_DIR)/ir_cpuinfo.o + $(BUILD_DIR)/ir_cpuinfo.o $(BUILD_DIR)/ir_emit_llvm.o OBJS_IR = $(BUILD_DIR)/ir_main.o OBJS_IR_TEST = $(BUILD_DIR)/ir_test.o EXAMPLE_EXES = $(EXAMPLES_BUILD_DIR)/0001-basic $(EXAMPLES_BUILD_DIR)/0001-while $(EXAMPLES_BUILD_DIR)/0005-basic-runner-func \ diff --git a/ir.c b/ir.c index 5acb2a59..3fed3c81 100644 --- a/ir.c +++ b/ir.c @@ -2205,20 +2205,23 @@ ir_type ir_get_return_type(ir_ctx *ctx) ir_ref ref; ir_insn *insn; uint8_t ret_type = 255; + ir_type type; /* Check all RETURN nodes */ ref = ctx->ir_base[1].op1; while (ref) { insn = &ctx->ir_base[ref]; if (insn->op == IR_RETURN) { + type = ctx->ir_base[insn->op2].type; +check_type: if (ret_type == 255) { if (insn->op2) { - ret_type = ctx->ir_base[insn->op2].type; + ret_type = type; } else { ret_type = IR_VOID; } } else if (insn->op2) { - if (ret_type != ctx->ir_base[insn->op2].type) { + if (ret_type != type) { IR_ASSERT(0 && "conflicting return types"); return IR_VOID; } @@ -2228,6 +2231,12 @@ ir_type ir_get_return_type(ir_ctx *ctx) return IR_VOID; } } + } else if (insn->op == IR_UNREACHABLE) { + insn = &ctx->ir_base[insn->op1]; + if (insn->op == IR_TAILCALL) { + type = insn->type; + goto check_type; + } } ref = ctx->ir_base[ref].op3; } diff --git a/ir.h b/ir.h index a63e5eff..939f8bd3 100644 --- a/ir.h +++ b/ir.h @@ -484,7 +484,7 @@ void ir_strtab_free(ir_strtab *strtab); #define IR_OPT_IN_SCCP (1<<19) #define IR_LINEAR (1<<20) #define IR_GEN_NATIVE (1<<21) -#define IR_GEN_C (1<<22) +#define IR_GEN_CODE (1<<22) /* C or LLVM */ /* Temporary: SCCP -> CFG */ #define IR_SCCP_DONE (1<<25) @@ -763,7 +763,10 @@ void ir_dump_live_ranges(const ir_ctx *ctx, FILE *f); void ir_dump_codegen(const ir_ctx *ctx, FILE *f); /* IR to C conversion (implementation in ir_emit_c.c) */ -int ir_emit_c(ir_ctx *ctx, FILE *f); +int ir_emit_c(ir_ctx *ctx, const char *name, FILE *f); + +/* IR to LLVM conversion (implementation in ir_emit_llvm.c) */ +int ir_emit_llvm(ir_ctx *ctx, const char *name, FILE *f); /* IR verification API (implementation in ir_check.c) */ bool ir_check(const ir_ctx *ctx); diff --git a/ir_check.c b/ir_check.c index 9e68d034..6dbb898d 100644 --- a/ir_check.c +++ b/ir_check.c @@ -168,6 +168,10 @@ bool ir_check(const ir_ctx *ctx) /* second argument of SHIFT may be incompatible with result */ break; } + if (insn->op == IR_NOT && insn->type == IR_BOOL) { + /* bolean not */ + break; + } if (sizeof(void*) == 8) { if (insn->type == IR_ADDR && use_insn->type == IR_U64) { break; diff --git a/ir_emit_c.c b/ir_emit_c.c index 5eaf95e0..801aa0d3 100644 --- a/ir_emit_c.c +++ b/ir_emit_c.c @@ -554,7 +554,7 @@ static void ir_emit_tailcall(ir_ctx *ctx, FILE *f, ir_insn *insn) } fprintf(f, ");\n"); if (insn->type == IR_VOID) { - fprintf(f, "\treturn;"); + fprintf(f, "\treturn;\n"); } } @@ -613,7 +613,7 @@ static void ir_emit_store(ir_ctx *ctx, FILE *f, ir_insn *insn) fprintf(f, ";\n"); } -static int ir_emit_func(ir_ctx *ctx, FILE *f) +static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f) { ir_ref i, n, *p; ir_insn *insn; @@ -642,7 +642,7 @@ static int ir_emit_func(ir_ctx *ctx, FILE *f) /* Emit function prototype */ fprintf(f, "%s", ir_type_cname[ret_type]); - fprintf(f, " test("); + fprintf(f, " %s(", name); if (has_params) { use_list = &ctx->use_lists[1]; n = use_list->count; @@ -849,7 +849,7 @@ static int ir_emit_func(ir_ctx *ctx, FILE *f) IR_ASSERT(bb->successors_count == 0); fprintf(f, "\treturn"); if (!insn->op2) { - fprintf(f, ";"); + fprintf(f, ";\n"); } else { fprintf(f, " "); ir_emit_ref(ctx, f, insn->op2); @@ -914,7 +914,7 @@ static int ir_emit_func(ir_ctx *ctx, FILE *f) return 1; } -int ir_emit_c(ir_ctx *ctx, FILE *f) +int ir_emit_c(ir_ctx *ctx, const char *name, FILE *f) { - return ir_emit_func(ctx, f); + return ir_emit_func(ctx, name, f); } diff --git a/ir_emit_llvm.c b/ir_emit_llvm.c new file mode 100644 index 00000000..0f4c9097 --- /dev/null +++ b/ir_emit_llvm.c @@ -0,0 +1,811 @@ +/* + * IR - Lightweight JIT Compilation Framework + * (LLVM code generator) + * Copyright (C) 2022 Zend by Perforce. + * Authors: Dmitry Stogov + */ + +#include "ir.h" +#include "ir_private.h" + +#include + +static const char *ir_type_llvm_name[IR_LAST_TYPE] = { + "void", // IR_VOID + "i1", // IR_BOOL + "i8", // IR_U8 + "i16", // IR_U16 + "i32", // IR_U32 + "i64", // IR_U63 + "ptr", // IR_ADDR + "i8", // IR_CHAR + "i8", // IR_I8 + "i16", // IR_I16 + "i32", // IR_I32 + "i64", // IR_I64 + "double", // IR_DOUBLE + "float", // IR_FLOAT +}; + +static void ir_emit_ref(ir_ctx *ctx, FILE *f, ir_ref ref) +{ + if (IR_IS_CONST_REF(ref)) { + ir_insn *insn = &ctx->ir_base[ref]; + if (insn->op == IR_FUNC) { + fprintf(f, "@%s", ir_get_str(ctx, insn->val.i32)); + } else if (insn->op == IR_STR) { + fprintf(f, "@.str%d", -ref); + } else if (IR_IS_TYPE_FP(insn->type)) { + if (insn->type == IR_DOUBLE) { + if (isnan(insn->val.d)) { + fprintf(f, "nan"); + } else if (insn->val.d == 0.0) { + fprintf(f, "0.0"); + } else { + fprintf(f, "%g", insn->val.d); + } + } else { + IR_ASSERT(insn->type == IR_FLOAT); + if (isnan(insn->val.f)) { + fprintf(f, "nan"); + } else if (insn->val.f == 0.0) { + fprintf(f, "0.0"); + } else { + fprintf(f, "%e", insn->val.f); + } + } + } else { + ir_print_const(ctx, &ctx->ir_base[ref], f, true); + } + } else { + fprintf(f, "%%d%d", ref); + } +} + +static void ir_emit_def_ref(ir_ctx *ctx, FILE *f, ir_ref def) +{ + fprintf(f, "\t%%d%d = ", def); +} + +static void ir_emit_phi(ir_ctx *ctx, FILE *f, int def, ir_insn *insn, ir_block *bb) +{ + bool first = 1; + uint32_t j, n, *p; + + ir_emit_def_ref(ctx, f, def); + fprintf(f, "phi %s ", ir_type_llvm_name[insn->type]); + n = insn->inputs_count; + p = ctx->cfg_edges + bb->predecessors; + for (j = 2; j <= n; j++) { + if (first) { + first = 0; + } else { + fprintf(f, ", "); + } + fprintf(f, "["); + ir_emit_ref(ctx, f, ir_insn_op(insn, j)); + fprintf(f, ", %%l%d", *p); + p++; + fprintf(f, "]"); + } + fprintf(f, "\n"); +} + +static void ir_emit_unary_neg(ir_ctx *ctx, FILE *f, int def, ir_insn *insn) +{ + ir_type type = insn->type; + + ir_emit_def_ref(ctx, f, def); + if (IR_IS_TYPE_FP(type)) { + fprintf(f, "fneg %s ", ir_type_llvm_name[type]); + } else { + fprintf(f, "sub %s 0, ", ir_type_llvm_name[type]); + } + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, "\n"); +} + +static void ir_emit_unary_not(ir_ctx *ctx, FILE *f, int def, ir_insn *insn) +{ + ir_type type = ctx->ir_base[insn->op1].type; + + ir_emit_def_ref(ctx, f, def); + if (insn->type == IR_BOOL) { + if (IR_IS_TYPE_FP(type)) { + fprintf(f, "fcmp oeq %s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", 0.0\n"); + } else { + fprintf(f, "icmp eq %s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", 0\n"); + } + } else { + IR_ASSERT(IR_IS_TYPE_INT(type) && type == insn->type); + fprintf(f, "xor %s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", -1\n"); + } +} + +static void ir_emit_binary_op(ir_ctx *ctx, FILE *f, int def, ir_insn *insn, const char *op, const char *uop, const char *fop) +{ + ir_type type = ctx->ir_base[insn->op1].type; + + ir_emit_def_ref(ctx, f, def); + if (fop && IR_IS_TYPE_FP(type)) { + fprintf(f, "%s ", fop); + } else { + IR_ASSERT(IR_IS_TYPE_INT(type)); + if (uop && IR_IS_TYPE_UNSIGNED(type)) { + fprintf(f, "%s ", uop); + } else { + fprintf(f, "%s ", op); + } + } + fprintf(f, "%s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", "); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, "\n"); +} + +static void ir_emit_binary_overflow_op(ir_ctx *ctx, FILE *f, int def, ir_insn *insn, const char *op, const char *uop) +{ + ir_type type = insn->type; + + IR_ASSERT(IR_IS_TYPE_INT(type)); + fprintf(f, "\t%%t%d = call {%s, i1} @llvm.%s.with.overflow.%s(%s ", def, ir_type_llvm_name[type], + IR_IS_TYPE_UNSIGNED(type) ? uop : op, + ir_type_llvm_name[type], ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", %s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, ")\n"); + + ir_emit_def_ref(ctx, f, def); + fprintf(f, "extractvalue {%s, i1} %%t%d, 0\n", ir_type_llvm_name[type], def); +} + +static void ir_emit_rol_ror(ir_ctx *ctx, FILE *f, int def, ir_insn *insn, const char *op1, const char *op2) +{ + ir_type type = ctx->ir_base[insn->op1].type; + + ir_emit_def_ref(ctx, f, def); + fprintf(f, "call %s @llvm.%s.%s(%s ", + ir_type_llvm_name[type], insn->op == IR_ROL ? "fshl" : "fshr", ir_type_llvm_name[type], ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", %s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", %s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, ")\n"); +} + +static void ir_emit_bswap(ir_ctx *ctx, FILE *f, int def, ir_insn *insn) +{ + ir_type type = insn->type; + + ir_emit_def_ref(ctx, f, def); + fprintf(f, "call %s @llvm.bswap.%s(%s ", + ir_type_llvm_name[type], ir_type_llvm_name[type], ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ")\n"); +} + +static void ir_emit_conv(ir_ctx *ctx, FILE *f, int def, ir_insn *insn, const char *op) +{ + ir_emit_def_ref(ctx, f, def); + fprintf(f, "%s %s ", op, ir_type_llvm_name[ctx->ir_base[insn->op1].type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, " to %s\n", ir_type_llvm_name[insn->type]); +} + +static void ir_emit_minmax_op(ir_ctx *ctx, FILE *f, int def, ir_insn *insn) +{ + ir_type type = insn->type; + + ir_emit_def_ref(ctx, f, def); + if (IR_IS_TYPE_FP(type)) { + fprintf(f, "call %s @llvm.%s.%s(%s ", ir_type_llvm_name[type], + insn->op == IR_MIN ? "minnum" : "maxnum", type == IR_DOUBLE ? "f64" : "f32", + ir_type_llvm_name[type]); + } else { + IR_ASSERT(IR_IS_TYPE_INT(type)); + if (IR_IS_TYPE_UNSIGNED(type)) { + fprintf(f, "call %s @llvm.%s.%s(%s ", ir_type_llvm_name[type], + insn->op == IR_MIN ? "umin" : "umax", ir_type_llvm_name[type], ir_type_llvm_name[type]); + } else { + fprintf(f, "call %s @llvm.%s.%s(%s ", ir_type_llvm_name[type], + insn->op == IR_MIN ? "smin" : "smax", ir_type_llvm_name[type], ir_type_llvm_name[type]); + } + } + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", %s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, ")\n"); +} + +static void ir_emit_conditional_op(ir_ctx *ctx, FILE *f, int def, ir_insn *insn) +{ + ir_type type = ctx->ir_base[insn->op1].type; + + ir_emit_def_ref(ctx, f, def); + if (type == IR_BOOL) { + fprintf(f, "select i1 "); + ir_emit_ref(ctx, f, insn->op1); + } else if (IR_IS_TYPE_FP(type)) { + fprintf(f, "\t%%t%d = fcmp une %s ", def, ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", 0.0\n"); + fprintf(f, "select i1 %%t%d", def); + } else { + fprintf(f, "\t%%t%d = icmp ne %s ", def, ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", 0\n"); + fprintf(f, "select i1 %%t%d", def); + } + + fprintf(f, ", %s ", ir_type_llvm_name[insn->type]); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, ", %s ", ir_type_llvm_name[insn->type]); + ir_emit_ref(ctx, f, insn->op3); + fprintf(f, "\n"); +} + +static void ir_emit_abs(ir_ctx *ctx, FILE *f, int def, ir_insn *insn) +{ + ir_type type = ctx->ir_base[insn->op1].type; + + ir_emit_def_ref(ctx, f, def); + if (IR_IS_TYPE_FP(type)) { + fprintf(f, "call %s @llvm.fabs.%s(%s ", + ir_type_llvm_name[type], type == IR_DOUBLE ? "f64" : "f32", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ")\n"); + } else { + fprintf(f, "call %s @llvm.abs.%s(%s ", + ir_type_llvm_name[type], ir_type_llvm_name[type], ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, ", i1 0)\n"); + } +} + +static void ir_emit_if(ir_ctx *ctx, FILE *f, uint32_t b, ir_ref def, ir_insn *insn) +{ + ir_type type = ctx->ir_base[insn->op2].type; + uint32_t true_block = 0, false_block = 0, next_block; + + ir_get_true_false_blocks(ctx, b, &true_block, &false_block, &next_block); + + // TODO: i1 @llvm.expect.i1(i1 , i1 ) ??? + + if (type == IR_BOOL) { + fprintf(f, "\tbr i1 "); + ir_emit_ref(ctx, f, insn->op2); + } else if (IR_IS_TYPE_FP(type)) { + fprintf(f, "\t%%t%d = fcmp une %s ", def, ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, ", 0.0\n"); + fprintf(f, "\tbr i1 %%t%d", def); + } else { + fprintf(f, "\t%%t%d = icmp ne %s ", def, ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, ", 0\n"); + fprintf(f, "\tbr i1 %%t%d", def); + } + fprintf(f, ", label %%l%d, label %%l%d\n", true_block, false_block); +} + +static void ir_emit_switch(ir_ctx *ctx, FILE *f, uint32_t b, ir_ref def, ir_insn *insn) +{ + ir_type type = ctx->ir_base[insn->op2].type; + ir_block *bb; + uint32_t n, *p, use_block; + ir_insn *use_insn; + + // TODO: i1 @llvm.expect.i1(i1 , i1 ) ??? + + fprintf(f, "\tswitch %s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op2); + + bb = &ctx->cfg_blocks[b]; + + p = &ctx->cfg_edges[bb->successors]; + for (n = bb->successors_count; n != 0; p++, n--) { + use_block = *p; + use_insn = &ctx->ir_base[ctx->cfg_blocks[use_block].start]; + if (use_insn->op == IR_CASE_DEFAULT) { + fprintf(f, ", label %%l%d", ir_skip_empty_target_blocks(ctx, use_block)); + break; + } else { + IR_ASSERT(use_insn->op == IR_CASE_VAL); + } + } + fprintf(f, " [\n"); + p = &ctx->cfg_edges[bb->successors]; + for (n = bb->successors_count; n != 0; p++, n--) { + use_block = *p; + use_insn = &ctx->ir_base[ctx->cfg_blocks[use_block].start]; + if (use_insn->op == IR_CASE_VAL) { + fprintf(f, "\t\t%s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, use_insn->op2); + fprintf(f, ", label %%l%d\n", ir_skip_empty_target_blocks(ctx, use_block)); + } else { + IR_ASSERT(use_insn->op == IR_CASE_DEFAULT); + } + } + fprintf(f, "\t]\n"); +} + +static void ir_emit_call(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn) +{ + int j, k, n; + + if (insn->type != IR_VOID) { + ir_emit_def_ref(ctx, f, def); + } else { + fprintf(f, "\t"); + } + if (insn->op == IR_TAILCALL) { + fprintf(f, "tail "); + } + fprintf(f, "call %s ", ir_type_llvm_name[insn->type]); + + // TODO: function prototype ??? + + if (IR_IS_CONST_REF(insn->op2)) { + fprintf(f, "@%s", ir_get_str(ctx, ctx->ir_base[insn->op2].val.i32)); + } else { + ir_emit_ref(ctx, f, insn->op2); + } + fprintf(f, "("); + n = insn->inputs_count; + for (j = 3; j <= n; j++) { + if (j != 3) { + fprintf(f, ", "); + } + k = ir_insn_op(insn, j); + fprintf(f, "%s ", ir_type_llvm_name[ctx->ir_base[k].type]); + ir_emit_ref(ctx, f, k); + } + fprintf(f, ")\n"); + if (insn->op == IR_TAILCALL) { + fprintf(f, "\tret %s", ir_type_llvm_name[insn->type]); + if (insn->type != IR_VOID) { + fprintf(f, " "); + ir_emit_ref(ctx, f, def); + } + fprintf(f, "\n"); + } +} + +static void ir_emit_ijmp(ir_ctx *ctx, FILE *f, ir_insn *insn) +{ + fprintf(f, "\tindirectbr ptr "); + 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); + fprintf(f, "alloca i8, %s ", ir_type_llvm_name[ctx->ir_base[insn->op2].type]); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, ", align 16\n"); +} + +static void ir_emit_vaddr(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn) +{ + ir_emit_def_ref(ctx, f, def); + fprintf(f, "bitcast ptr "); + ir_emit_ref(ctx, f, insn->op1); + fprintf(f, " to ptr\n"); +} + +static void ir_emit_load(ir_ctx *ctx, FILE *f, ir_ref def, ir_insn *insn) +{ + ir_emit_def_ref(ctx, f, def); + fprintf(f, "load %s, ptr ", ir_type_llvm_name[insn->type]); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, "\n"); +} + +static void ir_emit_store(ir_ctx *ctx, FILE *f, ir_insn *insn) +{ + ir_type type = ctx->ir_base[insn->op3].type; + + fprintf(f, "\tstore %s ", ir_type_llvm_name[type]); + ir_emit_ref(ctx, f, insn->op3); + fprintf(f, ", ptr "); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, "\n"); +} + +static bool may_be_used_by_phi(ir_ctx *ctx, ir_block *bb) +{ + if (bb->successors_count == 1) { + bb = &ctx->cfg_blocks[ctx->cfg_edges[bb->successors]]; + if (bb->predecessors_count > 1) { + ir_use_list *use_list = &ctx->use_lists[bb->start]; + ir_ref i, n, *p; + + n = use_list->count; + if (n > 1) { + for (i = 0, p = &ctx->use_edges[use_list->refs]; i < n; i++, p++) { + if (ctx->ir_base[*p].op == IR_PHI) { + return 1; + } + } + } + } + } + return 0; +} + +static int ir_emit_func(ir_ctx *ctx, const char *name, FILE *f) +{ + ir_ref i, n, *p, use; + ir_insn *insn; + ir_use_list *use_list; + uint8_t ret_type; + bool has_params = 0; + uint32_t b, target; + ir_block *bb; + + ret_type = ir_get_return_type(ctx); + + if (!ctx->prev_ref) { + ir_build_prev_refs(ctx); + } + + use_list = &ctx->use_lists[1]; + n = use_list->count; + for (i = 0, p = &ctx->use_edges[use_list->refs]; i < n; i++, p++) { + insn = &ctx->ir_base[*p]; + if (insn->op == IR_PARAM) { + has_params = 1; + break; + } + } + + /* Emit function prototype */ + fprintf(f, "define %s", ir_type_llvm_name[ret_type]); + fprintf(f, " @%s(", name); + if (has_params) { + use_list = &ctx->use_lists[1]; + n = use_list->count; + for (i = 0, p = &ctx->use_edges[use_list->refs]; i < n; i++, p++) { + use = *p; + insn = &ctx->ir_base[use]; + if (insn->op == IR_PARAM) { + if (has_params) { + has_params = 0; + } else { + fprintf(f, ", "); + } + fprintf(f, "%s %%d%d", ir_type_llvm_name[insn->type], use); + } + } + } + fprintf(f, ")\n{\n"); + + for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) { + IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE)); + if ((bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_EMPTY)) == IR_BB_EMPTY) { + continue; + } + if (bb->predecessors_count > 0 || may_be_used_by_phi(ctx, bb)) { + fprintf(f, "l%d:\n", b); + } + for (i = bb->start, insn = ctx->ir_base + i; i <= bb->end;) { + switch (insn->op) { + case IR_START: + case IR_BEGIN: + case IR_IF_TRUE: + case IR_IF_FALSE: + case IR_CASE_VAL: + case IR_CASE_DEFAULT: + case IR_MERGE: + case IR_LOOP_BEGIN: + case IR_UNREACHABLE: + case IR_PARAM: + /* skip */ + break; + case IR_PHI: + ir_emit_phi(ctx, f, i, insn, bb); + break; + case IR_VAR: + ir_use_list *use_list = &ctx->use_lists[i]; + if (use_list->count > 0) { + fprintf(f, "\t%%d%d = alloca %s\n", i, ir_type_llvm_name[insn->type]); + } + break; + case IR_EQ: + ir_emit_binary_op(ctx, f, i, insn, "icmp eq", NULL, "fcmp oeq"); + break; + case IR_NE: + ir_emit_binary_op(ctx, f, i, insn, "icmp ne", NULL, "fcmp une"); + break; + case IR_LT: + ir_emit_binary_op(ctx, f, i, insn, "icmp slt", "icmp ult", "fcmp olt"); + break; + case IR_GE: + ir_emit_binary_op(ctx, f, i, insn, "icmp sge", "icmp uge", "fcmp oge"); + break; + case IR_LE: + ir_emit_binary_op(ctx, f, i, insn, "icmp sle", "icmp ule", "fcmp ole"); + break; + case IR_GT: + ir_emit_binary_op(ctx, f, i, insn, "icmp sgt", "icmp ugt", "fcmp ogt"); + break; + case IR_ULT: + ir_emit_binary_op(ctx, f, i, insn, "icmp ult", NULL, "fcmp ult"); + break; + case IR_UGE: + ir_emit_binary_op(ctx, f, i, insn, "icmp uge", NULL, "fcmp uge"); + break; + case IR_ULE: + ir_emit_binary_op(ctx, f, i, insn, "icmp ule", NULL, "fcmp ule"); + break; + case IR_UGT: + ir_emit_binary_op(ctx, f, i, insn, "icmp ugt", NULL, "fcmp ugt"); + break; + case IR_ADD: + ir_emit_binary_op(ctx, f, i, insn, "add", NULL, "fadd"); + break; + case IR_SUB: + ir_emit_binary_op(ctx, f, i, insn, "sub", NULL, "fsub"); + break; + case IR_MUL: + ir_emit_binary_op(ctx, f, i, insn, "mul", NULL, "fmul"); + break; + case IR_DIV: + ir_emit_binary_op(ctx, f, i, insn, "sdiv", "udiv", "fdiv"); + break; + case IR_MOD: + ir_emit_binary_op(ctx, f, i, insn, "srem", "urem", NULL); + break; + case IR_NEG: + ir_emit_unary_neg(ctx, f, i, insn); + break; + case IR_NOT: + ir_emit_unary_not(ctx, f, i, insn); + break; + case IR_OR: + ir_emit_binary_op(ctx, f, i, insn, "or", NULL, NULL); + break; + case IR_AND: + ir_emit_binary_op(ctx, f, i, insn, "and", NULL, NULL); + break; + case IR_XOR: + ir_emit_binary_op(ctx, f, i, insn, "xor", NULL, NULL); + break; + case IR_MIN: + case IR_MAX: + ir_emit_minmax_op(ctx, f, i, insn); + break; + case IR_COND: + ir_emit_conditional_op(ctx, f, i, insn); + break; + case IR_ABS: + ir_emit_abs(ctx, f, i, insn); + break; + case IR_SHL: + ir_emit_binary_op(ctx, f, i, insn, "shl", NULL, NULL); + break; + case IR_SHR: + ir_emit_binary_op(ctx, f, i, insn, "lshr", NULL, NULL); + break; + case IR_SAR: + ir_emit_binary_op(ctx, f, i, insn, "ashr", NULL, NULL); + break; + case IR_ROL: + ir_emit_rol_ror(ctx, f, i, insn, "<<", ">>"); + break; + case IR_ROR: + ir_emit_rol_ror(ctx, f, i, insn, ">>", "<<"); + break; + case IR_BSWAP: + ir_emit_bswap(ctx, f, i, insn); + break; + case IR_SEXT: + IR_ASSERT(IR_IS_TYPE_INT(insn->type)); + IR_ASSERT(IR_IS_TYPE_INT(ctx->ir_base[insn->op1].type)); + IR_ASSERT(ir_type_size[insn->type] > ir_type_size[ctx->ir_base[insn->op1].type]); + ir_emit_conv(ctx, f, i, insn, "sext"); + break; + case IR_ZEXT: + IR_ASSERT(IR_IS_TYPE_INT(insn->type)); + IR_ASSERT(IR_IS_TYPE_INT(ctx->ir_base[insn->op1].type)); + IR_ASSERT(ir_type_size[insn->type] > ir_type_size[ctx->ir_base[insn->op1].type]); + ir_emit_conv(ctx, f, i, insn, "zext"); + break; + case IR_TRUNC: + IR_ASSERT(IR_IS_TYPE_INT(insn->type)); + IR_ASSERT(IR_IS_TYPE_INT(ctx->ir_base[insn->op1].type)); + IR_ASSERT(ir_type_size[insn->type] < ir_type_size[ctx->ir_base[insn->op1].type]); + ir_emit_conv(ctx, f, i, insn, "trunc"); + break; + case IR_BITCAST: + if (insn->type == IR_ADDR + && IR_IS_TYPE_INT(ctx->ir_base[insn->op1].type) + && ctx->ir_base[insn->op1].type != IR_ADDR) { + ir_emit_conv(ctx, f, i, insn, "inttoptr"); + } else if (ctx->ir_base[insn->op1].type == IR_ADDR + && IR_IS_TYPE_INT(insn->type) + && insn->type != IR_ADDR) { + ir_emit_conv(ctx, f, i, insn, "ptrtoint"); + } else { + ir_emit_conv(ctx, f, i, insn, "bitcast"); + } + break; + case IR_INT2FP: + IR_ASSERT(IR_IS_TYPE_FP(insn->type)); + IR_ASSERT(IR_IS_TYPE_INT(ctx->ir_base[insn->op1].type)); + ir_emit_conv(ctx, f, i, insn, IR_IS_TYPE_UNSIGNED(ctx->ir_base[insn->op1].type) ? "uitofp" : "sitofp"); + break; + case IR_FP2INT: + IR_ASSERT(IR_IS_TYPE_INT(insn->type)); + IR_ASSERT(IR_IS_TYPE_FP(ctx->ir_base[insn->op1].type)); + ir_emit_conv(ctx, f, i, insn, IR_IS_TYPE_UNSIGNED(insn->type) ? "fptoui" : "fptosi"); + break; + case IR_FP2FP: + IR_ASSERT(IR_IS_TYPE_FP(insn->type)); + IR_ASSERT(IR_IS_TYPE_FP(ctx->ir_base[insn->op1].type)); + ir_emit_conv(ctx, f, i, insn, insn->type == IR_DOUBLE ? "fpext" : "fptrunc"); + break; + case IR_COPY: + ir_emit_conv(ctx, f, i, insn, "bitcast"); + break; + case IR_ADD_OV: + ir_emit_binary_overflow_op(ctx, f, i, insn, "sadd", "uadd"); + break; + case IR_SUB_OV: + ir_emit_binary_overflow_op(ctx, f, i, insn, "ssub", "usub"); + break; + case IR_MUL_OV: + ir_emit_binary_overflow_op(ctx, f, i, insn, "smul", "umul"); + break; + case IR_OVERFLOW: + ir_emit_def_ref(ctx, f, i); + fprintf(f, "extractvalue {%s, i1} %%t%d, 1\n", ir_type_llvm_name[ctx->ir_base[insn->op1].type], insn->op1); + break; + case IR_RETURN: + IR_ASSERT(bb->successors_count == 0); + if (!insn->op2) { + fprintf(f, "\tret void\n"); + } else { + fprintf(f, "\tret %s ", ir_type_llvm_name[ctx->ir_base[insn->op2].type]); + ir_emit_ref(ctx, f, insn->op2); + fprintf(f, "\n"); + } + break; + case IR_END: + case IR_LOOP_END: + IR_ASSERT(bb->successors_count == 1); + target = ir_skip_empty_target_blocks(ctx, ctx->cfg_edges[bb->successors]); + fprintf(f, "\tbr label %%l%d\n", target); + break; + case IR_IF: + ir_emit_if(ctx, f, b, i, insn); + break; + case IR_SWITCH: + ir_emit_switch(ctx, f, b, i, insn); + break; + case IR_CALL: + case IR_TAILCALL: + ir_emit_call(ctx, f, i, insn); + break; + case IR_IJMP: + ir_emit_ijmp(ctx, f, insn); + break; + case IR_ALLOCA: + ir_emit_alloca(ctx, f, i, insn); + break; + case IR_VADDR: + ir_emit_vaddr(ctx, f, i, insn); + break; + case IR_LOAD: + case IR_VLOAD: + ir_emit_load(ctx, f, i, insn); + break; + case IR_STORE: + case IR_VSTORE: + ir_emit_store(ctx, f, insn); + break; + case IR_TRAP: + fprintf(f, "\tcall void @llvm.debugtrap()\n"); + break; + case IR_RLOAD: + case IR_RSTORE: + case IR_TLS: + case IR_GUARD: + case IR_GUARD_NOT: + default: + IR_ASSERT(0 && "NIY instruction"); + ctx->status = IR_ERROR_UNSUPPORTED_CODE_RULE; + return 0; + } + n = ir_insn_len(insn); + i += n; + insn += n; + } + } + + fprintf(f, "}\n"); + + for (i = IR_UNUSED + 1, insn = ctx->ir_base - i; i < ctx->consts_count; i++, insn--) { + if (insn->op == IR_FUNC) { + // TODO: function prototype ??? + fprintf(f, "declare void @%s()\n", ir_get_str(ctx, insn->val.i32)); + } else if (insn->op == IR_STR) { + const char *str = ir_get_str(ctx, insn->val.i32); + // TODO: strlen != size ??? + int len = strlen(str); + int j; + + fprintf(f, "@.str%d = private unnamed_addr constant [%d x i8] c\"", i, len + 1); + for (j = 0; j < len; j++) { + char c = str[j]; + + if (c == '\\') { + if (str[j+1] == '\\') { + j++; + c = '\\'; + } else if (str[j+1] == '\'') { + j++; + c = '\''; + } else if (str[j+1] == '"') { + j++; + c = '"'; + } else if (str[j+1] == 'a') { + j++; + c = '\a'; + } else if (str[j+1] == 'b') { + j++; + c = '\b'; + } else if (str[j+1] == 'e') { + j++; + c = 27; /* '\e'; */ + } else if (str[j+1] == 'f') { + j++; + c = '\f'; + } else if (str[j+1] == 'n') { + j++; + c = '\n'; + } else if (str[j+1] == 'r') { + j++; + c = '\r'; + } else if (str[j+1] == 't') { + j++; + c = '\t'; + } else if (str[j+1] == 'v') { + j++; + c = '\v'; + } else if (str[j+1] == '?') { + j++; + c = 0x3f; + } + } + if (c < ' ' || c >= 127) { + char c1 = c >> 8; + char c2 = c & 15; + c1 = (c1 < 10) ? (c1 + '0') : (c1 - 10 + 'A'); + c2 = (c2 < 10) ? (c2 + '0') : (c2 - 10 + 'A'); + fprintf(f, "\\%c%c", c1, c2); + } else { + fprintf(f, "%c", c); + } + } + fprintf(f, "\\00\"\n"); + } + } + + return 1; +} + +int ir_emit_llvm(ir_ctx *ctx, const char *name, FILE *f) +{ + return ir_emit_func(ctx, name, f); +} diff --git a/ir_main.c b/ir_main.c index 8acd4786..e66f8f62 100644 --- a/ir_main.c +++ b/ir_main.c @@ -25,6 +25,7 @@ static void help(const char *cmd) #endif " -muse-fp - use base frame pointer register\n" " --emit-c [file-name] - convert to C source\n" + " --emit-llvm [file-name] - convert to LLVM\n" " --save [file-name] - save IR\n" " --dot [file-name] - dump IR graph\n" " --dump [file-name] - dump IR table\n" @@ -152,7 +153,7 @@ int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, const char *dump_ return 0; } - if (opt_level > 0 || (ctx->flags & (IR_GEN_NATIVE|IR_GEN_C))) { + if (opt_level > 0 || (ctx->flags & (IR_GEN_NATIVE|IR_GEN_CODE))) { ir_build_def_use_lists(ctx); } @@ -167,7 +168,7 @@ int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, const char *dump_ } } - if (opt_level > 0 || (ctx->flags & (IR_GEN_NATIVE|IR_GEN_C))) { + if (opt_level > 0 || (ctx->flags & (IR_GEN_NATIVE|IR_GEN_CODE))) { ir_build_cfg(ctx); } @@ -212,7 +213,7 @@ int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, const char *dump_ } ir_schedule_blocks(ctx); - } else if (ctx->flags & (IR_GEN_NATIVE|IR_GEN_C)) { + } else if (ctx->flags & (IR_GEN_NATIVE|IR_GEN_CODE)) { ir_assign_virtual_registers(ctx); ir_compute_dessa_moves(ctx); } @@ -231,10 +232,10 @@ int main(int argc, char **argv) { int i; char *input = NULL; - char *dump_file = NULL, *c_file = NULL; + char *dump_file = NULL, *c_file = NULL, *llvm_file = 0; FILE *f; ir_ctx ctx; - bool emit_c = 0, dump_asm = 0, run = 0; + bool emit_c = 0, emit_llvm = 0, dump_asm = 0, run = 0; uint32_t dump = 0; int opt_level = 2; uint32_t flags = 0; @@ -274,6 +275,12 @@ int main(int argc, char **argv) c_file = argv[i + 1]; i++; } + } else if (strcmp(argv[i], "--emit-llvm") == 0) { + emit_llvm = 1; + if (i + 1 < argc && argv[i + 1][0] != '-') { + llvm_file = argv[i + 1]; + i++; + } } else if (strcmp(argv[i], "--save") == 0) { // TODO: check save/dot/dump/... conflicts dump |= IR_DUMP_SAVE; @@ -411,8 +418,8 @@ int main(int argc, char **argv) if (opt_level > 0) { flags |= IR_OPT_FOLDING | IR_OPT_CFG | IR_OPT_CODEGEN; } - if (emit_c) { - flags |= IR_GEN_C; + if (emit_c || emit_llvm) { + flags |= IR_GEN_CODE; } if (dump_asm || run) { flags |= IR_GEN_NATIVE; @@ -443,7 +450,7 @@ int main(int argc, char **argv) } else { f = stderr; } - ret = ir_emit_c(&ctx, f); + ret = ir_emit_c(&ctx, "test", f); if (c_file) { fclose(f); } @@ -452,6 +459,27 @@ int main(int argc, char **argv) } } + if (emit_llvm) { + int ret; + + if (llvm_file) { + f = fopen(llvm_file, "w+"); + if (!f) { + fprintf(stderr, "ERROR: Cannot create file '%s'\n", llvm_file); + return 0; + } + } else { + f = stderr; + } + ret = ir_emit_llvm(&ctx, "test", f); + if (llvm_file) { + fclose(f); + } + if (!ret) { + fprintf(stderr, "\nERROR: %d\n", ctx.status); + } + } + if (dump_asm || run) { size_t size; void *entry = ir_emit_code(&ctx, &size); diff --git a/ir_ra.c b/ir_ra.c index ba469fbb..b6ec256b 100644 --- a/ir_ra.c +++ b/ir_ra.c @@ -837,8 +837,7 @@ int ir_compute_live_ranges(ir_ctx *ctx) ival = ctx->live_intervals[v]; } ir_add_use(ctx, ival, j, use_pos, reg, IR_USE_FLAGS(def_flags, j), hint_ref); - } else { - IR_ASSERT(ctx->rules); + } else if (ctx->rules) { if (ctx->rules[input] & IR_FUSED) { ir_add_fusion_ranges(ctx, ref, input, bb, live); } else if (ctx->rules[input] == (IR_SKIPPED|IR_RLOAD)) { @@ -1449,8 +1448,7 @@ int ir_compute_live_ranges(ir_ctx *ctx) ival = ctx->live_intervals[v]; } ir_add_use(ctx, ival, j, use_pos, reg, IR_USE_FLAGS(def_flags, j), hint_ref); - } else { - IR_ASSERT(ctx->rules); + } else if (ctx->rules) { if (ctx->rules[input] & IR_FUSED) { ir_add_fusion_ranges(ctx, ref, input, bb, live_in_block, b); } else { diff --git a/ir_x86.dasc b/ir_x86.dasc index 4a3ff44f..ab9d9aca 100644 --- a/ir_x86.dasc +++ b/ir_x86.dasc @@ -6436,19 +6436,19 @@ static void ir_emit_call(ir_ctx *ctx, ir_ref def, ir_insn *insn) if (sizeof(void*) == 4 || IR_MAY_USE_32BIT_ADDR(addr)) { | call aword &addr } else { - ir_reg tmp_reg = IR_REG_RAX; +|.if X64 +|| ir_reg tmp_reg = IR_REG_RAX; #ifdef IR_REG_VARARG_FP_REGS - if (ir_is_vararg(ctx, insn)) { - tmp_reg = IR_REG_R11; - } +|| if (ir_is_vararg(ctx, insn)) { +|| tmp_reg = IR_REG_R11; +|| } #endif -|.if X64 - if (IR_IS_SIGNED_32BIT(addr)) { +|| if (IR_IS_SIGNED_32BIT(addr)) { | mov Rq(tmp_reg), ((ptrdiff_t)addr) // 0x48 0xc7 0xc0 - } else { +|| } else { | mov64 Rq(tmp_reg), ((ptrdiff_t)addr) // 0x48 0xb8 - } +|| } | call Rq(tmp_reg) |.endif } @@ -6554,19 +6554,19 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) if (sizeof(void*) == 4 || IR_MAY_USE_32BIT_ADDR(addr)) { | jmp aword &addr } else { - ir_reg tmp_reg = IR_REG_RAX; +|.if X64 +|| ir_reg tmp_reg = IR_REG_RAX; #ifdef IR_REG_VARARG_FP_REGS - if (ir_is_vararg(ctx, insn)) { - tmp_reg = IR_REG_R11; - } +|| if (ir_is_vararg(ctx, insn)) { +|| tmp_reg = IR_REG_R11; +|| } #endif -|.if X64 - if (IR_IS_SIGNED_32BIT(addr)) { +|| if (IR_IS_SIGNED_32BIT(addr)) { | mov Rq(tmp_reg), ((ptrdiff_t)addr) // 0x48 0xc7 0xc0 - } else { +|| } else { | mov64 Rq(tmp_reg), ((ptrdiff_t)addr) // 0x48 0xb8 - } +|| } | jmp Rq(tmp_reg) |.endif } diff --git a/tests/c/conv_007.irt b/tests/c/conv_007.irt index 1f454e5d..546fba40 100644 --- a/tests/c/conv_007.irt +++ b/tests/c/conv_007.irt @@ -6,7 +6,7 @@ { l_1 = START(l_4); float x = PARAM(l_1, "x", 1); - uint32_t ret = INT2FP(x); + uint32_t ret = FP2INT(x); l_4 = RETURN(l_1, ret); } --EXPECT-- diff --git a/tests/llvm/abs_001.irt b/tests/llvm/abs_001.irt new file mode 100644 index 00000000..4a2b297d --- /dev/null +++ b/tests/llvm/abs_001.irt @@ -0,0 +1,17 @@ +--TEST-- +001: abs function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t ret = ABS(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + %d3 = call i32 @llvm.abs.i32(i32 %d2, i1 0) + ret i32 %d3 +} diff --git a/tests/llvm/abs_002.irt b/tests/llvm/abs_002.irt new file mode 100644 index 00000000..92e82979 --- /dev/null +++ b/tests/llvm/abs_002.irt @@ -0,0 +1,17 @@ +--TEST-- +002: abs function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double ret = ABS(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(double %d2) +{ + %d3 = call double @llvm.fabs.f64(double %d2) + ret double %d3 +} diff --git a/tests/llvm/add_001.irt b/tests/llvm/add_001.irt new file mode 100644 index 00000000..ec5c832b --- /dev/null +++ b/tests/llvm/add_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: add function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = ADD(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = add i32 %d3, %d2 + ret i32 %d4 +} diff --git a/tests/llvm/add_011.irt b/tests/llvm/add_011.irt new file mode 100644 index 00000000..2a3aef67 --- /dev/null +++ b/tests/llvm/add_011.irt @@ -0,0 +1,18 @@ +--TEST-- +011: add function +--ARGS-- +--emit-llvm +--CODE-- +{ + double c = 0.5; + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double ret = ADD(x, c); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(double %d2) +{ + %d3 = fadd double %d2, 0.5 + ret double %d3 +} diff --git a/tests/llvm/add_ov_001.irt b/tests/llvm/add_ov_001.irt new file mode 100644 index 00000000..98f41556 --- /dev/null +++ b/tests/llvm/add_ov_001.irt @@ -0,0 +1,21 @@ +--TEST-- +001: add_ov function +--ARGS-- +--emit-llvm +--CODE-- +{ + int32_t c = 2; + l_1 = START(l_2); + int32_t x = PARAM(l_1, "x", 1); + int32_t ret = ADD_OV(x, c); + bool ov = OVERFLOW(ret); + l_2 = RETURN(l_1, ov); +} +--EXPECT-- +define i1 @test(i32 %d2) +{ + %t3 = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %d2, i32 2) + %d3 = extractvalue {i32, i1} %t3, 0 + %d4 = extractvalue {i32, i1} %t3, 1 + ret i1 %d4 +} diff --git a/tests/llvm/add_ov_002.irt b/tests/llvm/add_ov_002.irt new file mode 100644 index 00000000..62310b1d --- /dev/null +++ b/tests/llvm/add_ov_002.irt @@ -0,0 +1,21 @@ +--TEST-- +002: add_ov function +--ARGS-- +--emit-llvm +--CODE-- +{ + uint32_t c = 2; + l_1 = START(l_2); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t ret = ADD_OV(x, c); + bool ov = OVERFLOW(ret); + l_2 = RETURN(l_1, ov); +} +--EXPECT-- +define i1 @test(i32 %d2) +{ + %t3 = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %d2, i32 2) + %d3 = extractvalue {i32, i1} %t3, 0 + %d4 = extractvalue {i32, i1} %t3, 1 + ret i1 %d4 +} diff --git a/tests/llvm/add_ov_003.irt b/tests/llvm/add_ov_003.irt new file mode 100644 index 00000000..2db3b49d --- /dev/null +++ b/tests/llvm/add_ov_003.irt @@ -0,0 +1,36 @@ +--TEST-- +003: add_ov function +--ARGS-- +--emit-llvm +--CODE-- +{ + int32_t c_1 = 0; + int32_t c = 2; + l_1 = START(l_8); + int32_t x = PARAM(l_1, "x", 1); + int32_t ret1 = ADD_OV(x, c); + bool ov = OVERFLOW(ret1); + l_2 = IF(l_1, ov); + l_3 = IF_TRUE(l_2); + l_4 = END(l_3); + l_5 = IF_FALSE(l_2); + l_6 = END(l_5); + l_7 = MERGE(l_4, l_6); + int32_t ret = PHI(l_7, c_1, ret1); + l_8 = RETURN(l_7, ret); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + %t3 = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %d2, i32 2) + %d3 = extractvalue {i32, i1} %t3, 0 + %d4 = extractvalue {i32, i1} %t3, 1 + br i1 %d4, label %l2, label %l4 +l2: + br label %l3 +l3: + %d11 = phi i32 [0, %l2], [%d3, %l4] + ret i32 %d11 +l4: + br label %l3 +} diff --git a/tests/llvm/add_ov_004.irt b/tests/llvm/add_ov_004.irt new file mode 100644 index 00000000..ee38b2b0 --- /dev/null +++ b/tests/llvm/add_ov_004.irt @@ -0,0 +1,36 @@ +--TEST-- +004: add_ov function (jmp probability) +--ARGS-- +--emit-llvm +--CODE-- +{ + int32_t c_1 = 0; + int32_t c = 2; + l_1 = START(l_8); + int32_t x = PARAM(l_1, "x", 1); + int32_t ret1 = ADD_OV(x, c); + bool ov = OVERFLOW(ret1); + l_2 = IF(l_1, ov); + l_3 = IF_TRUE(l_2, 1); + l_4 = END(l_3); + l_5 = IF_FALSE(l_2); + l_6 = END(l_5); + l_7 = MERGE(l_4, l_6); + int32_t ret = PHI(l_7, c_1, ret1); + l_8 = RETURN(l_7, ret); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + %t3 = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %d2, i32 2) + %d3 = extractvalue {i32, i1} %t3, 0 + %d4 = extractvalue {i32, i1} %t3, 1 + br i1 %d4, label %l4, label %l2 +l2: + br label %l3 +l3: + %d11 = phi i32 [0, %l4], [%d3, %l2] + ret i32 %d11 +l4: + br label %l3 +} diff --git a/tests/llvm/alloca_001.irt b/tests/llvm/alloca_001.irt new file mode 100644 index 00000000..9c6e2d3f --- /dev/null +++ b/tests/llvm/alloca_001.irt @@ -0,0 +1,17 @@ +--TEST-- +001: alloca function +--ARGS-- +--emit-llvm +--CODE-- +{ + int32_t size = 10; + l_1 = START(l_4); + uintptr_t ret, l_2 = ALLOCA(l_1, size); + l_4 = RETURN(l_2, ret); +} +--EXPECT-- +define ptr @test() +{ + %d2 = alloca i8, i32 10, align 16 + ret ptr %d2 +} diff --git a/tests/llvm/alloca_002.irt b/tests/llvm/alloca_002.irt new file mode 100644 index 00000000..a9a0c516 --- /dev/null +++ b/tests/llvm/alloca_002.irt @@ -0,0 +1,17 @@ +--TEST-- +002: alloca function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + uintptr_t ret, l_2 = ALLOCA(l_1, x); + l_4 = RETURN(l_2, ret); +} +--EXPECT-- +define ptr @test(i32 %d2) +{ + %d3 = alloca i8, i32 %d2, align 16 + ret ptr %d3 +} diff --git a/tests/llvm/bswap_001.irt b/tests/llvm/bswap_001.irt new file mode 100644 index 00000000..244ef8c2 --- /dev/null +++ b/tests/llvm/bswap_001.irt @@ -0,0 +1,17 @@ +--TEST-- +001: bswap function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t ret = BSWAP(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + %d3 = call i32 @llvm.bswap.i32(i32 %d2) + ret i32 %d3 +} diff --git a/tests/llvm/call_001.irt b/tests/llvm/call_001.irt new file mode 100644 index 00000000..58d9cbe7 --- /dev/null +++ b/tests/llvm/call_001.irt @@ -0,0 +1,24 @@ +--TEST-- +Simple CALL +--ARGS-- +--emit-llvm +--CODE-- +{ + uintptr_t c_1 = 0; + bool c_2 = 0; + bool c_3 = 1; + int32_t c_4 = 42; + uintptr_t c_5 = func(printf, 4); + uintptr_t c_6 = "hello %d!\n"; + l_1 = START(l_4); + int32_t d_2, l_2 = CALL/2(l_1, c_5, c_6, c_4); + l_4 = RETURN(l_2, d_2); +} +--EXPECT-- +define i32 @test() +{ + %d2 = call i32 @printf(ptr @.str6, i32 42) + ret i32 %d2 +} +declare void @printf() +@.str6 = private unnamed_addr constant [12 x i8] c"hello %d!\0A\00" diff --git a/tests/llvm/call_002.irt b/tests/llvm/call_002.irt new file mode 100644 index 00000000..b6e9e44d --- /dev/null +++ b/tests/llvm/call_002.irt @@ -0,0 +1,20 @@ +--TEST-- +Indirect CALL +--ARGS-- +--emit-llvm +--CODE-- +{ + uintptr_t c_6 = "hello %d!\n"; + l_1 = START(l_4); + uintptr_t f = PARAM(l_1, "f", 1); + int32_t p = PARAM(l_1, "p", 2); + int32_t d_2, l_2 = CALL/2(l_1, f, c_6, p); + l_4 = RETURN(l_2, d_2); +} +--EXPECT-- +define i32 @test(ptr %d2, i32 %d3) +{ + %d4 = call i32 %d2(ptr @.str4, i32 %d3) + ret i32 %d4 +} +@.str4 = private unnamed_addr constant [12 x i8] c"hello %d!\0A\00" diff --git a/tests/llvm/cond_01.irt b/tests/llvm/cond_01.irt new file mode 100644 index 00000000..080e287c --- /dev/null +++ b/tests/llvm/cond_01.irt @@ -0,0 +1,19 @@ +--TEST-- +001: cond function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool z = PARAM(l_1, "z", 3); + int32_t ret = COND(z, x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3, i1 %d4) +{ + %d5 = select i1 %d4, i32 %d2, i32 %d3 + ret i32 %d5 +} diff --git a/tests/llvm/conv_001.irt b/tests/llvm/conv_001.irt new file mode 100644 index 00000000..c741dade --- /dev/null +++ b/tests/llvm/conv_001.irt @@ -0,0 +1,17 @@ +--TEST-- +001: type conversion SEXT +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int64_t ret = SEXT(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i64 @test(i32 %d2) +{ + %d3 = sext i32 %d2 to i64 + ret i64 %d3 +} diff --git a/tests/llvm/conv_002.irt b/tests/llvm/conv_002.irt new file mode 100644 index 00000000..23480600 --- /dev/null +++ b/tests/llvm/conv_002.irt @@ -0,0 +1,17 @@ +--TEST-- +002: type conversion ZEXT +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint64_t ret = ZEXT(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i64 @test(i32 %d2) +{ + %d3 = zext i32 %d2 to i64 + ret i64 %d3 +} diff --git a/tests/llvm/conv_003.irt b/tests/llvm/conv_003.irt new file mode 100644 index 00000000..c1f48729 --- /dev/null +++ b/tests/llvm/conv_003.irt @@ -0,0 +1,17 @@ +--TEST-- +003: type conversion BITCAST +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + uint32_t ret = BITCAST(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + %d3 = bitcast i32 %d2 to i32 + ret i32 %d3 +} diff --git a/tests/llvm/conv_004.irt b/tests/llvm/conv_004.irt new file mode 100644 index 00000000..78cf27bc --- /dev/null +++ b/tests/llvm/conv_004.irt @@ -0,0 +1,17 @@ +--TEST-- +004: type conversion BITCAST +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + uint64_t ret = BITCAST(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i64 @test(double %d2) +{ + %d3 = bitcast double %d2 to i64 + ret i64 %d3 +} diff --git a/tests/llvm/conv_005.irt b/tests/llvm/conv_005.irt new file mode 100644 index 00000000..e4675f9b --- /dev/null +++ b/tests/llvm/conv_005.irt @@ -0,0 +1,17 @@ +--TEST-- +005: type conversion BITCAST +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + float x = PARAM(l_1, "x", 1); + uint32_t ret = BITCAST(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(float %d2) +{ + %d3 = bitcast float %d2 to i32 + ret i32 %d3 +} diff --git a/tests/llvm/conv_006.irt b/tests/llvm/conv_006.irt new file mode 100644 index 00000000..d066e27a --- /dev/null +++ b/tests/llvm/conv_006.irt @@ -0,0 +1,17 @@ +--TEST-- +006: type conversion INT2FP +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + double ret = INT2FP(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(i32 %d2) +{ + %d3 = sitofp i32 %d2 to double + ret double %d3 +} diff --git a/tests/llvm/conv_007.irt b/tests/llvm/conv_007.irt new file mode 100644 index 00000000..671bd281 --- /dev/null +++ b/tests/llvm/conv_007.irt @@ -0,0 +1,17 @@ +--TEST-- +007: type conversion FP2INT +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + float x = PARAM(l_1, "x", 1); + uint32_t ret = FP2INT(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(float %d2) +{ + %d3 = fptoui float %d2 to i32 + ret i32 %d3 +} diff --git a/tests/llvm/conv_008.irt b/tests/llvm/conv_008.irt new file mode 100644 index 00000000..6ab7ae37 --- /dev/null +++ b/tests/llvm/conv_008.irt @@ -0,0 +1,17 @@ +--TEST-- +008: type conversion FP2FP +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + float x = PARAM(l_1, "x", 1); + double ret = FP2FP(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(float %d2) +{ + %d3 = fpext float %d2 to double + ret double %d3 +} diff --git a/tests/llvm/conv_009.irt b/tests/llvm/conv_009.irt new file mode 100644 index 00000000..af0882f2 --- /dev/null +++ b/tests/llvm/conv_009.irt @@ -0,0 +1,17 @@ +--TEST-- +009: type conversion FP2FP +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + float ret = FP2FP(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define float @test(double %d2) +{ + %d3 = fptrunc double %d2 to float + ret float %d3 +} diff --git a/tests/llvm/conv_010.irt b/tests/llvm/conv_010.irt new file mode 100644 index 00000000..cf0fa284 --- /dev/null +++ b/tests/llvm/conv_010.irt @@ -0,0 +1,17 @@ +--TEST-- +010: type conversion BITCAST +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint64_t x = PARAM(l_1, "x", 1); + double ret = BITCAST(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(i64 %d2) +{ + %d3 = bitcast i64 %d2 to double + ret double %d3 +} diff --git a/tests/llvm/conv_011.irt b/tests/llvm/conv_011.irt new file mode 100644 index 00000000..167152d6 --- /dev/null +++ b/tests/llvm/conv_011.irt @@ -0,0 +1,17 @@ +--TEST-- +011: type conversion TRUNC +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int8_t ret = TRUNC(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i8 @test(i32 %d2) +{ + %d3 = trunc i32 %d2 to i8 + ret i8 %d3 +} diff --git a/tests/llvm/copy_001.irt b/tests/llvm/copy_001.irt new file mode 100644 index 00000000..42e05c63 --- /dev/null +++ b/tests/llvm/copy_001.irt @@ -0,0 +1,17 @@ +--TEST-- +001: copy function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_2); + int32_t d_2 = PARAM(l_1, "x", 1); + int32_t d_3 = COPY(d_2, 1); + l_2 = RETURN(l_1, d_3); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + %d3 = bitcast i32 %d2 to i32 + ret i32 %d3 +} diff --git a/tests/llvm/dessa_001.irt b/tests/llvm/dessa_001.irt new file mode 100644 index 00000000..12389bda --- /dev/null +++ b/tests/llvm/dessa_001.irt @@ -0,0 +1,35 @@ +--TEST-- +DESSA 001 +--ARGS-- +--emit-llvm +--CODE-- +# Figure 1 from "Translating Out of Static Single Assignment Form" by Sreedhar +{ + uintptr_t c_1 = 0; + bool c_2 = 0; + bool c_3 = 1; + l_1 = START(l_13); + int32_t d_2 = PARAM(l_1, "a", 0); + int32_t d_3 = PARAM(l_1, "b", 1); + bool d_4 = PARAM(l_1, "cond", 2); + l_6 = IF(l_1, d_4); + l_7 = IF_TRUE(l_6); + l_8 = END(l_7); + l_9 = IF_FALSE(l_6); + l_10 = END(l_9); + l_11 = MERGE(l_8, l_10); + int32_t d_12 = PHI(l_11, d_3, d_2); + l_13 = RETURN(l_11, d_12); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3, i1 %d4) +{ + br i1 %d4, label %l2, label %l4 +l2: + br label %l3 +l3: + %d11 = phi i32 [%d3, %l2], [%d2, %l4] + ret i32 %d11 +l4: + br label %l3 +} diff --git a/tests/llvm/dessa_002.irt b/tests/llvm/dessa_002.irt new file mode 100644 index 00000000..3aab3965 --- /dev/null +++ b/tests/llvm/dessa_002.irt @@ -0,0 +1,37 @@ +--TEST-- +DESSA 002 +--ARGS-- +--emit-llvm +--CODE-- +{ + uintptr_t c_1 = 0; + bool c_2 = 0; + bool c_3 = 1; + int32_t c_4 = 1; + l_1 = START(l_11); + int32_t d_2 = PARAM(l_1, "x", 0); + l_3 = END(l_1); + l_4 = LOOP_BEGIN(l_3, l_9); + int32_t d_5 = PHI(l_4, d_2, d_6); + int32_t d_6 = ADD(d_5, c_4); + l_7 = IF(l_4, d_6); + l_8 = IF_TRUE(l_7); + l_9 = LOOP_END(l_8); + l_10 = IF_FALSE(l_7); + l_11 = RETURN(l_10, d_5); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ +l1: + br label %l2 +l2: + %d5 = phi i32 [%d2, %l1], [%d6, %l3] + %d6 = add i32 %d5, 1 + %t7 = icmp ne i32 %d6, 0 + br i1 %t7, label %l3, label %l4 +l3: + br label %l2 +l4: + ret i32 %d5 +} diff --git a/tests/llvm/dessa_003.irt b/tests/llvm/dessa_003.irt new file mode 100644 index 00000000..573141a6 --- /dev/null +++ b/tests/llvm/dessa_003.irt @@ -0,0 +1,46 @@ +--TEST-- +DESSA 003 +--ARGS-- +--emit-llvm +--CODE-- +# Figure 8 (swap problem) from "Translating Out of Static Single Assignment Form" by Sreedhar +{ + uintptr_t c_1 = 0; + bool c_2 = 0; + bool c_3 = 1; + int32_t c_4 = 1; + int32_t c_12 = 12; + l_1 = START(l_11); + int32_t x0 = PARAM(l_1, "x", 0); + int32_t y1 = PARAM(l_1, "y", 1); + int32_t cond = PARAM(l_1, "z", 2); + int32_t x1 = DIV(x0, c_12); + l_3 = END(l_1); + l_4 = LOOP_BEGIN(l_3, l_9); + int32_t x2 = PHI(l_4, x1, x3); + int32_t y2 = PHI(l_4, y1, y3); + int32_t z = COPY(x2); + int32_t x3 = COPY(y2); + int32_t y3 = COPY(z); + l_7 = IF(l_4, cond); + l_8 = IF_TRUE(l_7); + l_9 = LOOP_END(l_8); + l_10 = IF_FALSE(l_7); + l_11 = RETURN(l_10, z); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3, i32 %d4) +{ +l1: + %d5 = sdiv i32 %d2, 12 + br label %l2 +l2: + %d8 = phi i32 [%d5, %l1], [%d9, %l3] + %d9 = phi i32 [%d3, %l1], [%d8, %l3] + %t10 = icmp ne i32 %d4, 0 + br i1 %t10, label %l3, label %l4 +l3: + br label %l2 +l4: + ret i32 %d8 +} diff --git a/tests/llvm/div_001.irt b/tests/llvm/div_001.irt new file mode 100644 index 00000000..ee7c59b9 --- /dev/null +++ b/tests/llvm/div_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: div function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = DIV(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = sdiv i32 %d2, %d3 + ret i32 %d4 +} diff --git a/tests/llvm/div_006.irt b/tests/llvm/div_006.irt new file mode 100644 index 00000000..db853088 --- /dev/null +++ b/tests/llvm/div_006.irt @@ -0,0 +1,18 @@ +--TEST-- +006: div function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + uint32_t ret = DIV(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = udiv i32 %d2, %d3 + ret i32 %d4 +} diff --git a/tests/llvm/div_007.irt b/tests/llvm/div_007.irt new file mode 100644 index 00000000..4159067c --- /dev/null +++ b/tests/llvm/div_007.irt @@ -0,0 +1,18 @@ +--TEST-- +007: div function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double y = PARAM(l_1, "y", 2); + double ret = DIV(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(double %d2, double %d3) +{ + %d4 = fdiv double %d2, %d3 + ret double %d4 +} diff --git a/tests/llvm/eq_001.irt b/tests/llvm/eq_001.irt new file mode 100644 index 00000000..1015522f --- /dev/null +++ b/tests/llvm/eq_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: eq function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool ret = EQ(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp eq i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/eq_004.irt b/tests/llvm/eq_004.irt new file mode 100644 index 00000000..c0f6a113 --- /dev/null +++ b/tests/llvm/eq_004.irt @@ -0,0 +1,18 @@ +--TEST-- +004: eq function +--ARGS-- +--emit-llvm +--CODE-- +{ + double c = 0; + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + bool ret = EQ(x, c); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(double %d2) +{ + %d3 = fcmp oeq double %d2, 0.0 + ret i1 %d3 +} diff --git a/tests/llvm/ge_001.irt b/tests/llvm/ge_001.irt new file mode 100644 index 00000000..ad1bef4d --- /dev/null +++ b/tests/llvm/ge_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: ge function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool ret = GE(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp sle i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/ge_004.irt b/tests/llvm/ge_004.irt new file mode 100644 index 00000000..f3a1a58d --- /dev/null +++ b/tests/llvm/ge_004.irt @@ -0,0 +1,18 @@ +--TEST-- +004: ge function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + bool ret = GE(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp ule i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/ge_006.irt b/tests/llvm/ge_006.irt new file mode 100644 index 00000000..578efbb6 --- /dev/null +++ b/tests/llvm/ge_006.irt @@ -0,0 +1,18 @@ +--TEST-- +006: ge function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double y = PARAM(l_1, "y", 2); + bool ret = GE(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(double %d2, double %d3) +{ + %d4 = fcmp ole double %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/gt_001.irt b/tests/llvm/gt_001.irt new file mode 100644 index 00000000..eff04f16 --- /dev/null +++ b/tests/llvm/gt_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: gt function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool ret = GT(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp slt i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/gt_004.irt b/tests/llvm/gt_004.irt new file mode 100644 index 00000000..6a58e163 --- /dev/null +++ b/tests/llvm/gt_004.irt @@ -0,0 +1,18 @@ +--TEST-- +004: gt function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + bool ret = GT(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp ult i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/gt_006.irt b/tests/llvm/gt_006.irt new file mode 100644 index 00000000..6bb7eaa8 --- /dev/null +++ b/tests/llvm/gt_006.irt @@ -0,0 +1,18 @@ +--TEST-- +006: gt function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double y = PARAM(l_1, "y", 2); + bool ret = GT(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(double %d2, double %d3) +{ + %d4 = fcmp olt double %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/ijmp_001.irt b/tests/llvm/ijmp_001.irt new file mode 100644 index 00000000..22b98cf9 --- /dev/null +++ b/tests/llvm/ijmp_001.irt @@ -0,0 +1,15 @@ +--TEST-- +001: IJMP - computed goto +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_2); + uintptr_t p = PARAM(l_1, "p", 1); + l_2 = IJMP(l_1, p); +} +--EXPECT-- +define void @test(ptr %d2) +{ + indirectbr ptr %d2, [] +} diff --git a/tests/llvm/le_001.irt b/tests/llvm/le_001.irt new file mode 100644 index 00000000..c115a997 --- /dev/null +++ b/tests/llvm/le_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: le function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool ret = LE(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp sge i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/le_004.irt b/tests/llvm/le_004.irt new file mode 100644 index 00000000..c7c8154b --- /dev/null +++ b/tests/llvm/le_004.irt @@ -0,0 +1,18 @@ +--TEST-- +004: le function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + bool ret = LE(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp uge i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/le_006.irt b/tests/llvm/le_006.irt new file mode 100644 index 00000000..59122ce4 --- /dev/null +++ b/tests/llvm/le_006.irt @@ -0,0 +1,18 @@ +--TEST-- +006: le function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double y = PARAM(l_1, "y", 2); + bool ret = LE(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(double %d2, double %d3) +{ + %d4 = fcmp oge double %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/lt_001.irt b/tests/llvm/lt_001.irt new file mode 100644 index 00000000..a2dd937d --- /dev/null +++ b/tests/llvm/lt_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: lt function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool ret = LT(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp sgt i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/lt_004.irt b/tests/llvm/lt_004.irt new file mode 100644 index 00000000..d163258b --- /dev/null +++ b/tests/llvm/lt_004.irt @@ -0,0 +1,18 @@ +--TEST-- +004: lt function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + bool ret = LT(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp ugt i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/lt_006.irt b/tests/llvm/lt_006.irt new file mode 100644 index 00000000..9cb6e5a0 --- /dev/null +++ b/tests/llvm/lt_006.irt @@ -0,0 +1,18 @@ +--TEST-- +006: lt function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double y = PARAM(l_1, "y", 2); + bool ret = LT(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(double %d2, double %d3) +{ + %d4 = fcmp ogt double %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/max_01.irt b/tests/llvm/max_01.irt new file mode 100644 index 00000000..78e51de8 --- /dev/null +++ b/tests/llvm/max_01.irt @@ -0,0 +1,18 @@ +--TEST-- +001: max function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = MAX(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = call i32 @llvm.smax.i32(i32 %d3, i32 %d2) + ret i32 %d4 +} diff --git a/tests/llvm/max_04.irt b/tests/llvm/max_04.irt new file mode 100644 index 00000000..fe338f58 --- /dev/null +++ b/tests/llvm/max_04.irt @@ -0,0 +1,18 @@ +--TEST-- +004: max function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + uint32_t ret = MAX(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = call i32 @llvm.umax.i32(i32 %d3, i32 %d2) + ret i32 %d4 +} diff --git a/tests/llvm/max_06.irt b/tests/llvm/max_06.irt new file mode 100644 index 00000000..ea2e0021 --- /dev/null +++ b/tests/llvm/max_06.irt @@ -0,0 +1,18 @@ +--TEST-- +006: max function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double y = PARAM(l_1, "y", 2); + double ret = MAX(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(double %d2, double %d3) +{ + %d4 = call double @llvm.maxnum.f64(double %d3, double %d2) + ret double %d4 +} diff --git a/tests/llvm/min_01.irt b/tests/llvm/min_01.irt new file mode 100644 index 00000000..00d239a6 --- /dev/null +++ b/tests/llvm/min_01.irt @@ -0,0 +1,18 @@ +--TEST-- +001: min function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = MIN(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = call i32 @llvm.smin.i32(i32 %d3, i32 %d2) + ret i32 %d4 +} diff --git a/tests/llvm/min_04.irt b/tests/llvm/min_04.irt new file mode 100644 index 00000000..134457ab --- /dev/null +++ b/tests/llvm/min_04.irt @@ -0,0 +1,18 @@ +--TEST-- +004: min function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + uint32_t ret = MIN(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = call i32 @llvm.umin.i32(i32 %d3, i32 %d2) + ret i32 %d4 +} diff --git a/tests/llvm/min_06.irt b/tests/llvm/min_06.irt new file mode 100644 index 00000000..ce79d5e9 --- /dev/null +++ b/tests/llvm/min_06.irt @@ -0,0 +1,18 @@ +--TEST-- +006: min function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double y = PARAM(l_1, "y", 2); + double ret = MIN(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(double %d2, double %d3) +{ + %d4 = call double @llvm.minnum.f64(double %d3, double %d2) + ret double %d4 +} diff --git a/tests/llvm/mod_001.irt b/tests/llvm/mod_001.irt new file mode 100644 index 00000000..33411c58 --- /dev/null +++ b/tests/llvm/mod_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: mod function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = MOD(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = srem i32 %d2, %d3 + ret i32 %d4 +} diff --git a/tests/llvm/mod_006.irt b/tests/llvm/mod_006.irt new file mode 100644 index 00000000..a0c674e9 --- /dev/null +++ b/tests/llvm/mod_006.irt @@ -0,0 +1,18 @@ +--TEST-- +006: mod function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + uint32_t ret = MOD(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = urem i32 %d2, %d3 + ret i32 %d4 +} diff --git a/tests/llvm/mul_001.irt b/tests/llvm/mul_001.irt new file mode 100644 index 00000000..3eb20b3c --- /dev/null +++ b/tests/llvm/mul_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: mul function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + uint32_t ret = MUL(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = mul i32 %d3, %d2 + ret i32 %d4 +} diff --git a/tests/llvm/mul_011.irt b/tests/llvm/mul_011.irt new file mode 100644 index 00000000..48581453 --- /dev/null +++ b/tests/llvm/mul_011.irt @@ -0,0 +1,18 @@ +--TEST-- +011: mul function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double y = PARAM(l_1, "y", 2); + double ret = MUL(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(double %d2, double %d3) +{ + %d4 = fmul double %d3, %d2 + ret double %d4 +} diff --git a/tests/llvm/mul_ov_001.irt b/tests/llvm/mul_ov_001.irt new file mode 100644 index 00000000..399796ad --- /dev/null +++ b/tests/llvm/mul_ov_001.irt @@ -0,0 +1,21 @@ +--TEST-- +001: mul_ov function +--ARGS-- +--emit-llvm +--CODE-- +{ + int32_t c = 2; + l_1 = START(l_2); + int32_t x = PARAM(l_1, "x", 1); + int32_t ret = MUL_OV(x, c); + bool ov = OVERFLOW(ret); + l_2 = RETURN(l_1, ov); +} +--EXPECT-- +define i1 @test(i32 %d2) +{ + %t3 = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %d2, i32 2) + %d3 = extractvalue {i32, i1} %t3, 0 + %d4 = extractvalue {i32, i1} %t3, 1 + ret i1 %d4 +} diff --git a/tests/llvm/mul_ov_002.irt b/tests/llvm/mul_ov_002.irt new file mode 100644 index 00000000..bd83a5ad --- /dev/null +++ b/tests/llvm/mul_ov_002.irt @@ -0,0 +1,21 @@ +--TEST-- +002: mul_ov function +--ARGS-- +--emit-llvm +--CODE-- +{ + uint32_t c = 2; + l_1 = START(l_2); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t ret = MUL_OV(x, c); + bool ov = OVERFLOW(ret); + l_2 = RETURN(l_1, ov); +} +--EXPECT-- +define i1 @test(i32 %d2) +{ + %t3 = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %d2, i32 2) + %d3 = extractvalue {i32, i1} %t3, 0 + %d4 = extractvalue {i32, i1} %t3, 1 + ret i1 %d4 +} diff --git a/tests/llvm/ne_001.irt b/tests/llvm/ne_001.irt new file mode 100644 index 00000000..86702a5d --- /dev/null +++ b/tests/llvm/ne_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: ne function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool ret = NE(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp ne i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/ne_004.irt b/tests/llvm/ne_004.irt new file mode 100644 index 00000000..e792a34a --- /dev/null +++ b/tests/llvm/ne_004.irt @@ -0,0 +1,18 @@ +--TEST-- +004: ne function +--ARGS-- +--emit-llvm +--CODE-- +{ + double c = 0; + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + bool ret = NE(x, c); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(double %d2) +{ + %d3 = fcmp une double %d2, 0.0 + ret i1 %d3 +} diff --git a/tests/llvm/neg_001.irt b/tests/llvm/neg_001.irt new file mode 100644 index 00000000..bdee57a6 --- /dev/null +++ b/tests/llvm/neg_001.irt @@ -0,0 +1,17 @@ +--TEST-- +001: neg function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t ret = NEG(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + %d3 = sub i32 0, %d2 + ret i32 %d3 +} diff --git a/tests/llvm/neg_002.irt b/tests/llvm/neg_002.irt new file mode 100644 index 00000000..0695e1e2 --- /dev/null +++ b/tests/llvm/neg_002.irt @@ -0,0 +1,17 @@ +--TEST-- +002: neg function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double ret = NEG(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(double %d2) +{ + %d3 = fneg double %d2 + ret double %d3 +} diff --git a/tests/llvm/neg_003.irt b/tests/llvm/neg_003.irt new file mode 100644 index 00000000..33a875dc --- /dev/null +++ b/tests/llvm/neg_003.irt @@ -0,0 +1,17 @@ +--TEST-- +003: neg function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + float x = PARAM(l_1, "x", 1); + float ret = NEG(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define float @test(float %d2) +{ + %d3 = fneg float %d2 + ret float %d3 +} diff --git a/tests/llvm/not_001.irt b/tests/llvm/not_001.irt new file mode 100644 index 00000000..034a37c1 --- /dev/null +++ b/tests/llvm/not_001.irt @@ -0,0 +1,17 @@ +--TEST-- +001: not function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t ret = NOT(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + %d3 = xor i32 %d2, -1 + ret i32 %d3 +} diff --git a/tests/llvm/not_002.irt b/tests/llvm/not_002.irt new file mode 100644 index 00000000..e5bad021 --- /dev/null +++ b/tests/llvm/not_002.irt @@ -0,0 +1,17 @@ +--TEST-- +002: not function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + bool x = PARAM(l_1, "x", 1); + bool ret = NOT(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i1 %d2) +{ + %d3 = icmp eq i1 %d2, 0 + ret i1 %d3 +} diff --git a/tests/llvm/not_003.irt b/tests/llvm/not_003.irt new file mode 100644 index 00000000..5c652b76 --- /dev/null +++ b/tests/llvm/not_003.irt @@ -0,0 +1,17 @@ +--TEST-- +003: not function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + bool ret = NOT(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2) +{ + %d3 = icmp eq i32 %d2, 0 + ret i1 %d3 +} diff --git a/tests/llvm/not_004.irt b/tests/llvm/not_004.irt new file mode 100644 index 00000000..0b64e01b --- /dev/null +++ b/tests/llvm/not_004.irt @@ -0,0 +1,17 @@ +--TEST-- +004: not function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + bool ret = NOT(x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(double %d2) +{ + %d3 = fcmp oeq double %d2, 0.0 + ret i1 %d3 +} diff --git a/tests/llvm/rol_001.irt b/tests/llvm/rol_001.irt new file mode 100644 index 00000000..5acb329b --- /dev/null +++ b/tests/llvm/rol_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: rol function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = ROL(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = call i32 @llvm.fshl.i32(i32 %d2, i32 %d2, i32 %d3) + ret i32 %d4 +} diff --git a/tests/llvm/ror_001.irt b/tests/llvm/ror_001.irt new file mode 100644 index 00000000..28eb28ed --- /dev/null +++ b/tests/llvm/ror_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: ror function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = ROR(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = call i32 @llvm.fshr.i32(i32 %d2, i32 %d2, i32 %d3) + ret i32 %d4 +} diff --git a/tests/llvm/sar_001.irt b/tests/llvm/sar_001.irt new file mode 100644 index 00000000..77a57b43 --- /dev/null +++ b/tests/llvm/sar_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: sar function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = SAR(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = ashr i32 %d2, %d3 + ret i32 %d4 +} diff --git a/tests/llvm/sar_002.irt b/tests/llvm/sar_002.irt new file mode 100644 index 00000000..56133d39 --- /dev/null +++ b/tests/llvm/sar_002.irt @@ -0,0 +1,18 @@ +--TEST-- +002: sar function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + uint32_t ret = SAR(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = ashr i32 %d2, %d3 + ret i32 %d4 +} diff --git a/tests/llvm/shl_001.irt b/tests/llvm/shl_001.irt new file mode 100644 index 00000000..f27f96bb --- /dev/null +++ b/tests/llvm/shl_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: shl function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = SHL(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = shl i32 %d2, %d3 + ret i32 %d4 +} diff --git a/tests/llvm/shr_001.irt b/tests/llvm/shr_001.irt new file mode 100644 index 00000000..dfa9b8ea --- /dev/null +++ b/tests/llvm/shr_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: shr function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = SHR(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = lshr i32 %d2, %d3 + ret i32 %d4 +} diff --git a/tests/llvm/shr_002.irt b/tests/llvm/shr_002.irt new file mode 100644 index 00000000..4f3debd2 --- /dev/null +++ b/tests/llvm/shr_002.irt @@ -0,0 +1,18 @@ +--TEST-- +002: shr function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + uint32_t x = PARAM(l_1, "x", 1); + uint32_t y = PARAM(l_1, "y", 2); + uint32_t ret = SHR(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = lshr i32 %d2, %d3 + ret i32 %d4 +} diff --git a/tests/llvm/sub_001.irt b/tests/llvm/sub_001.irt new file mode 100644 index 00000000..3a9db93f --- /dev/null +++ b/tests/llvm/sub_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: sub function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + int32_t ret = SUB(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i32 @test(i32 %d2, i32 %d3) +{ + %d4 = sub i32 %d2, %d3 + ret i32 %d4 +} diff --git a/tests/llvm/sub_011.irt b/tests/llvm/sub_011.irt new file mode 100644 index 00000000..555e42b4 --- /dev/null +++ b/tests/llvm/sub_011.irt @@ -0,0 +1,18 @@ +--TEST-- +011: sub function +--ARGS-- +--emit-llvm +--CODE-- +{ + double c = 0.5; + l_1 = START(l_4); + double x = PARAM(l_1, "x", 1); + double ret = SUB(c, x); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define double @test(double %d2) +{ + %d3 = fsub double 0.5, %d2 + ret double %d3 +} diff --git a/tests/llvm/switch_001.irt b/tests/llvm/switch_001.irt new file mode 100644 index 00000000..55a4d167 --- /dev/null +++ b/tests/llvm/switch_001.irt @@ -0,0 +1,52 @@ +--TEST-- +SWITCH 001 +--ARGS-- +--emit-llvm +--CODE-- +{ + uintptr_t c_1 = 0; + bool c_2 = 0; + bool c_3 = 1; + int32_t c_4 = 1; + int32_t c_5 = 2; + int32_t c_6 = 3; + int32_t c_7 = 4; + l_1 = START(l_16); + int32_t d_2 = PARAM(l_1, "z", 0); + l_4 = SWITCH(l_1, d_2); + l_5 = CASE_VAL(l_4, c_4); + int32_t x_1 = COPY(c_4); + l_6 = END(l_5); + l_7 = CASE_VAL(l_4, c_5); + int32_t x_2 = COPY(c_5); + l_8 = END(l_7); + l_9 = CASE_VAL(l_4, c_6); + int32_t x_3 = COPY(c_6); + l_10 = END(l_9); + l_11 = CASE_DEFAULT(l_4); + int32_t x_4 = COPY(c_7); + l_12 = END(l_11); + l_13 = MERGE/4(l_6, l_8, l_10, l_12); + int32_t ret = PHI/4(l_13, x_1, x_2, x_3, x_4); + l_16 = RETURN(l_13, ret); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + switch i32 %d2, label %l6 [ + i32 1, label %l2 + i32 2, label %l4 + i32 3, label %l5 + ] +l2: + br label %l3 +l3: + %d14 = phi i32 [1, %l2], [2, %l4], [3, %l5], [4, %l6] + ret i32 %d14 +l4: + br label %l3 +l5: + br label %l3 +l6: + br label %l3 +} diff --git a/tests/llvm/switch_002.irt b/tests/llvm/switch_002.irt new file mode 100644 index 00000000..7b0f7f8e --- /dev/null +++ b/tests/llvm/switch_002.irt @@ -0,0 +1,55 @@ +--TEST-- +SWITCH 001 +--ARGS-- +--emit-llvm +--CODE-- +{ + uintptr_t c_1 = 0; + bool c_2 = 0; + bool c_3 = 1; + int32_t c_4 = 0; + int32_t c_5 = 1; + int32_t c_6 = 2; + int32_t c_7 = 3; + l_1 = START(l_16); + int32_t d_2 = PARAM(l_1, "z", 0); + l_4 = SWITCH(l_1, d_2); + l_5 = CASE_VAL(l_4, c_4); + int32_t x_1 = MUL(d_2, c_7); + l_6 = END(l_5); + l_7 = CASE_VAL(l_4, c_5); + int32_t x_2 = ADD(d_2, c_5); + l_8 = END(l_7); + l_9 = CASE_VAL(l_4, c_6); + int32_t x_3 = SUB(d_2, c_6); + l_10 = END(l_9); + l_11 = CASE_DEFAULT(l_4); + int32_t x_4 = SUB(d_2, c_6); + l_12 = END(l_11); + l_13 = MERGE/4(l_6, l_8, l_10, l_12); + int32_t ret = PHI/4(l_13, x_1, x_2, x_3, x_4); + l_16 = RETURN(l_13, ret); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + %d3 = sub i32 %d2, 2 + switch i32 %d2, label %l6 [ + i32 0, label %l2 + i32 1, label %l4 + i32 2, label %l5 + ] +l2: + %d6 = mul i32 %d2, 3 + br label %l3 +l3: + %d17 = phi i32 [%d6, %l2], [%d9, %l4], [%d3, %l5], [%d3, %l6] + ret i32 %d17 +l4: + %d9 = add i32 %d2, 1 + br label %l3 +l5: + br label %l3 +l6: + br label %l3 +} diff --git a/tests/llvm/tailcall_001.irt b/tests/llvm/tailcall_001.irt new file mode 100644 index 00000000..fc6a7b32 --- /dev/null +++ b/tests/llvm/tailcall_001.irt @@ -0,0 +1,24 @@ +--TEST-- +Simple TAILCALL +--ARGS-- +--emit-llvm +--CODE-- +{ + uintptr_t c_1 = 0; + bool c_2 = 0; + bool c_3 = 1; + int32_t c_4 = 42; + uintptr_t c_5 = func(printf, 4); + uintptr_t c_6 = "hello %d!\n"; + l_1 = START(l_4); + char d_2, l_2 = TAILCALL/2(l_1, c_5, c_6, c_4); + l_4 = UNREACHABLE(l_2); +} +--EXPECT-- +define i8 @test() +{ + %d2 = tail call i8 @printf(ptr @.str6, i32 42) + ret i8 %d2 +} +declare void @printf() +@.str6 = private unnamed_addr constant [12 x i8] c"hello %d!\0A\00" diff --git a/tests/llvm/tailcall_002.irt b/tests/llvm/tailcall_002.irt new file mode 100644 index 00000000..f734cab5 --- /dev/null +++ b/tests/llvm/tailcall_002.irt @@ -0,0 +1,20 @@ +--TEST-- +Indirect Tail CALL +--ARGS-- +--emit-llvm +--CODE-- +{ + uintptr_t c_6 = "hello %d!\n"; + l_1 = START(l_4); + uintptr_t f = PARAM(l_1, "f", 1); + int32_t p = PARAM(l_1, "p", 2); + int32_t d_2, l_2 = TAILCALL/2(l_1, f, c_6, p); + l_4 = UNREACHABLE(l_2); +} +--EXPECT-- +define i32 @test(ptr %d2, i32 %d3) +{ + %d4 = tail call i32 %d2(ptr @.str4, i32 %d3) + ret i32 %d4 +} +@.str4 = private unnamed_addr constant [12 x i8] c"hello %d!\0A\00" diff --git a/tests/llvm/trap_001.irt b/tests/llvm/trap_001.irt new file mode 100644 index 00000000..d99eb342 --- /dev/null +++ b/tests/llvm/trap_001.irt @@ -0,0 +1,17 @@ +--TEST-- +001: trap function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_3); + int32_t d_2 = PARAM(l_1, "x", 1); + l_2 = TRAP(l_1); + l_3 = RETURN(l_2, d_2); +} +--EXPECT-- +define i32 @test(i32 %d2) +{ + call void @llvm.debugtrap() + ret i32 %d2 +} diff --git a/tests/llvm/uge_001.irt b/tests/llvm/uge_001.irt new file mode 100644 index 00000000..0a565f02 --- /dev/null +++ b/tests/llvm/uge_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: uge function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool ret = UGE(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp ule i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/ugt_001.irt b/tests/llvm/ugt_001.irt new file mode 100644 index 00000000..5cf1139a --- /dev/null +++ b/tests/llvm/ugt_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: ugt function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool ret = UGT(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp ult i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/ule_001.irt b/tests/llvm/ule_001.irt new file mode 100644 index 00000000..4781a039 --- /dev/null +++ b/tests/llvm/ule_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: ule function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool ret = ULE(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp uge i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/ult_001.irt b/tests/llvm/ult_001.irt new file mode 100644 index 00000000..2a7cf2f1 --- /dev/null +++ b/tests/llvm/ult_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: ult function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_4); + int32_t x = PARAM(l_1, "x", 1); + int32_t y = PARAM(l_1, "y", 2); + bool ret = ULT(x, y); + l_4 = RETURN(l_1, ret); +} +--EXPECT-- +define i1 @test(i32 %d2, i32 %d3) +{ + %d4 = icmp ugt i32 %d3, %d2 + ret i1 %d4 +} diff --git a/tests/llvm/vaddr_001.irt b/tests/llvm/vaddr_001.irt new file mode 100644 index 00000000..f3f0aced --- /dev/null +++ b/tests/llvm/vaddr_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: vaddr function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_2); + int32_t d_2 = VAR(l_1, "v"); + uintptr_t d_3 = VADDR(d_2); + l_2 = RETURN(l_1, d_3); +} +--EXPECT-- +define ptr @test() +{ + %d2 = alloca i32 + %d3 = bitcast ptr %d2 to ptr + ret ptr %d3 +} diff --git a/tests/llvm/vload_001.irt b/tests/llvm/vload_001.irt new file mode 100644 index 00000000..6547d912 --- /dev/null +++ b/tests/llvm/vload_001.irt @@ -0,0 +1,18 @@ +--TEST-- +001: vload function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_3); + int32_t d_2 = VAR(l_1, "v"); + int32_t d_3, l_2 = VLOAD(l_1, d_2); + l_3 = RETURN(l_2, d_3); +} +--EXPECT-- +define i32 @test() +{ + %d2 = alloca i32 + %d3 = load i32, ptr %d2 + ret i32 %d3 +} diff --git a/tests/llvm/vstore_001.irt b/tests/llvm/vstore_001.irt new file mode 100644 index 00000000..57174b0f --- /dev/null +++ b/tests/llvm/vstore_001.irt @@ -0,0 +1,19 @@ +--TEST-- +001: vstore function +--ARGS-- +--emit-llvm +--CODE-- +{ + l_1 = START(l_3); + int32_t d_2 = PARAM(l_1, "x", 1); + int32_t d_3 = VAR(l_1, "v"); + l_2 = VSTORE(l_1, d_3, d_2); + l_3 = RETURN(l_2); +} +--EXPECT-- +define void @test(i32 %d2) +{ + %d3 = alloca i32 + store i32 %d2, ptr %d3 + ret void +} diff --git a/win32/Makefile b/win32/Makefile index 5d218385..f138478c 100644 --- a/win32/Makefile +++ b/win32/Makefile @@ -73,7 +73,8 @@ LIBS=psapi.lib capstone.lib OBJS_COMMON=$(BUILD_DIR)\ir.obj $(BUILD_DIR)\ir_strtab.obj $(BUILD_DIR)\ir_cfg.obj \ $(BUILD_DIR)\ir_sccp.obj $(BUILD_DIR)\ir_gcm.obj $(BUILD_DIR)\ir_ra.obj $(BUILD_DIR)\ir_emit.obj \ $(BUILD_DIR)\ir_load.obj $(BUILD_DIR)\ir_save.obj $(BUILD_DIR)\ir_emit_c.obj $(BUILD_DIR)\ir_dump.obj \ - $(BUILD_DIR)\ir_disasm.obj $(BUILD_DIR)\ir_check.obj $(BUILD_DIR)\ir_cpuinfo.obj + $(BUILD_DIR)\ir_disasm.obj $(BUILD_DIR)\ir_check.obj $(BUILD_DIR)\ir_cpuinfo.obj \ + $(BUILD_DIR)\ir_emit_llvm.obj OBJS_IR = $(BUILD_DIR)\ir_main.obj OBJS_IR_TEST = $(BUILD_DIR)\ir_test.obj EXAMPLE_EXES = $(EXAMPLES_BUILD_DIR)\0001-basic.exe $(EXAMPLES_BUILD_DIR)\0001-while.exe $(EXAMPLES_BUILD_DIR)\0005-basic-runner-func.exe \