Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for LLVM loader (incomplete) #53

Merged
merged 5 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ TARGET = x86_64
BUILD = debug
BUILD_DIR = .
SRC_DIR = .
HAVE_LLVM = no
EXAMPLES_SRC_DIR = $(SRC_DIR)/examples
EXAMPLES_BUILD_DIR = $(BUILD_DIR)/examples

Expand Down Expand Up @@ -39,12 +40,18 @@ ifeq (aarch64, $(TARGET))
DASM_FLAGS = -M
endif

ifeq (yes, $(HAVE_LLVM))
override CFLAGS += -DHAVE_LLVM
LLVM_OBJS=$(BUILD_DIR)/ir_load_llvm.o
LLVM_LIBS=-lLLVM
endif

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_emit_llvm.o
OBJS_IR = $(BUILD_DIR)/ir_main.o
OBJS_IR = $(BUILD_DIR)/ir_main.o $(LLVM_OBJS)
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 \
$(EXAMPLES_BUILD_DIR)/0001-pointer $(EXAMPLES_BUILD_DIR)/0001-func
Expand All @@ -58,7 +65,7 @@ $(EXAMPLES_BUILD_DIR):
@mkdir -p $(EXAMPLES_BUILD_DIR)

$(BUILD_DIR)/ir: $(OBJS_COMMON) $(OBJS_IR)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) -lcapstone
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LLVM_LIBS) -lcapstone

$(BUILD_DIR)/ir_test: $(OBJS_COMMON) $(OBJS_IR_TEST)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) -lcapstone
Expand All @@ -73,6 +80,7 @@ $(BUILD_DIR)/ir_emit.o: $(SRC_DIR)/ir_$(DASM_ARCH).h $(BUILD_DIR)/ir_emit_$(DASM
$(BUILD_DIR)/ir_gdb.o: $(SRC_DIR)/ir_elf.h
$(BUILD_DIR)/ir_perf.o: $(SRC_DIR)/ir_elf.h
$(BUILD_DIR)/ir_disasm.o: $(SRC_DIR)/ir_elf.h
$(BUILD_DIR)/ir_load_llvm.o: $(SRC_DIR)/ir.h $(SRC_DIR)/ir_private.h $(SRC_DIR)/ir_builder.h

$(SRC_DIR)/ir_load.c: $(SRC_DIR)/ir.g
$(LLK) ir.g
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,12 @@ void gen_mandelbrot(ir_ctx *ctx)
ir_ref ci = ir_COPY_D(x);
ir_ref zi = ir_COPY_D(ir_CONST_DOUBLE(0.0));
ir_ref zr = ir_COPY_D(ir_CONST_DOUBLE(0.0));
ir_ref i = ir_COPY_D(ir_CONST_I32(0));
ir_ref i = ir_COPY_I32(ir_CONST_I32(0));

ir_ref loop = ir_LOOP_BEGIN(ir_END());
ir_ref zi_1 = ir_PHI_2(zi, IR_UNUSED);
ir_ref zr_1 = ir_PHI_2(zr, IR_UNUSED);
ir_ref i_1 = ir_PHI_2(i, IR_UNUSED);
ir_ref zi_1 = ir_PHI_2(IR_DOUBLE, zi, IR_UNUSED);
ir_ref zr_1 = ir_PHI_2(IR_DOUBLE, zr, IR_UNUSED);
ir_ref i_1 = ir_PHI_2(IR_I32, i, IR_UNUSED);

ir_ref i_2 = ir_ADD_I32(i_1, ir_CONST_I32(1));
ir_ref temp = ir_MUL_D(zr_1, zi_1);
Expand Down
2 changes: 1 addition & 1 deletion examples/0001-while.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void gen_myfunc(ir_ctx *ctx)
/* Declare loop counter. */
ir_ref i = ir_COPY_I32(ir_CONST_I32(0));
ir_ref loop = ir_LOOP_BEGIN(ir_END());
ir_ref phi_i_1 = ir_PHI_2(i, IR_UNUSED);
ir_ref phi_i_1 = ir_PHI_2(IR_I32, i, IR_UNUSED);
ir_ref i_2 = ir_ADD_I32(phi_i_1, ir_CONST_I32(1));
ir_ref cond = ir_IF(ir_LT(phi_i_1, ir_CONST_I32(42)));
ir_IF_TRUE(cond);
Expand Down
172 changes: 156 additions & 16 deletions ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,104 @@ void ir_hashtab_key_sort(ir_hashtab *tab)
} while (--i);
}

