Fixed several LLVM loader bugs

This commit is contained in:
Dmitry Stogov 2023-12-14 01:30:48 +03:00
parent 27f5e34d90
commit 5b2619243a
3 changed files with 67 additions and 17 deletions

1
ir.h
View File

@ -798,6 +798,7 @@ struct _ir_loader {
uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types); uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types);
bool (*sym_dcl) (ir_loader *loader, const char *name, uint32_t flags, size_t size, bool has_data); bool (*sym_dcl) (ir_loader *loader, const char *name, uint32_t flags, size_t size, bool has_data);
bool (*sym_data) (ir_loader *loader, ir_type type, uint32_t count, const void *data); bool (*sym_data) (ir_loader *loader, ir_type type, uint32_t count, const void *data);
bool (*sym_data_pad) (ir_loader *loader, size_t offset);
bool (*sym_data_ref) (ir_loader *loader, ir_op op, const char *ref); bool (*sym_data_ref) (ir_loader *loader, ir_op op, const char *ref);
bool (*sym_data_end) (ir_loader *loader); bool (*sym_data_end) (ir_loader *loader);
bool (*func_init) (ir_loader *loader, ir_ctx *ctx, const char *name); bool (*func_init) (ir_loader *loader, ir_ctx *ctx, const char *name);

View File

