mirror of
https://github.com/danog/ir.git
synced 2024-12-02 09:38:29 +01:00
Cleanup examples and README
This commit is contained in:
parent
e80fc065f3
commit
5053577e08
24
Makefile
24
Makefile
@ -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
|
||||||
|
73
README.md
73
README.md
@ -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.
|
||||||
|
@ -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);
|
||||||
|
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
2
ir.h
2
ir.h
@ -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);
|
||||||
|
@ -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]);
|
||||||
|
@ -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
48
test.ir
@ -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);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user