From 0103cedad7b18d2f8ac2337fd4221e874eb2e1ca Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 2 Feb 2020 23:36:15 +0000 Subject: [PATCH] Port code for lb_build_call_expr --- examples/llvm-demo/demo.odin | 56 ++--- src/llvm_backend.cpp | 429 +++++++++++++++++++++++++++++++++-- 2 files changed, 435 insertions(+), 50 deletions(-) diff --git a/examples/llvm-demo/demo.odin b/examples/llvm-demo/demo.odin index 3b8953134..58bb10682 100644 --- a/examples/llvm-demo/demo.odin +++ b/examples/llvm-demo/demo.odin @@ -1,45 +1,39 @@ package demo -import "core:os" - -// Foo :: struct { -// x, y: int, -// }; -// foo :: proc(x: int) -> (f: Foo) { -// return; -// } +BarBar :: struct { + x, y: int, +}; +foo :: proc(x: int) -> (b: BarBar) { + return; +} main :: proc() { Foo :: enum {A=1, B, C, D}; Foo_Set :: bit_set[Foo]; - x := Foo_Set{.A, .C}; + foo_set := Foo_Set{.A, .C}; - y := [4]int{3 = 1, 0 .. 1 = 3, 2 = 9}; - z := []int{1, 2, 3, 4}; + array := [4]int{3 = 1, 0 .. 1 = 3, 2 = 9}; + slice := []int{1, 2, 3, 4}; - // @thread_local a: int; + @thread_local a: int; - // x := i32(1); - // y := i32(2); - // z := x + y; - // w := z - 2; + x := i32(1); + y := i32(2); + z := x + y; + w := z - 2; - // foo(123); + f := foo; + c := 1 + 2i; + q := 1 + 2i + 3j + 4k; - // c := 1 + 2i; - // q := 1 + 2i + 3j + 4k; + s := "Hellope"; - // s := "Hellope"; - - // f := Foo{1, 2}; - // pc: proc "contextless" (x: i32) -> Foo; - // po: proc "odin" (x: i32) -> Foo; - // e: enum{A, B, C}; - // u: union{i32, bool}; - // u1: union{i32}; - // um: union #maybe {^int}; - - // os.write_string(os.stdout, "Hellope\n"); - return; + bb := BarBar{1, 2}; + pc: proc "contextless" (x: i32) -> BarBar; + po: proc "odin" (x: i32) -> BarBar; + e: enum{A, B, C}; + u: union{i32, bool}; + u1: union{i32}; + um: union #maybe {^int}; } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index c818051d0..a3ac6dcea 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -27,6 +27,11 @@ void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue const &value) { } +void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { + GB_ASSERT(value.value != nullptr); + LLVMValueRef v = LLVMBuildStore(p->builder, value.value, ptr.value); +} + lbValue lb_emit_load(lbProcedure *p, lbValue value) { GB_ASSERT(value.value != nullptr); Type *t = type_deref(value.type); @@ -99,14 +104,25 @@ String lb_mangle_name(lbModule *m, Entity *e) { return make_string(new_name, new_name_len-1); } -String lb_get_entity_name(lbModule *m, Entity *e, String name) { +String lb_get_entity_name(lbModule *m, Entity *e, String default_name) { if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) { return e->TypeName.ir_mangled_name; } + String name = {}; bool no_name_mangle = false; + if (e->kind == Entity_Variable) { + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export; + } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { + no_name_mangle = true; + } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { + no_name_mangle = true; + } + if (!no_name_mangle) { name = lb_mangle_name(m, e); } @@ -116,8 +132,10 @@ String lb_get_entity_name(lbModule *m, Entity *e, String name) { if (e != nullptr && e->kind == Entity_TypeName) { e->TypeName.ir_mangled_name = name; - + } else if (e != nullptr && e->kind == Entity_Procedure) { + e->Procedure.link_name = name; } + return name; } @@ -519,6 +537,8 @@ LLVMTypeRef lb_type_internal(Type *type) { } LLVMTypeRef lb_type(Type *type) { + type = default_type(type); + if (type->llvm_type) { return type->llvm_type; } @@ -726,11 +746,20 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr) { val.value = ptr; val.type = alloc_type_pointer(type); - lb_add_entity(p->module, e, val); + if (e != nullptr) { + lb_add_entity(p->module, e, val); + } return lb_addr(val); } +lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init) { + lbAddr addr = lb_add_local(p, type, nullptr); + lb_addr_store(p, addr, lb_const_nil(type)); + return addr; +} + + bool lb_init_generator(lbGenerator *gen, Checker *c) { if (global_error_collector.count != 0) { @@ -994,7 +1023,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { // res = lb_emit_load(p, *found); } else { res = lb_build_expr(p, rs->results[0]); - // res = ir_emit_conv(p, v, e->type); + res = lb_emit_conv(p, res, e->type); } } else { @@ -1041,6 +1070,13 @@ lbValue lb_const_nil(Type *type) { return lbValue{v, type}; } +lbValue lb_const_int(Type *type, u64 value) { + lbValue res = {}; + res.value = LLVMConstInt(lb_type(type), value, !is_type_unsigned(type)); + res.type = type; + return res; +} + LLVMValueRef llvm_const_f32(f32 f, Type *type=t_f32) { u32 u = bit_cast(f); LLVMValueRef i = LLVMConstInt(LLVMInt32Type(), u, false); @@ -1048,6 +1084,8 @@ LLVMValueRef llvm_const_f32(f32 f, Type *type=t_f32) { } + + lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) { HashKey key = hash_string(str); lbValue *found = map_get(&m->const_strings, key); @@ -1662,6 +1700,31 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value) { return lb_const_nil(original_type); } +u64 lb_generate_source_code_location_hash(TokenPos const &pos) { + u64 h = 0xcbf29ce484222325; + for (isize i = 0; i < pos.file.len; i++) { + h = (h ^ u64(pos.file[i])) * 0x100000001b3; + } + h = h ^ (u64(pos.line) * 0x100000001b3); + h = h ^ (u64(pos.column) * 0x100000001b3); + return h; +} + +lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, TokenPos const &pos) { + LLVMValueRef fields[5] = {}; + fields[0]/*file*/ = lb_find_or_add_entity_string(p->module, pos.file).value; + fields[1]/*line*/ = lb_const_int(t_int, pos.line).value; + fields[2]/*column*/ = lb_const_int(t_int, pos.column).value; + fields[3]/*procedure*/ = lb_find_or_add_entity_string(p->module, procedure).value; + fields[4]/*hash*/ = lb_const_int(t_u64, lb_generate_source_code_location_hash(pos)).value; + + lbValue res = {}; + res.value = LLVMConstNamedStruct(lb_type(t_source_code_location), fields, 5); + res.type = t_source_code_location; + return res; +} + + lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) { lbValue res = {}; res.type = type; @@ -1784,6 +1847,339 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { return {}; } +lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { + // TODO(bill): lb_emit_conv + return value; +} + +lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false) { + return {}; +} + +lbValue lb_emit_ev(lbProcedure *p, lbValue value, i32 index) { + return {}; +} + +lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, i32 index){ + return {}; +} + +void lb_fill_slice(lbProcedure *p, lbAddr slice, lbValue base_elem, lbValue len) { + +} + + +lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { + TypeAndValue tv = type_and_value_of_expr(expr); + + ast_node(ce, CallExpr, expr); + + TypeAndValue proc_tv = type_and_value_of_expr(ce->proc); + AddressingMode proc_mode = proc_tv.mode; + if (proc_mode == Addressing_Type) { + GB_ASSERT(ce->args.count == 1); + lbValue x = lb_build_expr(p, ce->args[0]); + lbValue y = lb_emit_conv(p, x, tv.type); + return y; + } + + Ast *pexpr = unparen_expr(ce->proc); + if (proc_mode == Addressing_Builtin) { + Entity *e = entity_of_node(pexpr); + BuiltinProcId id = BuiltinProc_Invalid; + if (e != nullptr) { + id = cast(BuiltinProcId)e->Builtin.id; + } else { + id = BuiltinProc_DIRECTIVE; + } + GB_PANIC("lb_build_builtin_proc"); + // return lb_build_builtin_proc(p, expr, tv, id); + } + + // NOTE(bill): Regular call + lbValue value = {}; + Ast *proc_expr = unparen_expr(ce->proc); + if (proc_expr->tav.mode == Addressing_Constant) { + ExactValue v = proc_expr->tav.value; + switch (v.kind) { + case ExactValue_Integer: + { + u64 u = big_int_to_u64(&v.value_integer); + lbValue x = {}; + x.value = LLVMConstInt(lb_type(t_uintptr), u, false); + x.type = t_uintptr; + x = lb_emit_conv(p, x, t_rawptr); + value = lb_emit_conv(p, x, proc_expr->tav.type); + break; + } + case ExactValue_Pointer: + { + u64 u = cast(u64)v.value_pointer; + lbValue x = {}; + x.value = LLVMConstInt(lb_type(t_uintptr), u, false); + x.type = t_uintptr; + x = lb_emit_conv(p, x, t_rawptr); + value = lb_emit_conv(p, x, proc_expr->tav.type); + break; + } + } + } + + if (value.value == nullptr) { + value = lb_build_expr(p, proc_expr); + } + + GB_ASSERT(value.value != nullptr); + Type *proc_type_ = base_type(value.type); + GB_ASSERT(proc_type_->kind == Type_Proc); + TypeProc *pt = &proc_type_->Proc; + set_procedure_abi_types(heap_allocator(), proc_type_); + + if (is_call_expr_field_value(ce)) { + auto args = array_make(heap_allocator(), pt->param_count); + + for_array(arg_index, ce->args) { + Ast *arg = ce->args[arg_index]; + ast_node(fv, FieldValue, arg); + GB_ASSERT(fv->field->kind == Ast_Ident); + String name = fv->field->Ident.token.string; + isize index = lookup_procedure_parameter(pt, name); + GB_ASSERT(index >= 0); + TypeAndValue tav = type_and_value_of_expr(fv->value); + if (tav.mode == Addressing_Type) { + args[index] = lb_const_nil(tav.type); + } else { + args[index] = lb_build_expr(p, fv->value); + } + } + TypeTuple *params = &pt->params->Tuple; + for (isize i = 0; i < args.count; i++) { + Entity *e = params->variables[i]; + if (e->kind == Entity_TypeName) { + args[i] = lb_const_nil(e->type); + } else if (e->kind == Entity_Constant) { + continue; + } else { + GB_ASSERT(e->kind == Entity_Variable); + if (args[i].value == nullptr) { + switch (e->Variable.param_value.kind) { + case ParameterValue_Constant: + args[i] = lb_const_value(p->module, e->type, e->Variable.param_value.value); + break; + case ParameterValue_Nil: + args[i] = lb_const_nil(e->type); + break; + case ParameterValue_Location: + args[i] = lb_emit_source_code_location(p, p->entity->token.string, ast_token(expr).pos); + break; + case ParameterValue_Value: + args[i] = lb_build_expr(p, e->Variable.param_value.ast_value); + break; + } + } else { + args[i] = lb_emit_conv(p, args[i], e->type); + } + } + } + + return lb_emit_call(p, value, args, ce->inlining, p->return_ptr_hint_ast == expr); + } + + isize arg_index = 0; + + isize arg_count = 0; + for_array(i, ce->args) { + Ast *arg = ce->args[i]; + TypeAndValue tav = type_and_value_of_expr(arg); + GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(arg), expr_to_string(expr)); + GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg)); + Type *at = tav.type; + if (at->kind == Type_Tuple) { + arg_count += at->Tuple.variables.count; + } else { + arg_count++; + } + } + + isize param_count = 0; + if (pt->params) { + GB_ASSERT(pt->params->kind == Type_Tuple); + param_count = pt->params->Tuple.variables.count; + } + + auto args = array_make(heap_allocator(), cast(isize)gb_max(param_count, arg_count)); + isize variadic_index = pt->variadic_index; + bool variadic = pt->variadic && variadic_index >= 0; + bool vari_expand = ce->ellipsis.pos.line != 0; + bool is_c_vararg = pt->c_vararg; + + String proc_name = {}; + if (p->entity != nullptr) { + proc_name = p->entity->token.string; + } + TokenPos pos = ast_token(ce->proc).pos; + + TypeTuple *param_tuple = nullptr; + if (pt->params) { + GB_ASSERT(pt->params->kind == Type_Tuple); + param_tuple = &pt->params->Tuple; + } + + for_array(i, ce->args) { + Ast *arg = ce->args[i]; + TypeAndValue arg_tv = type_and_value_of_expr(arg); + if (arg_tv.mode == Addressing_Type) { + args[arg_index++] = lb_const_nil(arg_tv.type); + } else { + lbValue a = lb_build_expr(p, arg); + Type *at = a.type; + if (at->kind == Type_Tuple) { + for_array(i, at->Tuple.variables) { + Entity *e = at->Tuple.variables[i]; + lbValue v = lb_emit_ev(p, a, cast(i32)i); + args[arg_index++] = v; + } + } else { + args[arg_index++] = a; + } + } + } + + + if (param_count > 0) { + GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count); + GB_ASSERT(param_count < 1000000); + + if (arg_count < param_count) { + isize end = cast(isize)param_count; + if (variadic) { + end = variadic_index; + } + while (arg_index < end) { + Entity *e = param_tuple->variables[arg_index]; + GB_ASSERT(e->kind == Entity_Variable); + + switch (e->Variable.param_value.kind) { + case ParameterValue_Constant: + args[arg_index++] = lb_const_value(p->module, e->type, e->Variable.param_value.value); + break; + case ParameterValue_Nil: + args[arg_index++] = lb_const_nil(e->type); + break; + case ParameterValue_Location: + args[arg_index++] = lb_emit_source_code_location(p, proc_name, pos); + break; + case ParameterValue_Value: + args[arg_index++] = lb_build_expr(p, e->Variable.param_value.ast_value); + break; + } + } + } + + if (is_c_vararg) { + GB_ASSERT(variadic); + GB_ASSERT(!vari_expand); + isize i = 0; + for (; i < variadic_index; i++) { + Entity *e = param_tuple->variables[i]; + if (e->kind == Entity_Variable) { + args[i] = lb_emit_conv(p, args[i], e->type); + } + } + Type *variadic_type = param_tuple->variables[i]->type; + GB_ASSERT(is_type_slice(variadic_type)); + variadic_type = base_type(variadic_type)->Slice.elem; + if (!is_type_any(variadic_type)) { + for (; i < arg_count; i++) { + args[i] = lb_emit_conv(p, args[i], variadic_type); + } + } else { + for (; i < arg_count; i++) { + args[i] = lb_emit_conv(p, args[i], default_type(args[i].type)); + } + } + } else if (variadic) { + isize i = 0; + for (; i < variadic_index; i++) { + Entity *e = param_tuple->variables[i]; + if (e->kind == Entity_Variable) { + args[i] = lb_emit_conv(p, args[i], e->type); + } + } + if (!vari_expand) { + Type *variadic_type = param_tuple->variables[i]->type; + GB_ASSERT(is_type_slice(variadic_type)); + variadic_type = base_type(variadic_type)->Slice.elem; + for (; i < arg_count; i++) { + args[i] = lb_emit_conv(p, args[i], variadic_type); + } + } + } else { + for (isize i = 0; i < param_count; i++) { + Entity *e = param_tuple->variables[i]; + if (e->kind == Entity_Variable) { + GB_ASSERT(args[i].value != nullptr); + args[i] = lb_emit_conv(p, args[i], e->type); + } + } + } + + if (variadic && !vari_expand && !is_c_vararg) { + // variadic call argument generation + gbAllocator allocator = heap_allocator(); + Type *slice_type = param_tuple->variables[variadic_index]->type; + Type *elem_type = base_type(slice_type)->Slice.elem; + lbAddr slice = lb_add_local_generated(p, slice_type, true); + isize slice_len = arg_count+1 - (variadic_index+1); + + if (slice_len > 0) { + lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); + + for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) { + lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)j); + lb_emit_store(p, addr, args[i]); + } + + lbValue base_elem = lb_emit_array_epi(p, base_array.addr, 0); + lbValue len = lb_const_int(t_int, slice_len); + lb_fill_slice(p, slice, base_elem, len); + } + + arg_count = param_count; + args[variadic_index] = lb_addr_load(p, slice); + } + } + + if (variadic && variadic_index+1 < param_count) { + for (isize i = variadic_index+1; i < param_count; i++) { + Entity *e = param_tuple->variables[i]; + switch (e->Variable.param_value.kind) { + case ParameterValue_Constant: + args[i] = lb_const_value(p->module, e->type, e->Variable.param_value.value); + break; + case ParameterValue_Nil: + args[i] = lb_const_nil(e->type); + break; + case ParameterValue_Location: + args[i] = lb_emit_source_code_location(p, proc_name, pos); + break; + case ParameterValue_Value: + args[i] = lb_build_expr(p, e->Variable.param_value.ast_value); + break; + } + } + } + + isize final_count = param_count; + if (is_c_vararg) { + final_count = arg_count; + } + + auto call_args = array_slice(args, 0, final_count); + return lb_emit_call(p, value, call_args, ce->inlining, p->return_ptr_hint_ast == expr); +} + + lbValue lb_build_expr(lbProcedure *p, Ast *expr) { expr = unparen_expr(expr); @@ -1809,7 +2205,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { case_end; case_ast_node(i, Implicit, expr); - // return ir_addr_load(proc, ir_build_addr(proc, expr)); + // return ir_addr_load(p, ir_build_addr(p, expr)); GB_PANIC("TODO(bill): Implicit"); case_end; @@ -1822,7 +2218,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { GB_ASSERT_MSG(e != nullptr, "%s", expr_to_string(expr)); if (e->kind == Entity_Builtin) { Token token = ast_token(expr); - GB_PANIC("TODO(bill): ir_build_expr Entity_Builtin '%.*s'\n" + GB_PANIC("TODO(bill): lb_build_expr Entity_Builtin '%.*s'\n" "\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name), LIT(token.pos.file), token.pos.line, token.pos.column); return {}; @@ -1833,13 +2229,13 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { auto *found = map_get(&p->module->values, hash_entity(e)); if (found) { auto v = *found; - LLVMTypeKind kind = LLVMGetTypeKind(LLVMTypeOf(v.value)); - if (kind == LLVMFunctionTypeKind) { + // NOTE(bill): This is because pointers are already pointers in LLVM + if (is_type_proc(v.type)) { return v; } return lb_emit_load(p, v); // } else if (e != nullptr && e->kind == Entity_Variable) { - // return ir_addr_load(proc, ir_build_addr(proc, expr)); + // return ir_addr_load(p, ir_build_addr(p, expr)); } GB_PANIC("nullptr value for expression from identifier: %.*s : %s @ %p", LIT(i->token.string), type_to_string(e->type), expr); return {}; @@ -1848,6 +2244,11 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { case_ast_node(be, BinaryExpr, expr); return lb_build_binary_expr(p, expr); case_end; + + + case_ast_node(ce, CallExpr, expr); + return lb_build_call_expr(p, expr); + case_end; } return {}; @@ -1941,17 +2342,7 @@ void lb_generate_module(lbGenerator *gen) { defer (LLVMDisposeMessage(llvm_error)); - // LLVMPassManagerRef pass_manager = LLVMCreatePassManager(); - // defer (LLVMDisposePassManager(pass_manager)); - - // LLVMAddAggressiveInstCombinerPass(pass_manager); - // LLVMAddConstantMergePass(pass_manager); - // LLVMAddDeadArgEliminationPass(pass_manager); - - // LLVMRunPassManager(pass_manager, mod); - LLVMVerifyModule(mod, LLVMAbortProcessAction, &llvm_error); - llvm_error = nullptr; LLVMDumpModule(mod);