@ -47,7 +47,6 @@ static ir_type llvm2ir_type(LLVMTypeRef type)
case 32: return IR_I32; case 32: return IR_I32;
case 64: return IR_I64; case 64: return IR_I64;
default: default:
IR_ASSERT(0);
break; break;
} }
break; break;
@ -152,8 +151,9 @@ static ir_ref llvm2ir_op(ir_ctx *ctx, LLVMValueRef op, ir_type type)
ir_ref proto; ir_ref proto;
ir_val val; ir_val val;
char buf[256]; char buf[256];
LLVMValueKind kind = LLVMGetValueKind(op);
switch (LLVMGetValueKind(op)) { switch (kind) {
case LLVMConstantIntValueKind: case LLVMConstantIntValueKind:
IR_ASSERT(IR_IS_TYPE_INT(type)); IR_ASSERT(IR_IS_TYPE_INT(type));
if (IR_IS_TYPE_SIGNED(type)) { if (IR_IS_TYPE_SIGNED(type)) {
@ -201,9 +201,12 @@ static ir_ref llvm2ir_op(ir_ctx *ctx, LLVMValueRef op, ir_type type)
name = LLVMGetValueName2(op, &name_len); name = LLVMGetValueName2(op, &name_len);
return ir_const_func(ctx, ir_strl(ctx, name, name_len), proto); return ir_const_func(ctx, ir_strl(ctx, name, name_len), proto);
case LLVMUndefValueValueKind: case LLVMUndefValueValueKind:
case LLVMPoisonValueValueKind:
// TODO: ???
val.u64 = 0; val.u64 = 0;
return ir_const(ctx, val, type); return ir_const(ctx, val, type);
default: default:
fprintf(stderr, "Unsupported LLVM value kind: %d\n", kind);
IR_ASSERT(0); IR_ASSERT(0);
return 0; return 0;
} }
@ -522,6 +525,9 @@ static ir_ref llvm2ir_intrinsic(ir_ctx *ctx, LLVMValueRef insn, LLVMTypeRef ftyp
} else if (STR_START(name, name_len, "llvm.dbg.")) { } else if (STR_START(name, name_len, "llvm.dbg.")) {
/* skip */ /* skip */
return IR_NULL; return IR_NULL;
} else if (STR_EQUAL(name, name_len, "llvm.experimental.noalias.scope.decl")) {
/* skip */
return IR_NULL;
} else if (STR_EQUAL(name, name_len, "llvm.assume")) { } else if (STR_EQUAL(name, name_len, "llvm.assume")) {
/* skip */ /* skip */
return IR_NULL; return IR_NULL;
@ -1127,10 +1133,8 @@ static ir_ref llvm2ir_const_element_ptr(ir_ctx *ctx, LLVMValueRef expr)
type_kind = LLVMGetTypeKind(type); type_kind = LLVMGetTypeKind(type);
IR_ASSERT(type_kind == LLVMPointerTypeKind); IR_ASSERT(type_kind == LLVMPointerTypeKind);
if (LLVMGetValueKind(op0) == LLVMGlobalVariableValueKind) { type = LLVMGetGEPSourceElementType(expr);
type = LLVMGlobalGetValueType(op0); type_kind = LLVMGetTypeKind(type);
type_kind = LLVMGetTypeKind(type);
}
op = LLVMGetOperand(expr, 1); op = LLVMGetOperand(expr, 1);
IR_ASSERT(LLVMGetValueKind(op) == LLVMConstantIntValueKind); IR_ASSERT(LLVMGetValueKind(op) == LLVMConstantIntValueKind);
@ -1932,7 +1936,7 @@ static int llvm2ir_forward_func(ir_loader *loader, const char *name, LLVMValueRe
return loader->forward_func_dcl(loader, name, flags, ret_type, count, param_types); return loader->forward_func_dcl(loader, name, flags, ret_type, count, param_types);
} }
static int llvm2ir_data(ir_loader *loader, LLVMTargetDataRef target_data, LLVMTypeRef type, LLVMValueRef op) static int llvm2ir_data(ir_loader *loader, LLVMTargetDataRef target_data, LLVMTypeRef type, LLVMValueRef op, size_t pos)
{ {
LLVMTypeRef el_type; LLVMTypeRef el_type;
LLVMValueRef el; LLVMValueRef el;
@ -1944,6 +1948,7 @@ static int llvm2ir_data(ir_loader *loader, LLVMTargetDataRef target_data, LLVMTy
size_t name_len; size_t name_len;
char buf[256]; char buf[256];
void *p = NULL; void *p = NULL;
size_t offset, el_size;
LLVMValueKind kind = LLVMGetValueKind(op); LLVMValueKind kind = LLVMGetValueKind(op);
switch (kind) { switch (kind) {
@ -1981,22 +1986,27 @@ static int llvm2ir_data(ir_loader *loader, LLVMTargetDataRef target_data, LLVMTy
case LLVMConstantArrayValueKind: case LLVMConstantArrayValueKind:
case LLVMConstantDataArrayValueKind: case LLVMConstantDataArrayValueKind:
el_type = LLVMGetElementType(type); el_type = LLVMGetElementType(type);
el_size = LLVMABISizeOfType(target_data, el_type);
len = LLVMGetArrayLength(type); len = LLVMGetArrayLength(type);
offset = 0;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
el = LLVMGetAggregateElement(op, i); el = LLVMGetAggregateElement(op, i);
if (!llvm2ir_data(loader, target_data, el_type, el)) { if (!llvm2ir_data(loader, target_data, el_type, el, pos)) {
return 0; return 0;
} }
pos += el_size;
} }
return 1; return 1;
case LLVMConstantStructValueKind: case LLVMConstantStructValueKind:
len = LLVMCountStructElementTypes(type); len = LLVMCountStructElementTypes(type);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
// TODO: support for offset and alignment offset = LLVMOffsetOfElement(target_data, type, i);
// offset = LLVMOffsetOfElement(target_data, type, i); if (i > 0 && loader->sym_data_pad) {
loader->sym_data_pad(loader, pos + offset);
}
el_type = LLVMStructGetTypeAtIndex(type, i); el_type = LLVMStructGetTypeAtIndex(type, i);
el = LLVMGetAggregateElement(op, i); el = LLVMGetAggregateElement(op, i);
if (!llvm2ir_data(loader, target_data, el_type, el)) { if (!llvm2ir_data(loader, target_data, el_type, el, pos + offset)) {
return 0; return 0;
} }
} }
@ -2038,9 +2048,20 @@ static int llvm2ir_data(ir_loader *loader, LLVMTargetDataRef target_data, LLVMTy
// case LLVMConstantExprValueKind: // case LLVMConstantExprValueKind:
// IR_ASSERT(0); // IR_ASSERT(0);
// return 0; // return 0;
// case LLVMUndefValueValueKind: case LLVMUndefValueValueKind:
// IR_ASSERT(0); case LLVMPoisonValueValueKind:
// return 0; // TODO: ???
if (LLVMGetTypeKind(type) == LLVMArrayTypeKind) {
el_type = LLVMGetElementType(type);
len = LLVMGetArrayLength(type);
t = llvm2ir_type(el_type);
val.i64 = 0;
return loader->sym_data(loader, t, len, &val.i64);
} else {
t = llvm2ir_type(type);
val.i64 = 0;
return loader->sym_data(loader, t, 1, &val.i64);
}
default: default:
fprintf(stderr, "Unsupported LLVM value kind: %d\n", kind); fprintf(stderr, "Unsupported LLVM value kind: %d\n", kind);
IR_ASSERT(0); IR_ASSERT(0);
@ -2125,7 +2146,7 @@ static int ir_load_llvm_module(ir_loader *loader, LLVMModuleRef module)
return 0; return 0;
} }
if (has_data) { if (has_data) {
llvm2ir_data(loader, target_data, type, init); llvm2ir_data(loader, target_data, type, init, 0);
if (!loader->sym_data_end(loader)) { if (!loader->sym_data_end(loader)) {
return 0; return 0;
} }

View File

@ -253,6 +253,7 @@ typedef struct _ir_main_loader {
ir_strtab symtab; ir_strtab symtab;
ir_sym *sym; ir_sym *sym;
ir_ref sym_count; ir_ref sym_count;
void *data_start;
void *data; void *data;
ir_code_buffer code_buffer; ir_code_buffer code_buffer;
} ir_main_loader; } ir_main_loader;
@ -456,7 +457,7 @@ static bool ir_loader_sym_dcl(ir_loader *loader, const char *name, uint32_t flag
} }
memset(data, 0, size); memset(data, 0, size);
if (has_data) { if (has_data) {
l->data = data; l->data_start = l->data = data;
} }
if (l->dump_asm) { if (l->dump_asm) {
ir_disasm_add_symbol(name, (uintptr_t)data, size); ir_disasm_add_symbol(name, (uintptr_t)data, size);
@ -514,13 +515,39 @@ static bool ir_loader_sym_data(ir_loader *loader, ir_type type, uint32_t count,
if (!l->data) { if (!l->data) {
return 0; return 0;
} }
// TODO: alignement
memcpy(l->data, data, size); memcpy(l->data, data, size);
l->data = (void*)((uintptr_t)l->data + size); l->data = (void*)((uintptr_t)l->data + size);
} }
return 1; return 1;
} }
static bool ir_loader_sym_data_pad(ir_loader *loader, size_t offset)
{
ir_main_loader *l = (ir_main_loader*) loader;
size_t i;
IR_ASSERT(offset >= (size_t)((char*)l->data - (char*)l->data_start));
offset -= (char*)l->data - (char*)l->data_start;
if (offset) {
if ((l->dump & IR_DUMP_SAVE) && (l->dump_file)) {
for (i = 0; i < offset; i++) {
fprintf(l->dump_file, "\tuint8_t 0x00,\n");
}
}
if (l->c_file) {
// TODO:
}
if (l->llvm_file) {
// TODO:
}
if (l->dump_asm || l->dump_size || l->run) {
memset(l->data, 0, offset);
l->data = (void*)((uintptr_t)l->data + offset);
}
}
return 1;
}
static bool ir_loader_sym_data_ref(ir_loader *loader, ir_op op, const char *ref) static bool ir_loader_sym_data_ref(ir_loader *loader, ir_op op, const char *ref)
{ {
ir_main_loader *l = (ir_main_loader*) loader; ir_main_loader *l = (ir_main_loader*) loader;
@ -943,6 +970,7 @@ int main(int argc, char **argv)
loader.loader.forward_func_dcl = ir_loader_forward_func_dcl; loader.loader.forward_func_dcl = ir_loader_forward_func_dcl;
loader.loader.sym_dcl = ir_loader_sym_dcl; loader.loader.sym_dcl = ir_loader_sym_dcl;
loader.loader.sym_data = ir_loader_sym_data; loader.loader.sym_data = ir_loader_sym_data;
loader.loader.sym_data_pad = ir_loader_sym_data_pad;
loader.loader.sym_data_ref = ir_loader_sym_data_ref; loader.loader.sym_data_ref = ir_loader_sym_data_ref;
loader.loader.sym_data_end = ir_loader_sym_data_end; loader.loader.sym_data_end = ir_loader_sym_data_end;
loader.loader.func_init = ir_loader_func_init; loader.loader.func_init = ir_loader_func_init;