Cleanup examples and README

This commit is contained in:
Dmitry Stogov 2023-12-29 12:33:06 +03:00
parent e80fc065f3
commit 5053577e08
8 changed files with 81 additions and 74 deletions

View File

@ -60,11 +60,14 @@ OBJS_COMMON = $(BUILD_DIR)/ir.o $(BUILD_DIR)/ir_strtab.o $(BUILD_DIR)/ir_cfg.o \
$(BUILD_DIR)/ir_disasm.o $(BUILD_DIR)/ir_gdb.o $(BUILD_DIR)/ir_perf.o $(BUILD_DIR)/ir_check.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_emit_llvm.o $(BUILD_DIR)/ir_cpuinfo.o $(BUILD_DIR)/ir_emit_llvm.o
OBJS_IR = $(BUILD_DIR)/ir_main.o $(LLVM_OBJS) OBJS_IR = $(BUILD_DIR)/ir_main.o $(LLVM_OBJS)
OBJS_IR_TEST = $(BUILD_DIR)/ir_test.o EXAMPLE_EXES = $(EXAMPLES_BUILD_DIR)/mandelbrot \
EXAMPLE_EXES = $(EXAMPLES_BUILD_DIR)/0001-basic $(EXAMPLES_BUILD_DIR)/0001-while $(EXAMPLES_BUILD_DIR)/0005-basic-runner-func \ $(EXAMPLES_BUILD_DIR)/0001-basic \
$(EXAMPLES_BUILD_DIR)/0001-pointer $(EXAMPLES_BUILD_DIR)/0001-func $(EXAMPLES_BUILD_DIR)/0001-while \
$(EXAMPLES_BUILD_DIR)/0001-pointer \
$(EXAMPLES_BUILD_DIR)/0001-func \
$(EXAMPLES_BUILD_DIR)/0005-basic-runner-func
all: $(BUILD_DIR) $(BUILD_DIR)/ir $(BUILD_DIR)/ir_test $(BUILD_DIR)/tester all: $(BUILD_DIR) $(BUILD_DIR)/ir $(BUILD_DIR)/tester
$(BUILD_DIR): $(BUILD_DIR):
@mkdir -p $(BUILD_DIR) @mkdir -p $(BUILD_DIR)
@ -75,13 +78,9 @@ $(EXAMPLES_BUILD_DIR):
$(BUILD_DIR)/ir: $(OBJS_COMMON) $(OBJS_IR) $(BUILD_DIR)/ir: $(OBJS_COMMON) $(OBJS_IR)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LLVM_LIBS) -lcapstone $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LLVM_LIBS) -lcapstone
$(BUILD_DIR)/ir_test: $(OBJS_COMMON) $(OBJS_IR_TEST)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) -lcapstone
$(OBJS_COMMON): $(SRC_DIR)/ir.h $(SRC_DIR)/ir_private.h $(OBJS_COMMON): $(SRC_DIR)/ir.h $(SRC_DIR)/ir_private.h
$(BUILD_DIR)/ir_main.o: $(SRC_DIR)/ir.h $(BUILD_DIR)/ir_main.o: $(SRC_DIR)/ir.h
$(BUILD_DIR)/ir_test.o: $(SRC_DIR)/ir.h $(SRC_DIR)/ir_builder.h
$(BUILD_DIR)/ir.o: $(SRC_DIR)/ir_fold.h $(BUILD_DIR)/ir_fold_hash.h $(BUILD_DIR)/ir.o: $(SRC_DIR)/ir_fold.h $(BUILD_DIR)/ir_fold_hash.h
$(BUILD_DIR)/ir_ra.o: $(SRC_DIR)/ir_$(DASM_ARCH).h $(BUILD_DIR)/ir_ra.o: $(SRC_DIR)/ir_$(DASM_ARCH).h
$(BUILD_DIR)/ir_emit.o: $(SRC_DIR)/ir_$(DASM_ARCH).h $(BUILD_DIR)/ir_emit_$(DASM_ARCH).h $(BUILD_DIR)/ir_emit.o: $(SRC_DIR)/ir_$(DASM_ARCH).h $(BUILD_DIR)/ir_emit_$(DASM_ARCH).h
@ -103,7 +102,7 @@ $(BUILD_DIR)/minilua: $(SRC_DIR)/dynasm/minilua.c
$(BUILD_DIR)/ir_emit_$(DASM_ARCH).h: $(SRC_DIR)/ir_$(DASM_ARCH).dasc $(SRC_DIR)/dynasm/*.lua $(BUILD_DIR)/minilua $(BUILD_DIR)/ir_emit_$(DASM_ARCH).h: $(SRC_DIR)/ir_$(DASM_ARCH).dasc $(SRC_DIR)/dynasm/*.lua $(BUILD_DIR)/minilua
$(BUILD_DIR)/minilua $(SRC_DIR)/dynasm/dynasm.lua $(DASM_FLAGS) -o $@ $(SRC_DIR)/ir_$(DASM_ARCH).dasc $(BUILD_DIR)/minilua $(SRC_DIR)/dynasm/dynasm.lua $(DASM_FLAGS) -o $@ $(SRC_DIR)/ir_$(DASM_ARCH).dasc
$(OBJS_COMMON) $(OBJS_IR) $(OBJS_IR_TEST): $(BUILD_DIR)/$(notdir %.o): $(SRC_DIR)/$(notdir %.c) $(OBJS_COMMON) $(OBJS_IR): $(BUILD_DIR)/$(notdir %.o): $(SRC_DIR)/$(notdir %.c)
$(CC) $(CFLAGS) -I$(BUILD_DIR) -o $@ -c $< $(CC) $(CFLAGS) -I$(BUILD_DIR) -o $@ -c $<
$(EXAMPLE_EXES): $(EXAMPLES_BUILD_DIR)/$(notdir %): $(EXAMPLES_SRC_DIR)/$(notdir %.c) $(EXAMPLE_EXES): $(EXAMPLES_BUILD_DIR)/$(notdir %): $(EXAMPLES_SRC_DIR)/$(notdir %.c)
@ -113,9 +112,6 @@ $(BUILD_DIR)/tester: $(SRC_DIR)/tools/tester.c
$(CC) $(BUILD_CFLAGS) -o $@ $< $(CC) $(BUILD_CFLAGS) -o $@ $<
test: $(BUILD_DIR)/ir $(BUILD_DIR)/tester test: $(BUILD_DIR)/ir $(BUILD_DIR)/tester
$(BUILD_DIR)/ir $(SRC_DIR)/test.ir --dump --save 2>$(BUILD_DIR)/test.log
$(BUILD_DIR)/ir $(SRC_DIR)/test.ir --dot $(BUILD_DIR)/ir.dot
dot -Tpdf $(BUILD_DIR)/ir.dot -o $(BUILD_DIR)/ir.pdf
$(BUILD_DIR)/tester --test-cmd $(BUILD_DIR)/ir --target $(TARGET) --default-args "--save" \ $(BUILD_DIR)/tester --test-cmd $(BUILD_DIR)/ir --target $(TARGET) --default-args "--save" \
--test-extension ".irt" --code-extension ".ir" $(SRC_DIR)/tests --test-extension ".irt" --code-extension ".ir" $(SRC_DIR)/tests
@ -126,10 +122,10 @@ test-ci: $(BUILD_DIR)/ir $(BUILD_DIR)/tester
examples: $(OBJS_COMMON) $(EXAMPLES_BUILD_DIR) $(EXAMPLE_EXES) examples: $(OBJS_COMMON) $(EXAMPLES_BUILD_DIR) $(EXAMPLE_EXES)
clean: clean:
rm -rf $(BUILD_DIR)/ir $(BUILD_DIR)/ir_test $(BUILD_DIR)/*.o \ rm -rf $(BUILD_DIR)/ir $(BUILD_DIR)/*.o \
$(BUILD_DIR)/minilua $(BUILD_DIR)/ir_emit_$(DASM_ARCH).h \ $(BUILD_DIR)/minilua $(BUILD_DIR)/ir_emit_$(DASM_ARCH).h \
$(BUILD_DIR)/ir_fold_hash.h $(BUILD_DIR)/gen_ir_fold_hash \ $(BUILD_DIR)/ir_fold_hash.h $(BUILD_DIR)/gen_ir_fold_hash \
$(BUILD_DIR)/ir.dot $(BUILD_DIR)/ir.pdf $(BUILD_DIR)/test.log \ $(EXAMPLE_EXES) \
$(BUILD_DIR)/tester $(BUILD_DIR)/tester
find $(SRC_DIR)/tests -type f -name '*.diff' -delete find $(SRC_DIR)/tests -type f -name '*.diff' -delete
find $(SRC_DIR)/tests -type f -name '*.out' -delete find $(SRC_DIR)/tests -type f -name '*.out' -delete

View File

@ -37,7 +37,9 @@ the LuaJIT IR designed by Mike Pall [3].
## IR Generation ## IR Generation
TODO... IR Framework provides a simple IR Builder API ([ir_builder.h](ir_builder.h)).
It's implemented as a number of C preprocessor macros, where each macro just
creates a corresponding IR node and ties it with the sources.
## IR Optimization ## IR Optimization
@ -56,6 +58,9 @@ IR in a proper (Reverse Post) order, that would emit all Nodes before their
first usage. (In case of different order the scope of the folding should be first usage. (In case of different order the scope of the folding should be
limited). limited).
All the folding rules are written in a declarative style in the single file -
[ir_fold.h](ir_fold.h)
Folding Engine performs Constants Folding, Copy Propagation, Algebraic Folding Engine performs Constants Folding, Copy Propagation, Algebraic
Simplifications, Algebraic Re-Association and Common Sub-Expression Simplifications, Algebraic Re-Association and Common Sub-Expression
Elimination. The simple and fast declarative implementation is borrowed from Elimination. The simple and fast declarative implementation is borrowed from
@ -113,13 +118,30 @@ and inserts the necessary spill load/store and SSA deconstruction code.
- GDB/JIT interface to allow debugging of JIT-ed code - GDB/JIT interface to allow debugging of JIT-ed code
- Linux perf interface to analyze the code performance - Linux perf interface to analyze the code performance
## LLVM interopability ## Building and Playing with IR
Under development... IR Framework is under active development and doesn't provide any stable libraries yet.
In case you like to you IR, it's better to embed the necessary sources into your project
(like [PHP]((https://github.com/php/php-src/tree/master/ext/opcache/jit)) does].
However, we provide a simple driver that may be built to run tests and play with IR.
```
git clone https://github.com/dstogov/ir.git
cd ir
make
make test
./ir bench/mandelbrit.ir --run
./ir bench/mandelbrit.ir -S
./ir --help
```
## IR Example ## IR Example
Let's try to generate code for the following function: The complete described example may be found in [examples/mandelbrot.c](examples/mandelbrot.c))
and built using ``make examples``.
It generate the code for the following C function:
```c ```c
int32_t mandelbrot(double x, double y) int32_t mandelbrot(double x, double y)
@ -146,7 +168,7 @@ int32_t mandelbrot(double x, double y)
} }
``` ```
This may be done through IR construction API by the following code: This is done through IR builder API by the following code:
```c ```c
void gen_mandelbrot(ir_ctx *ctx) void gen_mandelbrot(ir_ctx *ctx)
@ -234,9 +256,16 @@ The textual representation of the IR after system independent optimizations:
``` ```
The visualized graph: The visualized graph:
![IR example](example.svg) ![IR example](examples/mandelbrot.svg)
The final generated code: The graph was generated by the commands:
```
./ir bench/mandelbrot.ir --dot mandelbrot.dot
dot -Tsvg mandelbrot.dot -o mandelbrot.svg
```
The final generated assembler code:
```asm ```asm
test: test:
@ -275,6 +304,36 @@ test:
.db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x40 .db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x40
``` ```
## LLVM interopability
IR is partially compatible with LLVM. It's possible to convert IR
into LLVM and then compile it.
```
./ir bench/mandelbrot.ir --emit-llvm mandelbrot.ll
llc mandelbrot.ll
gcc mandelbrot.s
./a.out
```
It's also possible to read an LLVM file and convert it to IR, but this
requres LLVM loader and therefore IR should be rebuilt with LLVM support.
```
make clean
make HAVE_LLVM=yes
```
Now you may compile some C file into LLVM, and then convert it to IR.
```
clang -O2 -fno-vectorize -fno-slp-vectorize -S -emit-llvm -o minilua.ll ./dynasm/minilua.c
./ir --llvm-asm minilua.ll --save 2>minilua.ir
./ir minilua.ir --run bench/mandelbrot.lua
```
Note that the last comand above compiles and runs the Lua interpreter.
## PHP JIT based on IR ## PHP JIT based on IR
A new experimental JIT for PHP based on this project is developed at [master](https://github.com/php/php-src/tree/master/ext/opcache/jit) php-src branch. A new experimental JIT for PHP based on this project is developed at [master](https://github.com/php/php-src/tree/master/ext/opcache/jit) php-src branch.

View File

@ -191,7 +191,7 @@ int main(int argc, char **argv)
// ir_dump(&ctx, stderr); // ir_dump(&ctx, stderr);
ir_save(&ctx, stderr); ir_save(&ctx, stderr);
ir_dump_live_ranges(&ctx, stderr); ir_dump_live_ranges(&ctx, stderr);
f = fopen("ir.dot", "w+"); f = fopen("mandelbrot.dot", "w+");
ir_dump_dot(&ctx, f); ir_dump_dot(&ctx, f);
fclose(f); fclose(f);

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

2
ir.h
View File

@ -827,7 +827,7 @@ void ir_save(const ir_ctx *ctx, FILE *f);
/* IR debug dump API (implementation in ir_dump.c) */ /* IR debug dump API (implementation in ir_dump.c) */
void ir_dump(const ir_ctx *ctx, FILE *f); void ir_dump(const ir_ctx *ctx, FILE *f);
void ir_dump_dot(const ir_ctx *ctx, FILE *f); void ir_dump_dot(const ir_ctx *ctx, const char *name, FILE *f);
void ir_dump_use_lists(const ir_ctx *ctx, FILE *f); void ir_dump_use_lists(const ir_ctx *ctx, FILE *f);
void ir_dump_cfg(ir_ctx *ctx, FILE *f); void ir_dump_cfg(ir_ctx *ctx, FILE *f);
void ir_dump_cfg_map(const ir_ctx *ctx, FILE *f); void ir_dump_cfg_map(const ir_ctx *ctx, FILE *f);

