2022-11-08 09:32:46 +01:00
|
|
|
/*
|
|
|
|
* IR - Lightweight JIT Compilation Framework
|
|
|
|
* (Mandelbrot example)
|
|
|
|
* Copyright (C) 2022 Zend by Perforce.
|
|
|
|
* Authors: Dmitry Stogov <dmitry@php.net>
|
|
|
|
*/
|
|
|
|
|
2022-04-05 23:19:23 +02:00
|
|
|
#include "ir.h"
|
|
|
|
#include <sys/time.h>
|
2022-04-27 13:47:52 +02:00
|
|
|
#include <stdlib.h>
|
2022-05-27 12:18:04 +02:00
|
|
|
#include <string.h>
|
2022-04-05 23:19:23 +02:00
|
|
|
|
|
|
|
#define BAILOUT 16
|
|
|
|
#define MAX_ITERATIONS 1000
|
|
|
|
|
|
|
|
void gen_mandelbrot(ir_ctx *ctx)
|
|
|
|
{
|
|
|
|
ir_ref start = ir_emit0(ctx, IR_START);
|
|
|
|
ir_ref ret;
|
|
|
|
|
|
|
|
ir_ref x_1 = ir_param(ctx, IR_DOUBLE, start, "x", 0);
|
|
|
|
ir_ref y_1 = ir_param(ctx, IR_DOUBLE, start, "y", 1);
|
|
|
|
|
|
|
|
ir_ref cr = ir_var(ctx, IR_DOUBLE, start, "cr");
|
|
|
|
ir_ref cr_1 = ir_fold2(ctx, IR_OPT(IR_SUB, IR_DOUBLE), y_1,
|
|
|
|
ir_const_double(ctx, 0.5));
|
|
|
|
ir_bind(ctx, cr, cr_1); // cr=cr_1
|
|
|
|
ir_ref ci = ir_var(ctx, IR_DOUBLE, start, "ci");
|
|
|
|
ir_bind(ctx, ci, x_1); // cr=cr_1, ci=x_1
|
|
|
|
ir_ref zi = ir_var(ctx, IR_DOUBLE, start, "zi");
|
|
|
|
ir_bind(ctx, zi, ir_const_double(ctx, 0.0)); // cr=cr_1, ci=x_1, zi=0.0
|
|
|
|
ir_ref zr = ir_var(ctx, IR_DOUBLE, start, "zr");
|
|
|
|
ir_bind(ctx, zr, ir_const_double(ctx, 0.0)); // cr=cr_1, ci=x_1, zi=0.0, zr=0.0
|
|
|
|
ir_ref i = ir_var(ctx, IR_I32, start, "i");
|
|
|
|
ir_bind(ctx, i, ir_const_i32(ctx, 0)); // cr=cr_1, ci=x_1, zi=0.0, zr=0.0, i=0
|
|
|
|
|
|
|
|
ir_ref e_1 = ir_emit1(ctx, IR_END, start);
|
|
|
|
ir_ref l_1 = ir_emit1(ctx, IR_LOOP_BEGIN, e_1);
|
|
|
|
|
|
|
|
ir_ref zi_1 = ir_emit2(ctx, IR_OPT(IR_PHI, IR_DOUBLE), l_1,
|
|
|
|
ir_const_double(ctx, 0.0));
|
|
|
|
ir_bind(ctx, zi, zi_1); // cr=cr_1, ci=x_1, zi=zi_1, zr=0.0, i=0
|
|
|
|
ir_ref zr_1 = ir_emit2(ctx, IR_OPT(IR_PHI, IR_DOUBLE), l_1,
|
|
|
|
ir_const_double(ctx, 0.0));
|
2022-09-08 09:50:07 +02:00
|
|
|
ir_bind(ctx, zr, zr_1); // cr=cr_1, ci=x_1, zi=zi_1, zr=zr_1, i=0
|
2022-04-05 23:19:23 +02:00
|
|
|
ir_ref i_1 = ir_emit2(ctx, IR_OPT(IR_PHI, IR_I32), l_1,
|
|
|
|
ir_const_i32(ctx, 0));
|
|
|
|
ir_bind(ctx, i, i_1); // cr=cr_1, ci=x_1, zi=zi_1, zr=zr_1, i=i_1
|
|
|
|
ir_ref i_2 = ir_emit2(ctx, IR_OPT(IR_ADD, IR_I32), i_1,
|
|
|
|
ir_const_i32(ctx, 1));
|
2022-09-08 09:50:07 +02:00
|
|
|
ir_bind(ctx, i, i_2); // cr=cr_1, ci=x_1, zi=zi_1, zr=zr_1, i=i_2
|
2022-04-05 23:19:23 +02:00
|
|
|
ir_ref temp = ir_var(ctx, IR_DOUBLE, l_1, "temp");
|
|
|
|
ir_ref temp_1 = ir_fold2(ctx, IR_OPT(IR_MUL, IR_DOUBLE), zr_1, zi_1);
|
|
|
|
ir_bind(ctx, temp, temp_1); // ... temp=temp_1
|
|
|
|
ir_ref zr2 = ir_var(ctx, IR_DOUBLE, l_1, "zr2");
|
|
|
|
ir_ref zr2_1 = ir_fold2(ctx, IR_OPT(IR_MUL, IR_DOUBLE), zr_1, zr_1);
|
|
|
|
ir_bind(ctx, zr2, zr2_1); // ... temp=temp_1, zr2=zr2_1
|
|
|
|
ir_ref zi2 = ir_var(ctx, IR_DOUBLE, l_1, "zi2");
|
|
|
|
ir_ref zi2_1 = ir_fold2(ctx, IR_OPT(IR_MUL, IR_DOUBLE), zi_1, zi_1);
|
|
|
|
ir_bind(ctx, zi2, zi2_1); // ... temp=temp_1, zr2=zr2_1, zi2=zi2_1
|
|
|
|
ir_ref zr_2 = ir_fold2(ctx, IR_OPT(IR_ADD, IR_DOUBLE),
|
|
|
|
ir_fold2(ctx, IR_OPT(IR_SUB, IR_DOUBLE), zr2_1, zi2_1),
|
|
|
|
cr_1);
|
|
|
|
ir_bind(ctx, zr, zr_2); // cr=cr_1, ci=x_1, zi=zi_1, zr=zr_2, i=i_2
|
|
|
|
ir_ref zi_2 = ir_fold2(ctx, IR_OPT(IR_ADD, IR_DOUBLE),
|
|
|
|
ir_fold2(ctx, IR_OPT(IR_ADD, IR_DOUBLE), temp_1, temp_1),
|
|
|
|
x_1);
|
|
|
|
ir_bind(ctx, zi, zi_2); // cr=cr_1, ci=x_1, zi=zi_2 zr=zr_2, i=i_2
|
|
|
|
|
|
|
|
ir_ref if_1 = ir_emit2(ctx, IR_IF, l_1,
|
|
|
|
ir_fold2(ctx, IR_OPT(IR_GT, IR_BOOL),
|
|
|
|
ir_fold2(ctx, IR_OPT(IR_ADD, IR_DOUBLE), zi2_1, zr2_1),
|
|
|
|
ir_const_double(ctx, 16.0)));
|
|
|
|
|
|
|
|
ir_ref r_1 = ir_emit1(ctx, IR_IF_TRUE, if_1);
|
|
|
|
ret = ir_emit2(ctx, IR_OPT(IR_RETURN, IR_I32), r_1, i_2);
|
|
|
|
|
|
|
|
ir_ref r_2 = ir_emit1(ctx, IR_IF_FALSE, if_1);
|
|
|
|
|
|
|
|
ir_ref if_2 = ir_emit2(ctx, IR_IF, r_2,
|
|
|
|
ir_fold2(ctx, IR_OPT(IR_GT, IR_BOOL), i_2, ir_const_i32(ctx, 1000)));
|
|
|
|
|
|
|
|
ir_ref r_3 = ir_emit1(ctx, IR_IF_TRUE, if_2);
|
|
|
|
|
|
|
|
ret = ir_emit3(ctx, IR_OPT(IR_RETURN, IR_I32), r_3, ir_const_i32(ctx, 0), ret);
|
|
|
|
|
|
|
|
ir_ref r_4 = ir_emit1(ctx, IR_IF_FALSE, if_2);
|
|
|
|
|
|
|
|
ir_ref l_2 = ir_emit2(ctx, IR_LOOP_END, r_4, l_1);
|
|
|
|
|
|
|
|
ir_set_op2(ctx, l_1, l_2);
|
|
|
|
ir_set_op3(ctx, zi_1, zi_2);
|
|
|
|
ir_set_op3(ctx, zr_1, zr_2);
|
|
|
|
ir_set_op3(ctx, i_1, i_2);
|
|
|
|
|
|
|
|
ir_set_op1(ctx, start, ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
typedef int (*mandelbrot_t)(double, double);
|
|
|
|
|
|
|
|
void run(mandelbrot_t mandelbrot)
|
|
|
|
{
|
|
|
|
struct timeval aTv;
|
|
|
|
gettimeofday(&aTv, NULL);
|
|
|
|
long init_time = aTv.tv_sec;
|
|
|
|
long init_usec = aTv.tv_usec;
|
|
|
|
|
|
|
|
int x,y;
|
|
|
|
for (y = -39; y < 39; y++) {
|
|
|
|
printf("\n");
|
|
|
|
for (x = -39; x < 39; x++) {
|
|
|
|
int i = mandelbrot(x/40.0, y/40.0);
|
|
|
|
if (i==0)
|
|
|
|
printf("*");
|
|
|
|
else
|
|
|
|
printf(" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
printf ("\n");
|
|
|
|
|
|
|
|
gettimeofday(&aTv,NULL);
|
|
|
|
double query_time = (aTv.tv_sec - init_time) + (double)(aTv.tv_usec - init_usec)/1000000.0;
|
|
|
|
printf ("C Elapsed %0.3f\n", query_time);
|
|
|
|
}
|
|
|
|
|
2022-04-19 10:03:01 +02:00
|
|
|
int main(int argc, char **argv)
|
2022-04-05 23:19:23 +02:00
|
|
|
{
|
|
|
|
ir_ctx ctx;
|
|
|
|
FILE *f;
|
2022-04-19 10:03:01 +02:00
|
|
|
int i;
|
|
|
|
int opt_level = 2;
|
|
|
|
uint32_t mflags = 0;
|
2022-06-21 15:13:14 +02:00
|
|
|
uint64_t debug_regset = 0xffffffffffffffff;
|
2022-04-19 10:03:01 +02:00
|
|
|
|
2022-05-27 12:18:04 +02:00
|
|
|
ir_consistency_check();
|
|
|
|
|
2022-04-19 10:03:01 +02:00
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
if (argv[i][0] == '-' && argv[i][1] == 'O' && strlen(argv[i]) == 3) {
|
|
|
|
if (argv[i][2] == '0') {
|
|
|
|
opt_level = 0;
|
|
|
|
} else if (argv[i][2] == '1') {
|
|
|
|
opt_level = 1;
|
|
|
|
} else if (argv[i][2] == '2') {
|
|
|
|
opt_level = 2;
|
|
|
|
} else {
|
|
|
|
/* pass */
|
|
|
|
}
|
|
|
|
} else if (strcmp(argv[i], "-mavx") == 0) {
|
|
|
|
mflags |= IR_AVX;
|
2022-05-17 21:37:13 +02:00
|
|
|
} else if (strcmp(argv[i], "-muse-fp") == 0) {
|
|
|
|
mflags |= IR_USE_FRAME_POINTER;
|
2022-04-27 13:47:52 +02:00
|
|
|
#ifdef IR_DEBUG
|
|
|
|
} else if (strcmp(argv[i], "--debug-sccp") == 0) {
|
|
|
|
mflags |= IR_DEBUG_SCCP;
|
|
|
|
} else if (strcmp(argv[i], "--debug-gcm") == 0) {
|
|
|
|
mflags |= IR_DEBUG_GCM;
|
2022-05-24 17:04:38 +02:00
|
|
|
} else if (strcmp(argv[i], "--debug-schedule") == 0) {
|
|
|
|
mflags |= IR_DEBUG_SCHEDULE;
|
2022-04-27 13:47:52 +02:00
|
|
|
} else if (strcmp(argv[i], "--debug-ra") == 0) {
|
|
|
|
mflags |= IR_DEBUG_RA;
|
2022-05-13 08:22:31 +02:00
|
|
|
#endif
|
2022-04-27 13:47:52 +02:00
|
|
|
} else if (strcmp(argv[i], "--debug-regset") == 0) {
|
|
|
|
if (i + 1 == argc || argv[i + 1][0] == '-') {
|
|
|
|
fprintf(stderr, "ERROR: Invalid usage' (use --help)\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2022-05-31 23:34:45 +02:00
|
|
|
debug_regset = strtoull(argv[i + 1], NULL, 0);
|
2022-04-27 13:47:52 +02:00
|
|
|
i++;
|
2022-04-19 10:03:01 +02:00
|
|
|
} else {
|
|
|
|
/* pass*/
|
|
|
|
}
|
|
|
|
}
|
2022-04-05 23:19:23 +02:00
|
|
|
|
|
|
|
ir_init(&ctx, 256, 1024);
|
2022-04-19 10:03:01 +02:00
|
|
|
ctx.flags |= IR_FUNCTION;
|
|
|
|
ctx.flags |= mflags;
|
|
|
|
if (opt_level > 0) {
|
2022-10-05 15:29:49 +02:00
|
|
|
ctx.flags |= IR_OPT_FOLDING | IR_OPT_CFG | IR_OPT_CODEGEN;
|
2022-04-19 10:03:01 +02:00
|
|
|
}
|
2022-06-21 15:13:14 +02:00
|
|
|
ctx.fixed_regset = ~debug_regset;
|
2022-09-08 09:50:07 +02:00
|
|
|
gen_mandelbrot(&ctx);
|
|
|
|
// ir_save(&ctx, stderr);
|
2022-04-05 23:19:23 +02:00
|
|
|
|
|
|
|
ir_build_def_use_lists(&ctx);
|
2022-04-19 10:03:01 +02:00
|
|
|
if (opt_level > 1) {
|
|
|
|
ir_sccp(&ctx);
|
|
|
|
}
|
2022-04-05 23:19:23 +02:00
|
|
|
ir_build_cfg(&ctx);
|
2022-04-19 10:03:01 +02:00
|
|
|
if (opt_level > 0) {
|
|
|
|
ir_build_dominators_tree(&ctx);
|
|
|
|
ir_find_loops(&ctx);
|
|
|
|
ir_gcm(&ctx);
|
|
|
|
ir_schedule(&ctx);
|
|
|
|
}
|
2022-04-05 23:19:23 +02:00
|
|
|
ir_match(&ctx);
|
|
|
|
ir_assign_virtual_registers(&ctx);
|
2022-04-19 10:03:01 +02:00
|
|
|
if (opt_level > 0) {
|
|
|
|
ir_compute_live_ranges(&ctx);
|
|
|
|
ir_coalesce(&ctx);
|
|
|
|
ir_reg_alloc(&ctx);
|
2022-05-23 23:43:35 +02:00
|
|
|
ir_schedule_blocks(&ctx);
|
2022-04-19 10:03:01 +02:00
|
|
|
} else {
|
|
|
|
ir_compute_dessa_moves(&ctx);
|
|
|
|
}
|
2022-04-05 23:19:23 +02:00
|
|
|
|
2022-09-08 09:50:07 +02:00
|
|
|
ir_truncate(&ctx);
|
|
|
|
// ir_dump(&ctx, stderr);
|
|
|
|
ir_save(&ctx, stderr);
|
|
|
|
ir_dump_live_ranges(&ctx, stderr);
|
|
|
|
f = fopen("ir.dot", "w+");
|
|
|
|
ir_dump_dot(&ctx, f);
|
|
|
|
fclose(f);
|
2022-04-05 23:19:23 +02:00
|
|
|
|
|
|
|
size_t size;
|
2022-05-27 12:18:04 +02:00
|
|
|
void *entry = ir_emit_code(&ctx, &size);
|
2022-04-05 23:19:23 +02:00
|
|
|
|
|
|
|
if (entry) {
|
2022-06-16 22:49:27 +02:00
|
|
|
ir_disasm("test", entry, size, 0, &ctx, stderr);
|
2022-04-05 23:19:23 +02:00
|
|
|
|
|
|
|
ir_perf_map_register("test", entry, size);
|
|
|
|
ir_perf_jitdump_open();
|
|
|
|
ir_perf_jitdump_register("test", entry, size);
|
|
|
|
|
|
|
|
ir_mem_unprotect(entry, 4096);
|
|
|
|
ir_gdb_register("test", entry, size, 0, 0);
|
|
|
|
ir_mem_protect(entry, 4096);
|
|
|
|
|
|
|
|
run((mandelbrot_t)entry);
|
|
|
|
|
|
|
|
ir_perf_jitdump_close();
|
|
|
|
}
|
|
|
|
|
|
|
|
ir_free(&ctx);
|
|
|
|
return 0;
|
|
|
|
}
|