static void ir_addrtab_resize(ir_hashtab *tab)
{
uint32_t old_hash_size = (uint32_t)(-(int32_t)tab->mask);
char *old_data = tab->data;
uint32_t size = tab->size * 2;
uint32_t hash_size = ir_hashtab_hash_size(size);
char *data = ir_mem_malloc(hash_size * sizeof(uint32_t) + size * sizeof(ir_addrtab_bucket));
ir_addrtab_bucket *p;
uint32_t pos, i;

memset(data, -1, hash_size * sizeof(uint32_t));
tab->data = data + (hash_size * sizeof(uint32_t));
tab->mask = (uint32_t)(-(int32_t)hash_size);
tab->size = size;

memcpy(tab->data, old_data, tab->count * sizeof(ir_addrtab_bucket));
ir_mem_free(old_data - (old_hash_size * sizeof(uint32_t)));

i = tab->count;
pos = 0;
p = (ir_addrtab_bucket*)tab->data;
do {
uint32_t key = (uint32_t)p->key | tab->mask;
p->next = ((uint32_t*)tab->data)[(int32_t)key];
((uint32_t*)tab->data)[(int32_t)key] = pos;
pos += sizeof(ir_addrtab_bucket);
p++;
} while (--i);
}

void ir_addrtab_init(ir_hashtab *tab, uint32_t size)
{
IR_ASSERT(size > 0);
uint32_t hash_size = ir_hashtab_hash_size(size);
char *data = ir_mem_malloc(hash_size * sizeof(uint32_t) + size * sizeof(ir_addrtab_bucket));
memset(data, -1, hash_size * sizeof(uint32_t));
tab->data = (data + (hash_size * sizeof(uint32_t)));
tab->mask = (uint32_t)(-(int32_t)hash_size);
tab->size = size;
tab->count = 0;
tab->pos = 0;
}

void ir_addrtab_free(ir_hashtab *tab)
{
uint32_t hash_size = (uint32_t)(-(int32_t)tab->mask);
char *data = (char*)tab->data - (hash_size * sizeof(uint32_t));
ir_mem_free(data);
tab->data = NULL;
}

ir_ref ir_addrtab_find(const ir_hashtab *tab, uint64_t key)
{
const char *data = (const char*)tab->data;
uint32_t pos = ((uint32_t*)data)[(int32_t)(key | tab->mask)];
ir_addrtab_bucket *p;

while (pos != IR_INVALID_IDX) {
p = (ir_addrtab_bucket*)(data + pos);
if (p->key == key) {
return p->val;
}
pos = p->next;
}
return IR_INVALID_VAL;
}

bool ir_addrtab_add(ir_hashtab *tab, uint64_t key, ir_ref val)
{
char *data = (char*)tab->data;
uint32_t pos = ((uint32_t*)data)[(int32_t)(key | tab->mask)];
ir_addrtab_bucket *p;

while (pos != IR_INVALID_IDX) {
p = (ir_addrtab_bucket*)(data + pos);
if (p->key == key) {
return p->val == val;
}
pos = p->next;
}

if (UNEXPECTED(tab->count >= tab->size)) {
ir_addrtab_resize(tab);
data = tab->data;
}

pos = tab->pos;
tab->pos += sizeof(ir_addrtab_bucket);
tab->count++;
p = (ir_addrtab_bucket*)(data + pos);
p->key = key;
p->val = val;
key |= tab->mask;
p->next = ((uint32_t*)data)[(int32_t)key];
((uint32_t*)data)[(int32_t)key] = pos;
return 1;
}

/* Memory API */
#ifdef _WIN32
void *ir_mem_mmap(size_t size)
Expand Down Expand Up @@ -1545,24 +1643,32 @@ ir_ref _ir_PARAM(ir_ctx *ctx, ir_type type, const char* name, ir_ref num)

ir_ref _ir_VAR(ir_ctx *ctx, ir_type type, const char* name)
{
IR_ASSERT(ctx->control);
IR_ASSERT(IR_IS_BB_START(ctx->ir_base[ctx->control].op));
return ir_var(ctx, type, ctx->control, name);
// IR_ASSERT(ctx->control);
// IR_ASSERT(IR_IS_BB_START(ctx->ir_base[ctx->control].op));
// TODO: VAR may be insterted after some "memory" instruction
ir_ref ref = ctx->control;

while (1) {
IR_ASSERT(ctx->control);
if (IR_IS_BB_START(ctx->ir_base[ref].op)) {
break;
}
ref = ctx->ir_base[ref].op1;
}
return ir_var(ctx, type, ref, name);
}