View File

@ -52,7 +52,7 @@ void ir_dump(const ir_ctx *ctx, FILE *f)
} }
} }
void ir_dump_dot(const ir_ctx *ctx, FILE *f) void ir_dump_dot(const ir_ctx *ctx, const char *name, FILE *f)
{ {
int DATA_WEIGHT = 0; int DATA_WEIGHT = 0;
int CONTROL_WEIGHT = 5; int CONTROL_WEIGHT = 5;
@ -61,7 +61,7 @@ void ir_dump_dot(const ir_ctx *ctx, FILE *f)
ir_insn *insn; ir_insn *insn;
uint32_t flags; uint32_t flags;
fprintf(f, "digraph ir {\n"); fprintf(f, "digraph %s {\n", name);
fprintf(f, "\trankdir=TB;\n"); fprintf(f, "\trankdir=TB;\n");
for (i = 1 - ctx->consts_count, insn = ctx->ir_base + i; i < IR_UNUSED; i++, insn++) { for (i = 1 - ctx->consts_count, insn = ctx->ir_base + i; i < IR_UNUSED; i++, insn++) {
fprintf(f, "\tc%d [label=\"C%d: CONST %s(", -i, -i, ir_type_name[insn->type]); fprintf(f, "\tc%d [label=\"C%d: CONST %s(", -i, -i, ir_type_name[insn->type]);

View File

@ -131,7 +131,7 @@ static int _save(ir_ctx *ctx, uint32_t dump, uint32_t pass, FILE *f, const char
ir_dump(ctx, f); ir_dump(ctx, f);
} }
if (dump & IR_DUMP_DOT) { if (dump & IR_DUMP_DOT) {
ir_dump_dot(ctx, f); ir_dump_dot(ctx, func_name, f);
} }
if (dump & IR_DUMP_USE_LISTS) { if (dump & IR_DUMP_USE_LISTS) {
ir_dump_use_lists(ctx, f); ir_dump_use_lists(ctx, f);

48
test.ir
View File

@ -1,48 +0,0 @@
{
uintptr_t c_1 = 0;
bool c_2 = 0;
bool c_3 = 1;
double c_4 = 0.5;
double c_5 = 0;
int32_t c_6 = 0;
int32_t c_7 = 1;
double c_8 = 16;
int32_t c_9 = 1000;
l_1 = START(l_35);
double d_2 = PARAM(l_1, "x", 0);
double d_3 = PARAM(l_1, "y", 1);
double d_4 = VAR(l_1, "cr");
double d_5 = SUB(d_3, c_4);
double d_6 = VAR(l_1, "ci");
double d_7 = VAR(l_1, "zi");
double d_8 = VAR(l_1, "zr");
int32_t d_9 = VAR(l_1, "i");
l_10 = END(l_1);
l_11 = LOOP_BEGIN(l_10, l_37);
double d_12 = PHI(l_11, c_5, d_25);
double d_13 = PHI(l_11, c_5, d_23);
int32_t d_14 = PHI(l_11, c_6, d_15);
int32_t d_15 = ADD(d_14, c_7);
double d_16 = VAR(l_11, "temp");
double d_17 = MUL(d_13, d_12);
double d_18 = VAR(l_11, "zr2");
double d_19 = MUL(d_13, d_13);
double d_20 = VAR(l_11, "zi2");
double d_21 = MUL(d_12, d_12);
double d_22 = SUB(d_19, d_21);
double d_23 = ADD(d_22, d_5);
double d_24 = ADD(d_17, d_17);
double d_25 = ADD(d_24, d_2);
double d_26 = ADD(d_21, d_19);
bool d_27 = GT(d_26, c_8);
l_28 = IF(l_11, d_27);
l_29 = IF_TRUE(l_28);
l_30 = RETURN(l_29, d_15);
l_31 = IF_FALSE(l_28);
bool d_32 = GT(d_15, c_9);
l_33 = IF(l_31, d_32);
l_34 = IF_TRUE(l_33);
l_35 = RETURN(l_34, c_6, l_30);
l_36 = IF_FALSE(l_33);
l_37 = LOOP_END(l_36);
}