ir_ref _ir_PHI_2(ir_ctx *ctx, ir_ref src1, ir_ref src2)
ir_ref _ir_PHI_2(ir_ctx *ctx, ir_type type, ir_ref src1, ir_ref src2)
{
ir_type type = ctx->ir_base[src1].type;

IR_ASSERT(ctx->control);
IR_ASSERT(ctx->ir_base[ctx->control].op == IR_MERGE || ctx->ir_base[ctx->control].op == IR_LOOP_BEGIN);
if (src1 == src2) {
if (src1 == src2 && src1 != IR_UNUSED) {
return src1;
}
return ir_emit3(ctx, IR_OPTX(IR_PHI, type, 3), ctx->control, src1, src2);
}

ir_ref _ir_PHI_N(ir_ctx *ctx, ir_ref n, ir_ref *inputs)
ir_ref _ir_PHI_N(ir_ctx *ctx, ir_type type, ir_ref n, ir_ref *inputs)
{
IR_ASSERT(ctx->control);
IR_ASSERT(n > 0);
Expand All @@ -1573,17 +1679,19 @@ ir_ref _ir_PHI_N(ir_ctx *ctx, ir_ref n, ir_ref *inputs)
ir_ref ref = inputs[0];

IR_ASSERT(ctx->ir_base[ctx->control].op == IR_MERGE || ctx->ir_base[ctx->control].op == IR_LOOP_BEGIN);
for (i = 1; i < n; i++) {
if (inputs[i] != ref) {
break;
if (ref != IR_UNUSED) {
for (i = 1; i < n; i++) {
if (inputs[i] != ref) {
break;
}
}
if (i == n) {
/* all the same */
return ref;
}
}
if (i == n) {
/* all the same */
return ref;
}

ref = ir_emit_N(ctx, IR_OPT(IR_PHI, ctx->ir_base[inputs[0]].type), n + 1);
ref = ir_emit_N(ctx, IR_OPT(IR_PHI, type), n + 1);
ir_set_op(ctx, ref, 1, ctx->control);
for (i = 0; i < n; i++) {
ir_set_op(ctx, ref, i + 2, inputs[i]);
Expand Down Expand Up @@ -1865,6 +1973,22 @@ ir_ref _ir_CALL_5(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref ar
return call;
}

ir_ref _ir_CALL_N(ir_ctx *ctx, ir_type type, ir_ref func, uint32_t count, ir_ref *args)
{
ir_ref call;
uint32_t i;

IR_ASSERT(ctx->control);
call = ir_emit_N(ctx, IR_OPT(IR_CALL, type), count + 2);
ir_set_op(ctx, call, 1, ctx->control);
ir_set_op(ctx, call, 2, func);
for (i = 0; i < count; i++) {
ir_set_op(ctx, call, i + 3, args[i]);
}
ctx->control = call;
return call;
}

void _ir_UNREACHABLE(ir_ctx *ctx)
{
IR_ASSERT(ctx->control);
Expand Down Expand Up @@ -1949,6 +2073,22 @@ void _ir_TAILCALL_5(ir_ctx *ctx, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref a
_ir_UNREACHABLE(ctx);
}

void _ir_TAILCALL_N(ir_ctx *ctx, ir_ref func, uint32_t count, ir_ref *args)
{
ir_ref call;
uint32_t i;

IR_ASSERT(ctx->control);
call = ir_emit_N(ctx, IR_TAILCALL, count + 2);
ir_set_op(ctx, call, 1, ctx->control);
ir_set_op(ctx, call, 2, func);
for (i = 0; i < count; i++) {
ir_set_op(ctx, call, i + 3, args[i]);
}
ctx->control = call;
_ir_UNREACHABLE(ctx);
}

ir_ref _ir_SWITCH(ir_ctx *ctx, ir_ref val)
{
ir_ref ref;
Expand Down
4 changes: 4 additions & 0 deletions ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,10 @@ void ir_loader_init(void);
void ir_loader_free(void);
int ir_load(ir_ctx *ctx, FILE *f);

/* IR LLVM load API (implementation in ir_load_llvm.c) */
int ir_load_llvm_bitcode(const char *filename, uint32_t flags);
int ir_load_llvm_asm(const char *filename, uint32_t flags);

/* IR save API (implementation in ir_save.c) */
void ir_save(const ir_ctx *ctx, FILE *f);

Expand Down
Loading