diff options
| author | gingerBill <bill@gingerbill.org> | 2021-08-07 12:01:48 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2021-08-07 12:01:48 +0100 |
| commit | 40822be59517b277ec9313b8adcd270c45ce8d3a (patch) | |
| tree | f76c6d82e6ba019c446cd3a94236b8c6d9961c15 /src/llvm_backend.cpp | |
| parent | f5e51a29b57159fda894b9006b9142b166305f15 (diff) | |
Reorganize llvm_backend.cpp into separate files for easier maintenance
Diffstat (limited to 'src/llvm_backend.cpp')
| -rw-r--r-- | src/llvm_backend.cpp | 14681 |
1 files changed, 8 insertions, 14673 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 16681cdde..1adf620e8 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -12,3750 +12,14 @@ #include "llvm_backend.hpp" #include "llvm_abi.cpp" #include "llvm_backend_opt.cpp" - -gb_global ThreadPool lb_thread_pool = {}; - -gb_global Entity *lb_global_type_info_data_entity = {}; -gb_global lbAddr lb_global_type_info_member_types = {}; -gb_global lbAddr lb_global_type_info_member_names = {}; -gb_global lbAddr lb_global_type_info_member_offsets = {}; -gb_global lbAddr lb_global_type_info_member_usings = {}; -gb_global lbAddr lb_global_type_info_member_tags = {}; - -gb_global isize lb_global_type_info_data_index = 0; -gb_global isize lb_global_type_info_member_types_index = 0; -gb_global isize lb_global_type_info_member_names_index = 0; -gb_global isize lb_global_type_info_member_offsets_index = 0; -gb_global isize lb_global_type_info_member_usings_index = 0; -gb_global isize lb_global_type_info_member_tags_index = 0; - - -lbValue lb_global_type_info_data_ptr(lbModule *m) { - lbValue v = lb_find_value_from_entity(m, lb_global_type_info_data_entity); - return v; -} - - -struct lbLoopData { - lbAddr idx_addr; - lbValue idx; - lbBlock *body; - lbBlock *done; - lbBlock *loop; -}; - -struct lbCompoundLitElemTempData { - Ast * expr; - lbValue value; - i32 elem_index; - lbValue gep; -}; - -lbLoopData lb_loop_start(lbProcedure *p, isize count, Type *index_type=t_i32); -void lb_loop_end(lbProcedure *p, lbLoopData const &data); - -LLVMValueRef llvm_zero(lbModule *m) { - return LLVMConstInt(lb_type(m, t_int), 0, false); -} -LLVMValueRef llvm_zero32(lbModule *m) { - return LLVMConstInt(lb_type(m, t_i32), 0, false); -} -LLVMValueRef llvm_one(lbModule *m) { - return LLVMConstInt(lb_type(m, t_i32), 1, false); -} - -lbValue lb_zero(lbModule *m, Type *t) { - lbValue v = {}; - v.value = LLVMConstInt(lb_type(m, t), 0, false); - v.type = t; - return v; -} - -LLVMValueRef llvm_cstring(lbModule *m, String const &str) { - lbValue v = lb_find_or_add_entity_string(m, str); - unsigned indices[1] = {0}; - return LLVMConstExtractValue(v.value, indices, gb_count_of(indices)); -} - -bool lb_is_instr_terminating(LLVMValueRef instr) { - if (instr != nullptr) { - LLVMOpcode op = LLVMGetInstructionOpcode(instr); - switch (op) { - case LLVMRet: - case LLVMBr: - case LLVMSwitch: - case LLVMIndirectBr: - case LLVMInvoke: - case LLVMUnreachable: - case LLVMCallBr: - return true; - } - } - return false; -} - - - -lbModule *lb_pkg_module(lbGenerator *gen, AstPackage *pkg) { - auto *found = map_get(&gen->modules, hash_pointer(pkg)); - if (found) { - return *found; - } - return &gen->default_module; -} - - -lbAddr lb_addr(lbValue addr) { - lbAddr v = {lbAddr_Default, addr}; - if (addr.type != nullptr && is_type_relative_pointer(type_deref(addr.type))) { - GB_ASSERT(is_type_pointer(addr.type)); - v.kind = lbAddr_RelativePointer; - } else if (addr.type != nullptr && is_type_relative_slice(type_deref(addr.type))) { - GB_ASSERT(is_type_pointer(addr.type)); - v.kind = lbAddr_RelativeSlice; - } - return v; -} - - -lbAddr lb_addr_map(lbValue addr, lbValue map_key, Type *map_type, Type *map_result) { - lbAddr v = {lbAddr_Map, addr}; - v.map.key = map_key; - v.map.type = map_type; - v.map.result = map_result; - return v; -} - - -lbAddr lb_addr_soa_variable(lbValue addr, lbValue index, Ast *index_expr) { - lbAddr v = {lbAddr_SoaVariable, addr}; - v.soa.index = index; - v.soa.index_expr = index_expr; - return v; -} - -lbAddr lb_addr_swizzle(lbValue addr, Type *array_type, u8 swizzle_count, u8 swizzle_indices[4]) { - GB_ASSERT(is_type_array(array_type)); - GB_ASSERT(1 < swizzle_count && swizzle_count <= 4); - lbAddr v = {lbAddr_Swizzle, addr}; - v.swizzle.type = array_type; - v.swizzle.count = swizzle_count; - gb_memmove(v.swizzle.indices, swizzle_indices, swizzle_count); - return v; -} - -Type *lb_addr_type(lbAddr const &addr) { - if (addr.addr.value == nullptr) { - return nullptr; - } - if (addr.kind == lbAddr_Map) { - Type *t = base_type(addr.map.type); - GB_ASSERT(is_type_map(t)); - return t->Map.value; - } - if (addr.kind == lbAddr_Swizzle) { - return addr.swizzle.type; - } - return type_deref(addr.addr.type); -} -LLVMTypeRef lb_addr_lb_type(lbAddr const &addr) { - return LLVMGetElementType(LLVMTypeOf(addr.addr.value)); -} - -lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { - if (addr.addr.value == nullptr) { - GB_PANIC("Illegal addr -> nullptr"); - return {}; - } - - switch (addr.kind) { - case lbAddr_Map: { - Type *map_type = base_type(addr.map.type); - lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key); - - auto args = array_make<lbValue>(permanent_allocator(), 2); - args[0] = h; - args[1] = key; - - lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); - - return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value)); - } - - case lbAddr_RelativePointer: { - Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativePointer); - - lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); - lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); - offset = lb_emit_load(p, offset); - - if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); - } - offset = lb_emit_conv(p, offset, t_uintptr); - lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr); - absolute_ptr = lb_emit_conv(p, absolute_ptr, rel_ptr->RelativePointer.pointer_type); - - lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer)); - - // NOTE(bill): nil check - lbValue nil_ptr = lb_const_nil(p->module, rel_ptr->RelativePointer.pointer_type); - lbValue final_ptr = lb_emit_select(p, cond, nil_ptr, absolute_ptr); - return final_ptr; - } - - case lbAddr_SoaVariable: - // TODO(bill): FIX THIS HACK - return lb_address_from_load(p, lb_addr_load(p, addr)); - - case lbAddr_Context: - GB_PANIC("lbAddr_Context should be handled elsewhere"); - break; - - case lbAddr_Swizzle: - // TOOD(bill): is this good enough logic? - break; - } - - return addr.addr; -} - - -lbValue lb_build_addr_ptr(lbProcedure *p, Ast *expr) { - lbAddr addr = lb_build_addr(p, expr); - return lb_addr_get_ptr(p, addr); -} - -void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index, lbValue len) { - if (build_context.no_bounds_check) { - return; - } - if ((p->state_flags & StateFlag_no_bounds_check) != 0) { - return; - } - - index = lb_emit_conv(p, index, t_int); - len = lb_emit_conv(p, len, t_int); - - lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id)); - lbValue line = lb_const_int(p->module, t_i32, token.pos.line); - lbValue column = lb_const_int(p->module, t_i32, token.pos.column); - - auto args = array_make<lbValue>(permanent_allocator(), 5); - args[0] = file; - args[1] = line; - args[2] = column; - args[3] = index; - args[4] = len; - - lb_emit_runtime_call(p, "bounds_check_error", args); -} - -void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValue high, lbValue len, bool lower_value_used) { - if (build_context.no_bounds_check) { - return; - } - if ((p->state_flags & StateFlag_no_bounds_check) != 0) { - return; - } - - lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id)); - lbValue line = lb_const_int(p->module, t_i32, token.pos.line); - lbValue column = lb_const_int(p->module, t_i32, token.pos.column); - high = lb_emit_conv(p, high, t_int); - - if (!lower_value_used) { - auto args = array_make<lbValue>(permanent_allocator(), 5); - args[0] = file; - args[1] = line; - args[2] = column; - args[3] = high; - args[4] = len; - - lb_emit_runtime_call(p, "slice_expr_error_hi", args); - } else { - // No need to convert unless used - low = lb_emit_conv(p, low, t_int); - - auto args = array_make<lbValue>(permanent_allocator(), 6); - args[0] = file; - args[1] = line; - args[2] = column; - args[3] = low; - args[4] = high; - args[5] = len; - - lb_emit_runtime_call(p, "slice_expr_error_lo_hi", args); - } -} - -bool lb_try_update_alignment(lbValue ptr, unsigned alignment) { - LLVMValueRef addr_ptr = ptr.value; - if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) { - if (LLVMGetAlignment(addr_ptr) < alignment) { - if (LLVMIsAAllocaInst(addr_ptr) || LLVMIsAGlobalValue(addr_ptr)) { - LLVMSetAlignment(addr_ptr, alignment); - } - } - return LLVMGetAlignment(addr_ptr) >= alignment; - } - return false; -} - -bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) { - Type *array_type = base_type(type_deref(ptr.type)); - GB_ASSERT(is_type_array_like(array_type)); - i64 count = get_array_type_count(array_type); - Type *elem_type = base_array_type(array_type); - - // TODO(bill): Determine what is the correct limit for doing vector arithmetic - if (type_size_of(array_type) <= build_context.max_align && - is_type_valid_vector_elem(elem_type)) { - // Try to treat it like a vector if possible - bool possible = false; - LLVMTypeRef vector_type = LLVMVectorType(lb_type(m, elem_type), cast(unsigned)count); - unsigned vector_alignment = cast(unsigned)lb_alignof(vector_type); - - LLVMValueRef addr_ptr = ptr.value; - if (LLVMIsAAllocaInst(addr_ptr) || LLVMIsAGlobalValue(addr_ptr)) { - unsigned alignment = LLVMGetAlignment(addr_ptr); - alignment = gb_max(alignment, vector_alignment); - possible = true; - LLVMSetAlignment(addr_ptr, alignment); - } else if (LLVMIsALoadInst(addr_ptr)) { - unsigned alignment = LLVMGetAlignment(addr_ptr); - possible = alignment >= vector_alignment; - } - - // NOTE: Due to alignment requirements, if the pointer is not correctly aligned - // then it cannot be treated as a vector - if (possible) { - if (vector_type_) *vector_type_ =vector_type; - return true; - } - } - return false; -} - -void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { - if (addr.addr.value == nullptr) { - return; - } - GB_ASSERT(value.type != nullptr); - if (is_type_untyped_undef(value.type)) { - Type *t = lb_addr_type(addr); - value.type = t; - value.value = LLVMGetUndef(lb_type(p->module, t)); - } else if (is_type_untyped_nil(value.type)) { - Type *t = lb_addr_type(addr); - value.type = t; - value.value = LLVMConstNull(lb_type(p->module, t)); - } - - if (addr.kind == lbAddr_RelativePointer && addr.relative.deref) { - addr = lb_addr(lb_address_from_load(p, lb_addr_load(p, addr))); - } - - if (addr.kind == lbAddr_RelativePointer) { - Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativePointer); - - value = lb_emit_conv(p, value, rel_ptr->RelativePointer.pointer_type); - - GB_ASSERT(is_type_pointer(addr.addr.type)); - lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); - lbValue val_ptr = lb_emit_conv(p, value, t_uintptr); - lbValue offset = {}; - offset.value = LLVMBuildSub(p->builder, val_ptr.value, ptr.value, ""); - offset.type = t_uintptr; - - if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); - } - offset = lb_emit_conv(p, offset, rel_ptr->RelativePointer.base_integer); - - lbValue offset_ptr = lb_emit_conv(p, addr.addr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); - offset = lb_emit_select(p, - lb_emit_comp(p, Token_CmpEq, val_ptr, lb_const_nil(p->module, t_uintptr)), - lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer), - offset - ); - LLVMBuildStore(p->builder, offset.value, offset_ptr.value); - return; - - } else if (addr.kind == lbAddr_RelativeSlice) { - Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativeSlice); - - value = lb_emit_conv(p, value, rel_ptr->RelativeSlice.slice_type); - - GB_ASSERT(is_type_pointer(addr.addr.type)); - lbValue ptr = lb_emit_conv(p, lb_emit_struct_ep(p, addr.addr, 0), t_uintptr); - lbValue val_ptr = lb_emit_conv(p, lb_slice_elem(p, value), t_uintptr); - lbValue offset = {}; - offset.value = LLVMBuildSub(p->builder, val_ptr.value, ptr.value, ""); - offset.type = t_uintptr; - - if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); - } - offset = lb_emit_conv(p, offset, rel_ptr->RelativePointer.base_integer); - - - lbValue offset_ptr = lb_emit_conv(p, addr.addr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); - offset = lb_emit_select(p, - lb_emit_comp(p, Token_CmpEq, val_ptr, lb_const_nil(p->module, t_uintptr)), - lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer), - offset - ); - LLVMBuildStore(p->builder, offset.value, offset_ptr.value); - - lbValue len = lb_slice_len(p, value); - len = lb_emit_conv(p, len, rel_ptr->RelativePointer.base_integer); - - lbValue len_ptr = lb_emit_struct_ep(p, addr.addr, 1); - LLVMBuildStore(p->builder, len.value, len_ptr.value); - - return; - } else if (addr.kind == lbAddr_Map) { - lb_insert_dynamic_map_key_and_value(p, addr, addr.map.type, addr.map.key, value, p->curr_stmt); - return; - } else if (addr.kind == lbAddr_Context) { - lbAddr old_addr = lb_find_or_generate_context_ptr(p); - - - // IMPORTANT NOTE(bill, 2021-04-22): reuse unused 'context' variables to minimize stack usage - // This has to be done manually since the optimizer cannot determine when this is possible - bool create_new = true; - for_array(i, p->context_stack) { - lbContextData *ctx_data = &p->context_stack[i]; - if (ctx_data->ctx.addr.value == old_addr.addr.value) { - if (ctx_data->uses > 0) { - create_new = true; - } else if (p->scope_index > ctx_data->scope_index) { - create_new = true; - } else { - // gb_printf_err("%.*s (curr:%td) (ctx:%td) (uses:%td)\n", LIT(p->name), p->scope_index, ctx_data->scope_index, ctx_data->uses); - create_new = false; - } - break; - } - } - - lbValue next = {}; - if (create_new) { - lbValue old = lb_addr_load(p, old_addr); - lbAddr next_addr = lb_add_local_generated(p, t_context, true); - lb_addr_store(p, next_addr, old); - lb_push_context_onto_stack(p, next_addr); - next = next_addr.addr; - } else { - next = old_addr.addr; - } - - if (addr.ctx.sel.index.count > 0) { - lbValue lhs = lb_emit_deep_field_gep(p, next, addr.ctx.sel); - lbValue rhs = lb_emit_conv(p, value, type_deref(lhs.type)); - lb_emit_store(p, lhs, rhs); - } else { - lbValue lhs = next; - lbValue rhs = lb_emit_conv(p, value, lb_addr_type(addr)); - lb_emit_store(p, lhs, rhs); - } - - return; - } else if (addr.kind == lbAddr_SoaVariable) { - Type *t = type_deref(addr.addr.type); - t = base_type(t); - GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None); - Type *elem_type = t->Struct.soa_elem; - value = lb_emit_conv(p, value, elem_type); - elem_type = base_type(elem_type); - - lbValue index = addr.soa.index; - if (!lb_is_const(index) || t->Struct.soa_kind != StructSoa_Fixed) { - Type *t = base_type(type_deref(addr.addr.type)); - GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None); - lbValue len = lb_soa_struct_len(p, addr.addr); - if (addr.soa.index_expr != nullptr) { - lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), index, len); - } - } - - isize field_count = 0; - - switch (elem_type->kind) { - case Type_Struct: - field_count = elem_type->Struct.fields.count; - break; - case Type_Array: - field_count = cast(isize)elem_type->Array.count; - break; - } - for (isize i = 0; i < field_count; i++) { - lbValue dst = lb_emit_struct_ep(p, addr.addr, cast(i32)i); - lbValue src = lb_emit_struct_ev(p, value, cast(i32)i); - if (t->Struct.soa_kind == StructSoa_Fixed) { - dst = lb_emit_array_ep(p, dst, index); - lb_emit_store(p, dst, src); - } else { - lbValue field = lb_emit_load(p, dst); - dst = lb_emit_ptr_offset(p, field, index); - lb_emit_store(p, dst, src); - } - } - return; - } else if (addr.kind == lbAddr_Swizzle) { - GB_ASSERT(addr.swizzle.count <= 4); - - GB_ASSERT(value.value != nullptr); - value = lb_emit_conv(p, value, lb_addr_type(addr)); - - lbValue dst = lb_addr_get_ptr(p, addr); - lbValue src = lb_address_from_load_or_generate_local(p, value); - { - lbValue src_ptrs[4] = {}; - lbValue src_loads[4] = {}; - lbValue dst_ptrs[4] = {}; - - for (u8 i = 0; i < addr.swizzle.count; i++) { - src_ptrs[i] = lb_emit_array_epi(p, src, i); - } - for (u8 i = 0; i < addr.swizzle.count; i++) { - dst_ptrs[i] = lb_emit_array_epi(p, dst, addr.swizzle.indices[i]); - } - for (u8 i = 0; i < addr.swizzle.count; i++) { - src_loads[i] = lb_emit_load(p, src_ptrs[i]); - } - - for (u8 i = 0; i < addr.swizzle.count; i++) { - lb_emit_store(p, dst_ptrs[i], src_loads[i]); - } - } - return; - } - - GB_ASSERT(value.value != nullptr); - value = lb_emit_conv(p, value, lb_addr_type(addr)); - - // if (lb_is_const_or_global(value)) { - // // NOTE(bill): Just bypass the actual storage and set the initializer - // if (LLVMGetValueKind(addr.addr.value) == LLVMGlobalVariableValueKind) { - // LLVMValueRef dst = addr.addr.value; - // LLVMValueRef src = value.value; - // LLVMSetInitializer(dst, src); - // return; - // } - // } - - lb_emit_store(p, addr.addr, value); -} - -void lb_const_store(lbValue ptr, lbValue value) { - GB_ASSERT(lb_is_const(ptr)); - GB_ASSERT(lb_is_const(value)); - GB_ASSERT(is_type_pointer(ptr.type)); - LLVMSetInitializer(ptr.value, value.value); -} - - -bool lb_is_type_proc_recursive(Type *t) { - for (;;) { - if (t == nullptr) { - return false; - } - switch (t->kind) { - case Type_Named: - t = t->Named.base; - break; - case Type_Pointer: - t = t->Pointer.elem; - break; - case Type_Array: - t = t->Array.elem; - break; - case Type_EnumeratedArray: - t = t->EnumeratedArray.elem; - break; - case Type_Slice: - t = t->Slice.elem; - break; - case Type_DynamicArray: - t = t->DynamicArray.elem; - break; - case Type_Proc: - return true; - default: - return false; - } - } -} - -void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { - GB_ASSERT(value.value != nullptr); - Type *a = type_deref(ptr.type); - if (is_type_boolean(a)) { - // NOTE(bill): There are multiple sized booleans, thus force a conversion (if necessarily) - value = lb_emit_conv(p, value, a); - } - Type *ca = core_type(a); - if (ca->kind == Type_Basic) { - GB_ASSERT_MSG(are_types_identical(ca, core_type(value.type)), "%s != %s", type_to_string(a), type_to_string(value.type)); - } - - if (lb_is_type_proc_recursive(a)) { - // NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be - // stored as regular pointer with no procedure information - - LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value)); - LLVMValueRef v = LLVMBuildPointerCast(p->builder, value.value, src_t, ""); - LLVMBuildStore(p->builder, v, ptr.value); - } else { - Type *ca = core_type(a); - if (ca->kind == Type_Basic || ca->kind == Type_Proc) { - GB_ASSERT_MSG(are_types_identical(ca, core_type(value.type)), "%s != %s", type_to_string(a), type_to_string(value.type)); - } else { - GB_ASSERT_MSG(are_types_identical(a, value.type), "%s != %s", type_to_string(a), type_to_string(value.type)); - } - - LLVMBuildStore(p->builder, value.value, ptr.value); - } -} - -LLVMTypeRef llvm_addr_type(lbValue addr_val) { - return LLVMGetElementType(LLVMTypeOf(addr_val.value)); -} - -lbValue lb_emit_load(lbProcedure *p, lbValue value) { - lbModule *m = p->module; - GB_ASSERT(value.value != nullptr); - GB_ASSERT(is_type_pointer(value.type)); - Type *t = type_deref(value.type); - LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); - return lbValue{v, t}; -} - -lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { - GB_ASSERT(addr.addr.value != nullptr); - - - if (addr.kind == lbAddr_RelativePointer) { - Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativePointer); - - lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); - lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); - offset = lb_emit_load(p, offset); - - - if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); - } - offset = lb_emit_conv(p, offset, t_uintptr); - lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr); - absolute_ptr = lb_emit_conv(p, absolute_ptr, rel_ptr->RelativePointer.pointer_type); - - lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer)); - - // NOTE(bill): nil check - lbValue nil_ptr = lb_const_nil(p->module, rel_ptr->RelativePointer.pointer_type); - lbValue final_ptr = {}; - final_ptr.type = absolute_ptr.type; - final_ptr.value = LLVMBuildSelect(p->builder, cond.value, nil_ptr.value, absolute_ptr.value, ""); - - return lb_emit_load(p, final_ptr); - - } else if (addr.kind == lbAddr_RelativeSlice) { - Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativeSlice); - - lbValue offset_ptr = lb_emit_struct_ep(p, addr.addr, 0); - lbValue ptr = lb_emit_conv(p, offset_ptr, t_uintptr); - lbValue offset = lb_emit_load(p, offset_ptr); - - - if (!is_type_unsigned(rel_ptr->RelativeSlice.base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); - } - offset = lb_emit_conv(p, offset, t_uintptr); - lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr); - - Type *slice_type = base_type(rel_ptr->RelativeSlice.slice_type); - GB_ASSERT(rel_ptr->RelativeSlice.slice_type->kind == Type_Slice); - Type *slice_elem = slice_type->Slice.elem; - Type *slice_elem_ptr = alloc_type_pointer(slice_elem); - - absolute_ptr = lb_emit_conv(p, absolute_ptr, slice_elem_ptr); - - lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, rel_ptr->RelativeSlice.base_integer)); - - // NOTE(bill): nil check - lbValue nil_ptr = lb_const_nil(p->module, slice_elem_ptr); - lbValue data = {}; - data.type = absolute_ptr.type; - data.value = LLVMBuildSelect(p->builder, cond.value, nil_ptr.value, absolute_ptr.value, ""); - - lbValue len = lb_emit_load(p, lb_emit_struct_ep(p, addr.addr, 1)); - len = lb_emit_conv(p, len, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, data, len); - return lb_addr_load(p, slice); - - - } else if (addr.kind == lbAddr_Map) { - Type *map_type = base_type(addr.map.type); - lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true); - lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key); - - auto args = array_make<lbValue>(permanent_allocator(), 2); - args[0] = h; - args[1] = key; - - lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); - lbValue ok = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); - lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), ok); - - lbBlock *then = lb_create_block(p, "map.get.then"); - lbBlock *done = lb_create_block(p, "map.get.done"); - lb_emit_if(p, ok, then, done); - lb_start_block(p, then); - { - // TODO(bill): mem copy it instead? - lbValue gep0 = lb_emit_struct_ep(p, v.addr, 0); - lbValue value = lb_emit_conv(p, ptr, gep0.type); - lb_emit_store(p, gep0, lb_emit_load(p, value)); - } - lb_emit_jump(p, done); - lb_start_block(p, done); - - - if (is_type_tuple(addr.map.result)) { - return lb_addr_load(p, v); - } else { - lbValue single = lb_emit_struct_ep(p, v.addr, 0); - return lb_emit_load(p, single); - } - } else if (addr.kind == lbAddr_Context) { - lbValue a = addr.addr; - for_array(i, p->context_stack) { - lbContextData *ctx_data = &p->context_stack[i]; - if (ctx_data->ctx.addr.value == a.value) { - ctx_data->uses += 1; - break; - } - } - a.value = LLVMBuildPointerCast(p->builder, a.value, lb_type(p->module, t_context_ptr), ""); - - if (addr.ctx.sel.index.count > 0) { - lbValue b = lb_emit_deep_field_gep(p, a, addr.ctx.sel); - return lb_emit_load(p, b); - } else { - return lb_emit_load(p, a); - } - } else if (addr.kind == lbAddr_SoaVariable) { - Type *t = type_deref(addr.addr.type); - t = base_type(t); - GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None); - Type *elem = t->Struct.soa_elem; - - lbValue len = {}; - if (t->Struct.soa_kind == StructSoa_Fixed) { - len = lb_const_int(p->module, t_int, t->Struct.soa_count); - } else { - lbValue v = lb_emit_load(p, addr.addr); - len = lb_soa_struct_len(p, v); - } - - lbAddr res = lb_add_local_generated(p, elem, true); - - if (addr.soa.index_expr != nullptr && (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) { - lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); - } - - if (t->Struct.soa_kind == StructSoa_Fixed) { - for_array(i, t->Struct.fields) { - Entity *field = t->Struct.fields[i]; - Type *base_type = field->type; - GB_ASSERT(base_type->kind == Type_Array); - - lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i); - lbValue src_ptr = lb_emit_struct_ep(p, addr.addr, cast(i32)i); - src_ptr = lb_emit_array_ep(p, src_ptr, addr.soa.index); - lbValue src = lb_emit_load(p, src_ptr); - lb_emit_store(p, dst, src); - } - } else { - isize field_count = t->Struct.fields.count; - if (t->Struct.soa_kind == StructSoa_Slice) { - field_count -= 1; - } else if (t->Struct.soa_kind == StructSoa_Dynamic) { - field_count -= 3; - } - for (isize i = 0; i < field_count; i++) { - Entity *field = t->Struct.fields[i]; - Type *base_type = field->type; - GB_ASSERT(base_type->kind == Type_Pointer); - Type *elem = base_type->Pointer.elem; - - lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i); - lbValue src_ptr = lb_emit_struct_ep(p, addr.addr, cast(i32)i); - lbValue src = lb_emit_load(p, src_ptr); - src = lb_emit_ptr_offset(p, src, addr.soa.index); - src = lb_emit_load(p, src); - lb_emit_store(p, dst, src); - } - } - - return lb_addr_load(p, res); - } else if (addr.kind == lbAddr_Swizzle) { - Type *array_type = base_type(addr.swizzle.type); - GB_ASSERT(array_type->kind == Type_Array); - - unsigned res_align = cast(unsigned)type_align_of(addr.swizzle.type); - - static u8 const ordered_indices[4] = {0, 1, 2, 3}; - if (gb_memcompare(ordered_indices, addr.swizzle.indices, addr.swizzle.count) == 0) { - if (lb_try_update_alignment(addr.addr, res_align)) { - Type *pt = alloc_type_pointer(addr.swizzle.type); - lbValue res = {}; - res.value = LLVMBuildPointerCast(p->builder, addr.addr.value, lb_type(p->module, pt), ""); - res.type = pt; - return lb_emit_load(p, res); - } - } - - Type *elem_type = base_type(array_type->Array.elem); - lbAddr res = lb_add_local_generated(p, addr.swizzle.type, false); - lbValue ptr = lb_addr_get_ptr(p, res); - GB_ASSERT(is_type_pointer(ptr.type)); - - LLVMTypeRef vector_type = nullptr; - if (lb_try_vector_cast(p->module, addr.addr, &vector_type)) { - LLVMSetAlignment(res.addr.value, cast(unsigned)lb_alignof(vector_type)); - - LLVMValueRef vp = LLVMBuildPointerCast(p->builder, addr.addr.value, LLVMPointerType(vector_type, 0), ""); - LLVMValueRef v = LLVMBuildLoad2(p->builder, vector_type, vp, ""); - LLVMValueRef scalars[4] = {}; - for (u8 i = 0; i < addr.swizzle.count; i++) { - scalars[i] = LLVMConstInt(lb_type(p->module, t_u32), addr.swizzle.indices[i], false); - } - LLVMValueRef mask = LLVMConstVector(scalars, addr.swizzle.count); - LLVMValueRef sv = LLVMBuildShuffleVector(p->builder, v, LLVMGetUndef(vector_type), mask, ""); - - LLVMValueRef dst = LLVMBuildPointerCast(p->builder, ptr.value, LLVMPointerType(LLVMTypeOf(sv), 0), ""); - LLVMBuildStore(p->builder, sv, dst); - } else { - for (u8 i = 0; i < addr.swizzle.count; i++) { - u8 index = addr.swizzle.indices[i]; - lbValue dst = lb_emit_array_epi(p, ptr, i); - lbValue src = lb_emit_array_epi(p, addr.addr, index); - lb_emit_store(p, dst, lb_emit_load(p, src)); - } - } - return lb_addr_load(p, res); - } - - if (is_type_proc(addr.addr.type)) { - return addr.addr; - } - return lb_emit_load(p, addr.addr); -} - -lbValue lb_const_union_tag(lbModule *m, Type *u, Type *v) { - return lb_const_value(m, union_tag_type(u), exact_value_i64(union_variant_index(u, v))); -} - -lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { - Type *t = u.type; - GB_ASSERT_MSG(is_type_pointer(t) && - is_type_union(type_deref(t)), "%s", type_to_string(t)); - Type *ut = type_deref(t); - - GB_ASSERT(!is_type_union_maybe_pointer_original_alignment(ut)); - GB_ASSERT(!is_type_union_maybe_pointer(ut)); - GB_ASSERT(type_size_of(ut) > 0); - - Type *tag_type = union_tag_type(ut); - - LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value)); - unsigned element_count = LLVMCountStructElementTypes(uvt); - GB_ASSERT_MSG(element_count == 3, "(%s) != (%s)", type_to_string(ut), LLVMPrintTypeToString(uvt)); - - lbValue tag_ptr = {}; - tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 2, ""); - tag_ptr.type = alloc_type_pointer(tag_type); - return tag_ptr; -} - -lbValue lb_emit_union_tag_value(lbProcedure *p, lbValue u) { - lbValue ptr = lb_address_from_load_or_generate_local(p, u); - lbValue tag_ptr = lb_emit_union_tag_ptr(p, ptr); - return lb_emit_load(p, tag_ptr); -} - - -void lb_emit_store_union_variant_tag(lbProcedure *p, lbValue parent, Type *variant_type) { - Type *t = type_deref(parent.type); - - if (is_type_union_maybe_pointer(t) || type_size_of(t) == 0) { - // No tag needed! - } else { - lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent); - lb_emit_store(p, tag_ptr, lb_const_union_tag(p->module, t, variant_type)); - } -} - -void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant, Type *variant_type) { - lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); - - lb_emit_store(p, underlying, variant); - lb_emit_store_union_variant_tag(p, parent, variant_type); -} - - -void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) { - unsigned field_count = LLVMCountStructElementTypes(src); - LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); - LLVMGetStructElementTypes(src, fields); - LLVMStructSetBody(dst, fields, field_count, LLVMIsPackedStruct(src)); -} - -LLVMTypeRef lb_alignment_prefix_type_hack(lbModule *m, i64 alignment) { - switch (alignment) { - case 1: - return LLVMArrayType(lb_type(m, t_u8), 0); - case 2: - return LLVMArrayType(lb_type(m, t_u16), 0); - case 4: - return LLVMArrayType(lb_type(m, t_u32), 0); - case 8: - return LLVMArrayType(lb_type(m, t_u64), 0); - case 16: - return LLVMArrayType(LLVMVectorType(lb_type(m, t_u32), 4), 0); - default: - GB_PANIC("Invalid alignment %d", cast(i32)alignment); - break; - } - return nullptr; -} - -bool lb_is_elem_const(Ast *elem, Type *elem_type) { - if (!elem_type_can_be_constant(elem_type)) { - return false; - } - if (elem->kind == Ast_FieldValue) { - elem = elem->FieldValue.value; - } - TypeAndValue tav = type_and_value_of_expr(elem); - GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(elem), type_to_string(tav.type)); - return tav.value.kind != ExactValue_Invalid; -} - -String lb_mangle_name(lbModule *m, Entity *e) { - String name = e->token.string; - - AstPackage *pkg = e->pkg; - GB_ASSERT_MSG(pkg != nullptr, "Missing package for '%.*s'", LIT(name)); - String pkgn = pkg->name; - GB_ASSERT(!rune_is_digit(pkgn[0])); - if (pkgn == "llvm") { - pkgn = str_lit("llvm$"); - } - - isize max_len = pkgn.len + 1 + name.len + 1; - bool require_suffix_id = is_type_polymorphic(e->type, true); - - if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0) { - require_suffix_id = true; - } else if (is_blank_ident(e->token)) { - require_suffix_id = true; - }if (e->flags & EntityFlag_NotExported) { - require_suffix_id = true; - } - - if (require_suffix_id) { - max_len += 21; - } - - char *new_name = gb_alloc_array(permanent_allocator(), char, max_len); - isize new_name_len = gb_snprintf( - new_name, max_len, - "%.*s.%.*s", LIT(pkgn), LIT(name) - ); - if (require_suffix_id) { - char *str = new_name + new_name_len-1; - isize len = max_len-new_name_len; - isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id); - new_name_len += extra-1; - } - - String mangled_name = make_string((u8 const *)new_name, new_name_len-1); - return mangled_name; -} - -String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p) { - // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration - // and as a result, the declaration does not have time to determine what it should be - - GB_ASSERT(e != nullptr && e->kind == Entity_TypeName); - if (e->TypeName.ir_mangled_name.len != 0) { - return e->TypeName.ir_mangled_name; - } - GB_ASSERT((e->scope->flags & ScopeFlag_File) == 0); - - if (p == nullptr) { - Entity *proc = nullptr; - if (e->parent_proc_decl != nullptr) { - proc = e->parent_proc_decl->entity; - } else { - Scope *scope = e->scope; - while (scope != nullptr && (scope->flags & ScopeFlag_Proc) == 0) { - scope = scope->parent; - } - GB_ASSERT(scope != nullptr); - GB_ASSERT(scope->flags & ScopeFlag_Proc); - proc = scope->procedure_entity; - } - GB_ASSERT(proc->kind == Entity_Procedure); - if (proc->code_gen_procedure != nullptr) { - p = proc->code_gen_procedure; - } - } - - // NOTE(bill): Generate a new name - // parent_proc.name-guid - String ts_name = e->token.string; - - if (p != nullptr) { - isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); - u32 guid = ++p->module->nested_type_name_guid; - name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%u", LIT(p->name), LIT(ts_name), guid); - - String name = make_string(cast(u8 *)name_text, name_len-1); - e->TypeName.ir_mangled_name = name; - return name; - } else { - // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now - isize name_len = 9 + 1 + ts_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); - static u32 guid = 0; - guid += 1; - name_len = gb_snprintf(name_text, name_len, "_internal.%.*s-%u", LIT(ts_name), guid); - - String name = make_string(cast(u8 *)name_text, name_len-1); - e->TypeName.ir_mangled_name = name; - return 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; - } - GB_ASSERT(e != nullptr); - - if (e->pkg == nullptr) { - return e->token.string; - } - - if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { - return lb_set_nested_type_name_ir_mangled_name(e, nullptr); - } - - 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; - if (e->Variable.link_name.len > 0) { - return e->Variable.link_name; - } - } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { - return e->Procedure.link_name; - } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { - no_name_mangle = true; - } - - if (!no_name_mangle) { - name = lb_mangle_name(m, e); - } - if (name.len == 0) { - name = e->token.string; - } - - if (e->kind == Entity_TypeName) { - e->TypeName.ir_mangled_name = name; - } else if (e->kind == Entity_Procedure) { - e->Procedure.link_name = name; - } - - return name; -} - -LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { - Type *original_type = type; - - LLVMContextRef ctx = m->ctx; - i64 size = type_size_of(type); // Check size - - GB_ASSERT(type != t_invalid); - - switch (type->kind) { - case Type_Basic: - switch (type->Basic.kind) { - case Basic_llvm_bool: return LLVMInt1TypeInContext(ctx); - case Basic_bool: return LLVMInt8TypeInContext(ctx); - case Basic_b8: return LLVMInt8TypeInContext(ctx); - case Basic_b16: return LLVMInt16TypeInContext(ctx); - case Basic_b32: return LLVMInt32TypeInContext(ctx); - case Basic_b64: return LLVMInt64TypeInContext(ctx); - - case Basic_i8: return LLVMInt8TypeInContext(ctx); - case Basic_u8: return LLVMInt8TypeInContext(ctx); - case Basic_i16: return LLVMInt16TypeInContext(ctx); - case Basic_u16: return LLVMInt16TypeInContext(ctx); - case Basic_i32: return LLVMInt32TypeInContext(ctx); - case Basic_u32: return LLVMInt32TypeInContext(ctx); - case Basic_i64: return LLVMInt64TypeInContext(ctx); - case Basic_u64: return LLVMInt64TypeInContext(ctx); - case Basic_i128: return LLVMInt128TypeInContext(ctx); - case Basic_u128: return LLVMInt128TypeInContext(ctx); - - case Basic_rune: return LLVMInt32TypeInContext(ctx); - - - case Basic_f16: return LLVMHalfTypeInContext(ctx); - case Basic_f32: return LLVMFloatTypeInContext(ctx); - case Basic_f64: return LLVMDoubleTypeInContext(ctx); - - case Basic_f16le: return LLVMHalfTypeInContext(ctx); - case Basic_f32le: return LLVMFloatTypeInContext(ctx); - case Basic_f64le: return LLVMDoubleTypeInContext(ctx); - - case Basic_f16be: return LLVMHalfTypeInContext(ctx); - case Basic_f32be: return LLVMFloatTypeInContext(ctx); - case Basic_f64be: return LLVMDoubleTypeInContext(ctx); - - case Basic_complex32: - { - char const *name = "..complex32"; - LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); - if (type != nullptr) { - return type; - } - type = LLVMStructCreateNamed(ctx, name); - LLVMTypeRef fields[2] = { - lb_type(m, t_f16), - lb_type(m, t_f16), - }; - LLVMStructSetBody(type, fields, 2, false); - return type; - } - case Basic_complex64: - { - char const *name = "..complex64"; - LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); - if (type != nullptr) { - return type; - } - type = LLVMStructCreateNamed(ctx, name); - LLVMTypeRef fields[2] = { - lb_type(m, t_f32), - lb_type(m, t_f32), - }; - LLVMStructSetBody(type, fields, 2, false); - return type; - } - case Basic_complex128: - { - char const *name = "..complex128"; - LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); - if (type != nullptr) { - return type; - } - type = LLVMStructCreateNamed(ctx, name); - LLVMTypeRef fields[2] = { - lb_type(m, t_f64), - lb_type(m, t_f64), - }; - LLVMStructSetBody(type, fields, 2, false); - return type; - } - - case Basic_quaternion64: - { - char const *name = "..quaternion64"; - LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); - if (type != nullptr) { - return type; - } - type = LLVMStructCreateNamed(ctx, name); - LLVMTypeRef fields[4] = { - lb_type(m, t_f16), - lb_type(m, t_f16), - lb_type(m, t_f16), - lb_type(m, t_f16), - }; - LLVMStructSetBody(type, fields, 4, false); - return type; - } - case Basic_quaternion128: - { - char const *name = "..quaternion128"; - LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); - if (type != nullptr) { - return type; - } - type = LLVMStructCreateNamed(ctx, name); - LLVMTypeRef fields[4] = { - lb_type(m, t_f32), - lb_type(m, t_f32), - lb_type(m, t_f32), - lb_type(m, t_f32), - }; - LLVMStructSetBody(type, fields, 4, false); - return type; - } - case Basic_quaternion256: - { - char const *name = "..quaternion256"; - LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); - if (type != nullptr) { - return type; - } - type = LLVMStructCreateNamed(ctx, name); - LLVMTypeRef fields[4] = { - lb_type(m, t_f64), - lb_type(m, t_f64), - lb_type(m, t_f64), - lb_type(m, t_f64), - }; - LLVMStructSetBody(type, fields, 4, false); - return type; - } - - case Basic_int: return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size); - case Basic_uint: return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size); - - case Basic_uintptr: return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size); - - case Basic_rawptr: return LLVMPointerType(LLVMInt8TypeInContext(ctx), 0); - case Basic_string: - { - char const *name = "..string"; - LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); - if (type != nullptr) { - return type; - } - type = LLVMStructCreateNamed(ctx, name); - LLVMTypeRef fields[2] = { - LLVMPointerType(lb_type(m, t_u8), 0), - lb_type(m, t_int), - }; - LLVMStructSetBody(type, fields, 2, false); - return type; - } - case Basic_cstring: return LLVMPointerType(LLVMInt8TypeInContext(ctx), 0); - case Basic_any: - { - char const *name = "..any"; - LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); - if (type != nullptr) { - return type; - } - type = LLVMStructCreateNamed(ctx, name); - LLVMTypeRef fields[2] = { - lb_type(m, t_rawptr), - lb_type(m, t_typeid), - }; - LLVMStructSetBody(type, fields, 2, false); - return type; - } - - case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)build_context.word_size); - - // Endian Specific Types - case Basic_i16le: return LLVMInt16TypeInContext(ctx); - case Basic_u16le: return LLVMInt16TypeInContext(ctx); - case Basic_i32le: return LLVMInt32TypeInContext(ctx); - case Basic_u32le: return LLVMInt32TypeInContext(ctx); - case Basic_i64le: return LLVMInt64TypeInContext(ctx); - case Basic_u64le: return LLVMInt64TypeInContext(ctx); - case Basic_i128le: return LLVMInt128TypeInContext(ctx); - case Basic_u128le: return LLVMInt128TypeInContext(ctx); - - case Basic_i16be: return LLVMInt16TypeInContext(ctx); - case Basic_u16be: return LLVMInt16TypeInContext(ctx); - case Basic_i32be: return LLVMInt32TypeInContext(ctx); - case Basic_u32be: return LLVMInt32TypeInContext(ctx); - case Basic_i64be: return LLVMInt64TypeInContext(ctx); - case Basic_u64be: return LLVMInt64TypeInContext(ctx); - case Basic_i128be: return LLVMInt128TypeInContext(ctx); - case Basic_u128be: return LLVMInt128TypeInContext(ctx); - - // Untyped types - case Basic_UntypedBool: GB_PANIC("Basic_UntypedBool"); break; - case Basic_UntypedInteger: GB_PANIC("Basic_UntypedInteger"); break; - case Basic_UntypedFloat: GB_PANIC("Basic_UntypedFloat"); break; - case Basic_UntypedComplex: GB_PANIC("Basic_UntypedComplex"); break; - case Basic_UntypedQuaternion: GB_PANIC("Basic_UntypedQuaternion"); break; - case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break; - case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break; - case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break; - case Basic_UntypedUndef: GB_PANIC("Basic_UntypedUndef"); break; - } - break; - case Type_Named: - { - Type *base = base_type(type->Named.base); - - switch (base->kind) { - case Type_Basic: - return lb_type_internal(m, base); - - case Type_Named: - case Type_Generic: - GB_PANIC("INVALID TYPE"); - break; - - case Type_Pointer: - case Type_Array: - case Type_EnumeratedArray: - case Type_Slice: - case Type_DynamicArray: - case Type_Map: - case Type_Enum: - case Type_BitSet: - case Type_SimdVector: - return lb_type_internal(m, base); - - // TODO(bill): Deal with this correctly. Can this be named? - case Type_Proc: - return lb_type_internal(m, base); - - case Type_Tuple: - return lb_type_internal(m, base); - } - - LLVMTypeRef *found = map_get(&m->types, hash_type(base)); - if (found) { - LLVMTypeKind kind = LLVMGetTypeKind(*found); - if (kind == LLVMStructTypeKind) { - char const *name = alloc_cstring(permanent_allocator(), lb_get_entity_name(m, type->Named.type_name)); - LLVMTypeRef llvm_type = LLVMGetTypeByName(m->mod, name); - if (llvm_type != nullptr) { - return llvm_type; - } - llvm_type = LLVMStructCreateNamed(ctx, name); - map_set(&m->types, hash_type(type), llvm_type); - lb_clone_struct_type(llvm_type, *found); - return llvm_type; - } - } - - switch (base->kind) { - case Type_Struct: - case Type_Union: - { - char const *name = alloc_cstring(permanent_allocator(), lb_get_entity_name(m, type->Named.type_name)); - LLVMTypeRef llvm_type = LLVMGetTypeByName(m->mod, name); - if (llvm_type != nullptr) { - return llvm_type; - } - llvm_type = LLVMStructCreateNamed(ctx, name); - map_set(&m->types, hash_type(type), llvm_type); - lb_clone_struct_type(llvm_type, lb_type(m, base)); - return llvm_type; - } - } - - - return lb_type_internal(m, base); - } - - case Type_Pointer: - return LLVMPointerType(lb_type(m, type_deref(type)), 0); - - case Type_Array: { - m->internal_type_level -= 1; - LLVMTypeRef t = LLVMArrayType(lb_type(m, type->Array.elem), cast(unsigned)type->Array.count); - m->internal_type_level += 1; - return t; - } - - case Type_EnumeratedArray: { - m->internal_type_level -= 1; - LLVMTypeRef t = LLVMArrayType(lb_type(m, type->EnumeratedArray.elem), cast(unsigned)type->EnumeratedArray.count); - m->internal_type_level += 1; - return t; - } - - case Type_Slice: - { - LLVMTypeRef fields[2] = { - LLVMPointerType(lb_type(m, type->Slice.elem), 0), // data - lb_type(m, t_int), // len - }; - return LLVMStructTypeInContext(ctx, fields, 2, false); - } - break; - - case Type_DynamicArray: - { - LLVMTypeRef fields[4] = { - LLVMPointerType(lb_type(m, type->DynamicArray.elem), 0), // data - lb_type(m, t_int), // len - lb_type(m, t_int), // cap - lb_type(m, t_allocator), // allocator - }; - return LLVMStructTypeInContext(ctx, fields, 4, false); - } - break; - - case Type_Map: - return lb_type(m, type->Map.internal_type); - - case Type_Struct: - { - if (type->Struct.is_raw_union) { - unsigned field_count = 2; - LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count); - i64 alignment = type_align_of(type); - unsigned size_of_union = cast(unsigned)type_size_of(type); - fields[0] = lb_alignment_prefix_type_hack(m, alignment); - fields[1] = LLVMArrayType(lb_type(m, t_u8), size_of_union); - return LLVMStructTypeInContext(ctx, fields, field_count, false); - } - - isize offset = 0; - if (type->Struct.custom_align > 0) { - offset = 1; - } - - m->internal_type_level += 1; - defer (m->internal_type_level -= 1); - - unsigned field_count = cast(unsigned)(type->Struct.fields.count + offset); - LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); - - for_array(i, type->Struct.fields) { - Entity *field = type->Struct.fields[i]; - fields[i+offset] = lb_type(m, field->type); - } - - - if (type->Struct.custom_align > 0) { - fields[0] = lb_alignment_prefix_type_hack(m, type->Struct.custom_align); - } - - return LLVMStructTypeInContext(ctx, fields, field_count, type->Struct.is_packed); - } - break; - - case Type_Union: - if (type->Union.variants.count == 0) { - return LLVMStructTypeInContext(ctx, nullptr, 0, false); - } else { - // NOTE(bill): The zero size array is used to fix the alignment used in a structure as - // LLVM takes the first element's alignment as the entire alignment (like C) - i64 align = type_align_of(type); - i64 size = type_size_of(type); - - if (is_type_union_maybe_pointer_original_alignment(type)) { - LLVMTypeRef fields[1] = {lb_type(m, type->Union.variants[0])}; - return LLVMStructTypeInContext(ctx, fields, 1, false); - } - - unsigned block_size = cast(unsigned)type->Union.variant_block_size; - - LLVMTypeRef fields[3] = {}; - unsigned field_count = 1; - fields[0] = lb_alignment_prefix_type_hack(m, align); - if (is_type_union_maybe_pointer(type)) { - field_count += 1; - fields[1] = lb_type(m, type->Union.variants[0]); - } else { - field_count += 2; - if (block_size == align) { - fields[1] = LLVMIntTypeInContext(m->ctx, 8*block_size); - } else { - fields[1] = LLVMArrayType(lb_type(m, t_u8), block_size); - } - fields[2] = lb_type(m, union_tag_type(type)); - } - - return LLVMStructTypeInContext(ctx, fields, field_count, false); - } - break; - - case Type_Enum: - return lb_type(m, base_enum_type(type)); - - case Type_Tuple: - if (type->Tuple.variables.count == 1) { - return lb_type(m, type->Tuple.variables[0]->type); - } else { - unsigned field_count = cast(unsigned)(type->Tuple.variables.count); - LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); - - for_array(i, type->Tuple.variables) { - Entity *field = type->Tuple.variables[i]; - - LLVMTypeRef param_type = nullptr; - param_type = lb_type(m, field->type); - - fields[i] = param_type; - } - - return LLVMStructTypeInContext(ctx, fields, field_count, type->Tuple.is_packed); - } - - case Type_Proc: - // if (m->internal_type_level > 256) { // TODO HACK(bill): is this really enough? - if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough? - return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0); - } else { - unsigned param_count = 0; - if (type->Proc.calling_convention == ProcCC_Odin) { - param_count += 1; - } - - if (type->Proc.param_count != 0) { - GB_ASSERT(type->Proc.params->kind == Type_Tuple); - for_array(i, type->Proc.params->Tuple.variables) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - if (e->flags & EntityFlag_CVarArg) { - continue; - } - param_count += 1; - } - } - m->internal_type_level += 1; - defer (m->internal_type_level -= 1); - - LLVMTypeRef ret = nullptr; - LLVMTypeRef *params = gb_alloc_array(heap_allocator(), LLVMTypeRef, param_count); - if (type->Proc.result_count != 0) { - Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); - ret = lb_type(m, single_ret); - if (ret != nullptr) { - if (is_type_boolean(single_ret) && - is_calling_convention_none(type->Proc.calling_convention) && - type_size_of(single_ret) <= 1) { - ret = LLVMInt1TypeInContext(m->ctx); - } - } - } - - unsigned param_index = 0; - if (type->Proc.param_count != 0) { - GB_ASSERT(type->Proc.params->kind == Type_Tuple); - for_array(i, type->Proc.params->Tuple.variables) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - if (e->flags & EntityFlag_CVarArg) { - continue; - } - - Type *e_type = reduce_tuple_to_single_type(e->type); - - LLVMTypeRef param_type = nullptr; - if (is_type_boolean(e_type) && - type_size_of(e_type) <= 1) { - param_type = LLVMInt1TypeInContext(m->ctx); - } else { - if (is_type_proc(e_type)) { - param_type = lb_type(m, t_rawptr); - } else { - param_type = lb_type(m, e_type); - } - } - - params[param_index++] = param_type; - } - } - if (param_index < param_count) { - params[param_index++] = lb_type(m, t_rawptr); - } - GB_ASSERT(param_index == param_count); - - lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention); - { - for_array(j, ft->args) { - auto arg = ft->args[j]; - GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx, - "\n\t%s %td/%td" - "\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", - LLVMPrintTypeToString(arg.type), - j, ft->args.count, - LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext()); - } - GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx, - "\n\t%s" - "\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", - LLVMPrintTypeToString(ft->ret.type), - LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext()); - } - - map_set(&m->function_type_map, hash_type(type), ft); - LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg); - LLVMTypeRef new_abi_fn_type = LLVMGetElementType(new_abi_fn_ptr_type); - - GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx, - "\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", - LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext()); - - return new_abi_fn_ptr_type; - } - - break; - case Type_BitSet: - { - Type *ut = bit_set_to_int(type); - return lb_type(m, ut); - } - - case Type_SimdVector: - return LLVMVectorType(lb_type(m, type->SimdVector.elem), cast(unsigned)type->SimdVector.count); - - case Type_RelativePointer: - return lb_type_internal(m, type->RelativePointer.base_integer); - - case Type_RelativeSlice: - { - LLVMTypeRef base_integer = lb_type_internal(m, type->RelativeSlice.base_integer); - - unsigned field_count = 2; - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); - fields[0] = base_integer; - fields[1] = base_integer; - return LLVMStructTypeInContext(ctx, fields, field_count, false); - } - } - - GB_PANIC("Invalid type %s", type_to_string(type)); - return LLVMInt32TypeInContext(ctx); -} - -LLVMTypeRef lb_type(lbModule *m, Type *type) { - type = default_type(type); - - LLVMTypeRef *found = map_get(&m->types, hash_type(type)); - if (found) { - return *found; - } - - LLVMTypeRef llvm_type = nullptr; - - m->internal_type_level += 1; - llvm_type = lb_type_internal(m, type); - m->internal_type_level -= 1; - if (m->internal_type_level == 0) { - map_set(&m->types, hash_type(type), llvm_type); - if (is_type_named(type)) { - map_set(&m->llvm_types, hash_pointer(llvm_type), type); - } - } - return llvm_type; -} - -lbFunctionType *lb_get_function_type(lbModule *m, lbProcedure *p, Type *pt) { - lbFunctionType **ft_found = nullptr; - ft_found = map_get(&m->function_type_map, hash_type(pt)); - if (!ft_found) { - LLVMTypeRef llvm_proc_type = lb_type(p->module, pt); - ft_found = map_get(&m->function_type_map, hash_type(pt)); - } - GB_ASSERT(ft_found != nullptr); - - return *ft_found; -} - - -LLVMMetadataRef lb_get_llvm_metadata(lbModule *m, void *key) { - if (key == nullptr) { - return nullptr; - } - auto found = map_get(&m->debug_values, hash_pointer(key)); - if (found) { - return *found; - } - return nullptr; -} -void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef value) { - if (key != nullptr) { - map_set(&m->debug_values, hash_pointer(key), value); - } -} - -LLVMMetadataRef lb_get_llvm_file_metadata_from_node(lbModule *m, Ast *node) { - if (node == nullptr) { - return nullptr; - } - return lb_get_llvm_metadata(m, node->file); -} - -LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) { - GB_ASSERT_MSG(p->debug_info != nullptr, "missing debug information for %.*s", LIT(p->name)); - - for (isize i = p->scope_stack.count-1; i >= 0; i--) { - Scope *s = p->scope_stack[i]; - LLVMMetadataRef md = lb_get_llvm_metadata(p->module, s); - if (md) { - return md; - } - } - return p->debug_info; -} - -LLVMMetadataRef lb_debug_location_from_token_pos(lbProcedure *p, TokenPos pos) { - LLVMMetadataRef scope = lb_get_current_debug_scope(p); - GB_ASSERT_MSG(scope != nullptr, "%.*s", LIT(p->name)); - return LLVMDIBuilderCreateDebugLocation(p->module->ctx, cast(unsigned)pos.line, cast(unsigned)pos.column, scope, nullptr); -} -LLVMMetadataRef lb_debug_location_from_ast(lbProcedure *p, Ast *node) { - GB_ASSERT(node != nullptr); - return lb_debug_location_from_token_pos(p, ast_token(node).pos); -} - -LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) { - Type *original_type = type; - - LLVMContextRef ctx = m->ctx; - i64 size = type_size_of(type); // Check size - - GB_ASSERT(type != t_invalid); - - unsigned const word_size = cast(unsigned)build_context.word_size; - unsigned const word_bits = cast(unsigned)(8*build_context.word_size); - - GB_ASSERT(type->kind == Type_Proc); - LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx); - unsigned parameter_count = 1; - for (i32 i = 0; i < type->Proc.param_count; i++) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind == Entity_Variable) { - parameter_count += 1; - } - } - LLVMMetadataRef *parameters = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, parameter_count); - - unsigned param_index = 0; - if (type->Proc.result_count == 0) { - parameters[param_index++] = nullptr; - } else { - parameters[param_index++] = lb_debug_type(m, type->Proc.results); - } - - LLVMMetadataRef parent_scope = nullptr; - LLVMMetadataRef scope = nullptr; - LLVMMetadataRef file = nullptr; - - for (i32 i = 0; i < type->Proc.param_count; i++) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - parameters[param_index] = lb_debug_type(m, e->type); - param_index += 1; - } - - LLVMDIFlags flags = LLVMDIFlagZero; - if (type->Proc.diverging) { - flags = LLVMDIFlagNoReturn; - } - - return LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, parameters, parameter_count, flags); -} - -LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *type, u64 offset_in_bits) { - unsigned field_line = 1; - LLVMDIFlags field_flags = LLVMDIFlagZero; - - AstPackage *pkg = m->info->runtime_package; - GB_ASSERT(pkg->files.count != 0); - LLVMMetadataRef file = lb_get_llvm_metadata(m, pkg->files[0]); - LLVMMetadataRef scope = file; - - return LLVMDIBuilderCreateMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, field_line, - 8*cast(u64)type_size_of(type), 8*cast(u32)type_align_of(type), offset_in_bits, - field_flags, lb_debug_type(m, type) - ); -} -LLVMMetadataRef lb_debug_basic_struct(lbModule *m, String const &name, u64 size_in_bits, u32 align_in_bits, LLVMMetadataRef *elements, unsigned element_count) { - AstPackage *pkg = m->info->runtime_package; - GB_ASSERT(pkg->files.count != 0); - LLVMMetadataRef file = lb_get_llvm_metadata(m, pkg->files[0]); - LLVMMetadataRef scope = file; - - return LLVMDIBuilderCreateStructType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, 1, size_in_bits, align_in_bits, LLVMDIFlagZero, nullptr, elements, element_count, 0, nullptr, "", 0); -} - - -LLVMMetadataRef lb_debug_type_basic_type(lbModule *m, String const &name, u64 size_in_bits, LLVMDWARFTypeEncoding encoding, LLVMDIFlags flags = LLVMDIFlagZero) { - LLVMMetadataRef basic_type = LLVMDIBuilderCreateBasicType(m->debug_builder, cast(char const *)name.text, name.len, size_in_bits, encoding, flags); -#if 1 - LLVMMetadataRef final_decl = LLVMDIBuilderCreateTypedef(m->debug_builder, basic_type, cast(char const *)name.text, name.len, nullptr, 0, nullptr, cast(u32)size_in_bits); - return final_decl; -#else - return basic_type; -#endif -} - -LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { - Type *original_type = type; - - LLVMContextRef ctx = m->ctx; - i64 size = type_size_of(type); // Check size - - GB_ASSERT(type != t_invalid); - - unsigned const word_size = cast(unsigned)build_context.word_size; - unsigned const word_bits = cast(unsigned)(8*build_context.word_size); - - switch (type->kind) { - case Type_Basic: - switch (type->Basic.kind) { - case Basic_llvm_bool: return lb_debug_type_basic_type(m, str_lit("llvm bool"), 1, LLVMDWARFTypeEncoding_Boolean); - case Basic_bool: return lb_debug_type_basic_type(m, str_lit("bool"), 8, LLVMDWARFTypeEncoding_Boolean); - case Basic_b8: return lb_debug_type_basic_type(m, str_lit("b8"), 8, LLVMDWARFTypeEncoding_Boolean); - case Basic_b16: return lb_debug_type_basic_type(m, str_lit("b16"), 16, LLVMDWARFTypeEncoding_Boolean); - case Basic_b32: return lb_debug_type_basic_type(m, str_lit("b32"), 32, LLVMDWARFTypeEncoding_Boolean); - case Basic_b64: return lb_debug_type_basic_type(m, str_lit("b64"), 64, LLVMDWARFTypeEncoding_Boolean); - - case Basic_i8: return lb_debug_type_basic_type(m, str_lit("i8"), 8, LLVMDWARFTypeEncoding_Signed); - case Basic_u8: return lb_debug_type_basic_type(m, str_lit("u8"), 8, LLVMDWARFTypeEncoding_Unsigned); - case Basic_i16: return lb_debug_type_basic_type(m, str_lit("i16"), 16, LLVMDWARFTypeEncoding_Signed); - case Basic_u16: return lb_debug_type_basic_type(m, str_lit("u16"), 16, LLVMDWARFTypeEncoding_Unsigned); - case Basic_i32: return lb_debug_type_basic_type(m, str_lit("i32"), 32, LLVMDWARFTypeEncoding_Signed); - case Basic_u32: return lb_debug_type_basic_type(m, str_lit("u32"), 32, LLVMDWARFTypeEncoding_Unsigned); - case Basic_i64: return lb_debug_type_basic_type(m, str_lit("i64"), 64, LLVMDWARFTypeEncoding_Signed); - case Basic_u64: return lb_debug_type_basic_type(m, str_lit("u64"), 64, LLVMDWARFTypeEncoding_Unsigned); - case Basic_i128: return lb_debug_type_basic_type(m, str_lit("i128"), 128, LLVMDWARFTypeEncoding_Signed); - case Basic_u128: return lb_debug_type_basic_type(m, str_lit("u128"), 128, LLVMDWARFTypeEncoding_Unsigned); - - case Basic_rune: return lb_debug_type_basic_type(m, str_lit("rune"), 32, LLVMDWARFTypeEncoding_Utf); - - - case Basic_f16: return lb_debug_type_basic_type(m, str_lit("f16"), 16, LLVMDWARFTypeEncoding_Float); - case Basic_f32: return lb_debug_type_basic_type(m, str_lit("f32"), 32, LLVMDWARFTypeEncoding_Float); - case Basic_f64: return lb_debug_type_basic_type(m, str_lit("f64"), 64, LLVMDWARFTypeEncoding_Float); - - case Basic_int: return lb_debug_type_basic_type(m, str_lit("int"), word_bits, LLVMDWARFTypeEncoding_Signed); - case Basic_uint: return lb_debug_type_basic_type(m, str_lit("uint"), word_bits, LLVMDWARFTypeEncoding_Unsigned); - case Basic_uintptr: return lb_debug_type_basic_type(m, str_lit("uintptr"), word_bits, LLVMDWARFTypeEncoding_Unsigned); - - case Basic_typeid: - return lb_debug_type_basic_type(m, str_lit("typeid"), word_bits, LLVMDWARFTypeEncoding_Unsigned); - - // Endian Specific Types - case Basic_i16le: return lb_debug_type_basic_type(m, str_lit("i16le"), 16, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian); - case Basic_u16le: return lb_debug_type_basic_type(m, str_lit("u16le"), 16, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagLittleEndian); - case Basic_i32le: return lb_debug_type_basic_type(m, str_lit("i32le"), 32, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian); - case Basic_u32le: return lb_debug_type_basic_type(m, str_lit("u32le"), 32, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagLittleEndian); - case Basic_i64le: return lb_debug_type_basic_type(m, str_lit("i64le"), 64, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian); - case Basic_u64le: return lb_debug_type_basic_type(m, str_lit("u64le"), 64, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagLittleEndian); - case Basic_i128le: return lb_debug_type_basic_type(m, str_lit("i128le"), 128, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian); - case Basic_u128le: return lb_debug_type_basic_type(m, str_lit("u128le"), 128, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagLittleEndian); - - case Basic_f16le: return lb_debug_type_basic_type(m, str_lit("f16le"), 16, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); - case Basic_f32le: return lb_debug_type_basic_type(m, str_lit("f32le"), 32, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); - case Basic_f64le: return lb_debug_type_basic_type(m, str_lit("f64le"), 64, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); - - case Basic_i16be: return lb_debug_type_basic_type(m, str_lit("i16be"), 16, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagBigEndian); - case Basic_u16be: return lb_debug_type_basic_type(m, str_lit("u16be"), 16, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian); - case Basic_i32be: return lb_debug_type_basic_type(m, str_lit("i32be"), 32, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagBigEndian); - case Basic_u32be: return lb_debug_type_basic_type(m, str_lit("u32be"), 32, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian); - case Basic_i64be: return lb_debug_type_basic_type(m, str_lit("i64be"), 64, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagBigEndian); - case Basic_u64be: return lb_debug_type_basic_type(m, str_lit("u64be"), 64, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian); - case Basic_i128be: return lb_debug_type_basic_type(m, str_lit("i128be"), 128, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagBigEndian); - case Basic_u128be: return lb_debug_type_basic_type(m, str_lit("u128be"), 128, LLVMDWARFTypeEncoding_Unsigned, LLVMDIFlagBigEndian); - - case Basic_f16be: return lb_debug_type_basic_type(m, str_lit("f16be"), 16, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); - case Basic_f32be: return lb_debug_type_basic_type(m, str_lit("f32be"), 32, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); - case Basic_f64be: return lb_debug_type_basic_type(m, str_lit("f64be"), 64, LLVMDWARFTypeEncoding_Float, LLVMDIFlagLittleEndian); - - case Basic_complex32: - { - LLVMMetadataRef elements[2] = {}; - elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f16, 0); - elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 4); - return lb_debug_basic_struct(m, str_lit("complex32"), 64, 32, elements, gb_count_of(elements)); - } - case Basic_complex64: - { - LLVMMetadataRef elements[2] = {}; - elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f32, 0); - elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 4); - return lb_debug_basic_struct(m, str_lit("complex64"), 64, 32, elements, gb_count_of(elements)); - } - case Basic_complex128: - { - LLVMMetadataRef elements[2] = {}; - elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f64, 0); - elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 8); - return lb_debug_basic_struct(m, str_lit("complex128"), 128, 64, elements, gb_count_of(elements)); - } - - case Basic_quaternion64: - { - LLVMMetadataRef elements[4] = {}; - elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 0); - elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f16, 4); - elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f16, 8); - elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f16, 12); - return lb_debug_basic_struct(m, str_lit("quaternion64"), 128, 32, elements, gb_count_of(elements)); - } - case Basic_quaternion128: - { - LLVMMetadataRef elements[4] = {}; - elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 0); - elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f32, 4); - elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f32, 8); - elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f32, 12); - return lb_debug_basic_struct(m, str_lit("quaternion128"), 128, 32, elements, gb_count_of(elements)); - } - case Basic_quaternion256: - { - LLVMMetadataRef elements[4] = {}; - elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 0); - elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f64, 8); - elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f64, 16); - elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f64, 24); - return lb_debug_basic_struct(m, str_lit("quaternion256"), 256, 32, elements, gb_count_of(elements)); - } - - - - case Basic_rawptr: - { - LLVMMetadataRef void_type = lb_debug_type_basic_type(m, str_lit("void"), 8, LLVMDWARFTypeEncoding_Unsigned); - return LLVMDIBuilderCreatePointerType(m->debug_builder, void_type, word_bits, word_bits, LLVMDWARFTypeEncoding_Address, "rawptr", 6); - } - case Basic_string: - { - LLVMMetadataRef elements[2] = {}; - elements[0] = lb_debug_struct_field(m, str_lit("data"), t_u8_ptr, 0); - elements[1] = lb_debug_struct_field(m, str_lit("len"), t_int, word_bits); - return lb_debug_basic_struct(m, str_lit("string"), 2*word_bits, word_bits, elements, gb_count_of(elements)); - } - case Basic_cstring: - { - LLVMMetadataRef char_type = lb_debug_type_basic_type(m, str_lit("char"), 8, LLVMDWARFTypeEncoding_Unsigned); - return LLVMDIBuilderCreatePointerType(m->debug_builder, char_type, word_bits, word_bits, 0, "cstring", 7); - } - case Basic_any: - { - LLVMMetadataRef elements[2] = {}; - elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0); - elements[1] = lb_debug_struct_field(m, str_lit("id"), t_typeid, word_bits); - return lb_debug_basic_struct(m, str_lit("any"), 2*word_bits, word_bits, elements, gb_count_of(elements)); - } - - // Untyped types - case Basic_UntypedBool: GB_PANIC("Basic_UntypedBool"); break; - case Basic_UntypedInteger: GB_PANIC("Basic_UntypedInteger"); break; - case Basic_UntypedFloat: GB_PANIC("Basic_UntypedFloat"); break; - case Basic_UntypedComplex: GB_PANIC("Basic_UntypedComplex"); break; - case Basic_UntypedQuaternion: GB_PANIC("Basic_UntypedQuaternion"); break; - case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break; - case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break; - case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break; - case Basic_UntypedUndef: GB_PANIC("Basic_UntypedUndef"); break; - - default: GB_PANIC("Basic Unhandled"); break; - } - break; - - case Type_Named: - GB_PANIC("Type_Named should be handled in lb_debug_type separately"); - - case Type_Pointer: - return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->Pointer.elem), word_bits, word_bits, 0, nullptr, 0); - - case Type_Array: { - LLVMMetadataRef subscripts[1] = {}; - subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder, - 0ll, - type->Array.count - ); - - return LLVMDIBuilderCreateArrayType(m->debug_builder, - 8*cast(uint64_t)type_size_of(type), - 8*cast(unsigned)type_align_of(type), - lb_debug_type(m, type->Array.elem), - subscripts, gb_count_of(subscripts)); - } - - case Type_EnumeratedArray: { - LLVMMetadataRef subscripts[1] = {}; - subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder, - 0ll, - type->EnumeratedArray.count - ); - - LLVMMetadataRef array_type = LLVMDIBuilderCreateArrayType(m->debug_builder, - 8*cast(uint64_t)type_size_of(type), - 8*cast(unsigned)type_align_of(type), - lb_debug_type(m, type->EnumeratedArray.elem), - subscripts, gb_count_of(subscripts)); - gbString name = type_to_string(type, temporary_allocator()); - return LLVMDIBuilderCreateTypedef(m->debug_builder, array_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type))); - } - - - case Type_Struct: - case Type_Union: - case Type_Slice: - case Type_DynamicArray: - case Type_Map: - case Type_BitSet: - { - unsigned tag = DW_TAG_structure_type; - if (is_type_raw_union(type) || is_type_union(type)) { - tag = DW_TAG_union_type; - } - u64 size_in_bits = cast(u64)(8*type_size_of(type)); - u32 align_in_bits = cast(u32)(8*type_size_of(type)); - LLVMDIFlags flags = LLVMDIFlagZero; - - LLVMMetadataRef temp_forward_decl = LLVMDIBuilderCreateReplaceableCompositeType( - m->debug_builder, tag, "", 0, nullptr, nullptr, 0, 0, size_in_bits, align_in_bits, flags, "", 0 - ); - lbIncompleteDebugType idt = {}; - idt.type = type; - idt.metadata = temp_forward_decl; - - array_add(&m->debug_incomplete_types, idt); - lb_set_llvm_metadata(m, type, temp_forward_decl); - return temp_forward_decl; - } - - case Type_Enum: - { - LLVMMetadataRef scope = nullptr; - LLVMMetadataRef file = nullptr; - unsigned line = 0; - unsigned element_count = cast(unsigned)type->Enum.fields.count; - LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count); - Type *bt = base_enum_type(type); - LLVMBool is_unsigned = is_type_unsigned(bt); - for (unsigned i = 0; i < element_count; i++) { - Entity *f = type->Enum.fields[i]; - GB_ASSERT(f->kind == Entity_Constant); - String name = f->token.string; - i64 value = exact_value_to_i64(f->Constant.value); - elements[i] = LLVMDIBuilderCreateEnumerator(m->debug_builder, cast(char const *)name.text, cast(size_t)name.len, value, is_unsigned); - } - LLVMMetadataRef class_type = lb_debug_type(m, bt); - return LLVMDIBuilderCreateEnumerationType(m->debug_builder, scope, "", 0, file, line, 8*type_size_of(type), 8*cast(unsigned)type_align_of(type), elements, element_count, class_type); - } - - case Type_Tuple: - if (type->Tuple.variables.count == 1) { - return lb_debug_type(m, type->Tuple.variables[0]->type); - } else { - type_set_offsets(type); - LLVMMetadataRef parent_scope = nullptr; - LLVMMetadataRef scope = nullptr; - LLVMMetadataRef file = nullptr; - unsigned line = 0; - u64 size_in_bits = 8*cast(u64)type_size_of(type); - u32 align_in_bits = 8*cast(u32)type_align_of(type); - LLVMDIFlags flags = LLVMDIFlagZero; - - unsigned element_count = cast(unsigned)type->Tuple.variables.count; - LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count); - - for (unsigned i = 0; i < element_count; i++) { - Entity *f = type->Tuple.variables[i]; - GB_ASSERT(f->kind == Entity_Variable); - String name = f->token.string; - unsigned field_line = 0; - LLVMDIFlags field_flags = LLVMDIFlagZero; - u64 offset_in_bits = 8*cast(u64)type->Tuple.offsets[i]; - elements[i] = LLVMDIBuilderCreateMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, field_line, - 8*cast(u64)type_size_of(f->type), 8*cast(u32)type_align_of(f->type), offset_in_bits, - field_flags, lb_debug_type(m, f->type) - ); - } - - - return LLVMDIBuilderCreateStructType(m->debug_builder, parent_scope, "", 0, file, line, - size_in_bits, align_in_bits, flags, - nullptr, elements, element_count, 0, nullptr, - "", 0 - ); - } - - case Type_Proc: - { - LLVMMetadataRef proc_underlying_type = lb_debug_type_internal_proc(m, type); - LLVMMetadataRef pointer_type = LLVMDIBuilderCreatePointerType(m->debug_builder, proc_underlying_type, word_bits, word_bits, 0, nullptr, 0); - gbString name = type_to_string(type, temporary_allocator()); - return LLVMDIBuilderCreateTypedef(m->debug_builder, pointer_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type))); - } - break; - - case Type_SimdVector: - return LLVMDIBuilderCreateVectorType(m->debug_builder, cast(unsigned)type->SimdVector.count, 8*cast(unsigned)type_align_of(type), lb_debug_type(m, type->SimdVector.elem), nullptr, 0); - - case Type_RelativePointer: { - LLVMMetadataRef base_integer = lb_debug_type(m, type->RelativePointer.base_integer); - gbString name = type_to_string(type, temporary_allocator()); - return LLVMDIBuilderCreateTypedef(m->debug_builder, base_integer, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type))); - } - - case Type_RelativeSlice: - { - unsigned element_count = 0; - LLVMMetadataRef elements[2] = {}; - Type *base_integer = type->RelativeSlice.base_integer; - elements[0] = lb_debug_struct_field(m, str_lit("data_offset"), base_integer, 0); - elements[1] = lb_debug_struct_field(m, str_lit("len"), base_integer, 8*type_size_of(base_integer)); - gbString name = type_to_string(type, temporary_allocator()); - return LLVMDIBuilderCreateStructType(m->debug_builder, nullptr, name, gb_string_length(name), nullptr, 0, 2*word_bits, word_bits, LLVMDIFlagZero, nullptr, elements, element_count, 0, nullptr, "", 0); - } - } - - GB_PANIC("Invalid type %s", type_to_string(type)); - return nullptr; -} - -LLVMMetadataRef lb_get_base_scope_metadata(lbModule *m, Scope *scope) { - LLVMMetadataRef found = nullptr; - for (;;) { - if (scope == nullptr) { - return nullptr; - } - if (scope->flags & ScopeFlag_Proc) { - found = lb_get_llvm_metadata(m, scope->procedure_entity); - if (found) { - return found; - } - } - if (scope->flags & ScopeFlag_File) { - found = lb_get_llvm_metadata(m, scope->file); - if (found) { - return found; - } - } - scope = scope->parent; - } -} - -LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) { - GB_ASSERT(type != nullptr); - LLVMMetadataRef found = lb_get_llvm_metadata(m, type); - if (found != nullptr) { - return found; - } - - if (type->kind == Type_Named) { - LLVMMetadataRef file = nullptr; - unsigned line = 0; - LLVMMetadataRef scope = nullptr; - - - if (type->Named.type_name != nullptr) { - Entity *e = type->Named.type_name; - scope = lb_get_base_scope_metadata(m, e->scope); - if (scope != nullptr) { - file = LLVMDIScopeGetFile(scope); - } - line = cast(unsigned)e->token.pos.line; - } - // TODO(bill): location data for Type_Named - - u64 size_in_bits = 8*type_size_of(type); - u32 align_in_bits = 8*cast(u32)type_align_of(type); - String name = type->Named.name; - char const *name_text = cast(char const *)name.text; - size_t name_len = cast(size_t)name.len; - unsigned tag = DW_TAG_structure_type; - if (is_type_raw_union(type) || is_type_union(type)) { - tag = DW_TAG_union_type; - } - LLVMDIFlags flags = LLVMDIFlagZero; - - Type *bt = base_type(type->Named.base); - - lbIncompleteDebugType idt = {}; - idt.type = type; - - switch (bt->kind) { - case Type_Enum: - { - unsigned line = 0; - unsigned element_count = cast(unsigned)bt->Enum.fields.count; - LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count); - Type *ct = base_enum_type(type); - LLVMBool is_unsigned = is_type_unsigned(ct); - for (unsigned i = 0; i < element_count; i++) { - Entity *f = bt->Enum.fields[i]; - GB_ASSERT(f->kind == Entity_Constant); - String name = f->token.string; - i64 value = exact_value_to_i64(f->Constant.value); - elements[i] = LLVMDIBuilderCreateEnumerator(m->debug_builder, cast(char const *)name.text, cast(size_t)name.len, value, is_unsigned); - } - LLVMMetadataRef class_type = lb_debug_type(m, ct); - return LLVMDIBuilderCreateEnumerationType(m->debug_builder, scope, name_text, name_len, file, line, 8*type_size_of(type), 8*cast(unsigned)type_align_of(type), elements, element_count, class_type); - } - - - case Type_Basic: - case Type_Pointer: - case Type_Array: - case Type_EnumeratedArray: - case Type_Tuple: - case Type_Proc: - case Type_SimdVector: - case Type_RelativePointer: - case Type_RelativeSlice: - { - LLVMMetadataRef debug_bt = lb_debug_type(m, bt); - LLVMMetadataRef final_decl = LLVMDIBuilderCreateTypedef(m->debug_builder, debug_bt, name_text, name_len, file, line, scope, align_in_bits); - lb_set_llvm_metadata(m, type, final_decl); - return final_decl; - } - - case Type_Slice: - case Type_DynamicArray: - case Type_Map: - case Type_Struct: - case Type_Union: - case Type_BitSet: - LLVMMetadataRef temp_forward_decl = LLVMDIBuilderCreateReplaceableCompositeType( - m->debug_builder, tag, name_text, name_len, nullptr, nullptr, 0, 0, size_in_bits, align_in_bits, flags, "", 0 - ); - idt.metadata = temp_forward_decl; - - array_add(&m->debug_incomplete_types, idt); - lb_set_llvm_metadata(m, type, temp_forward_decl); - return temp_forward_decl; - } - } - - - LLVMMetadataRef dt = lb_debug_type_internal(m, type); - lb_set_llvm_metadata(m, type, dt); - return dt; -} - -void lb_debug_complete_types(lbModule *m) { - unsigned const word_size = cast(unsigned)build_context.word_size; - unsigned const word_bits = cast(unsigned)(8*build_context.word_size); - - for_array(debug_incomplete_type_index, m->debug_incomplete_types) { - auto const &idt = m->debug_incomplete_types[debug_incomplete_type_index]; - GB_ASSERT(idt.type != nullptr); - GB_ASSERT(idt.metadata != nullptr); - - Type *t = idt.type; - Type *bt = base_type(t); - - LLVMMetadataRef parent_scope = nullptr; - LLVMMetadataRef file = nullptr; - unsigned line_number = 0; - u64 size_in_bits = 8*type_size_of(t); - u32 align_in_bits = cast(u32)(8*type_align_of(t)); - LLVMDIFlags flags = LLVMDIFlagZero; - - LLVMMetadataRef derived_from = nullptr; - - LLVMMetadataRef *elements = nullptr; - unsigned element_count = 0; - - - unsigned runtime_lang = 0; // Objective-C runtime version - char const *unique_id = ""; - LLVMMetadataRef vtable_holder = nullptr; - size_t unique_id_len = 0; - - - LLVMMetadataRef record_scope = nullptr; - - switch (bt->kind) { - case Type_Slice: - case Type_DynamicArray: - case Type_Map: - case Type_Struct: - case Type_Union: - case Type_BitSet: { - bool is_union = is_type_raw_union(bt) || is_type_union(bt); - - String name = str_lit("<anonymous-struct>"); - if (t->kind == Type_Named) { - name = t->Named.name; - if (t->Named.type_name && t->Named.type_name->pkg && t->Named.type_name->pkg->name.len != 0) { - name = concatenate3_strings(temporary_allocator(), t->Named.type_name->pkg->name, str_lit("."), t->Named.name); - } - - LLVMMetadataRef file = nullptr; - unsigned line = 0; - LLVMMetadataRef file_scope = nullptr; - - if (t->Named.type_name != nullptr) { - Entity *e = t->Named.type_name; - file_scope = lb_get_llvm_metadata(m, e->scope); - if (file_scope != nullptr) { - file = LLVMDIScopeGetFile(file_scope); - } - line = cast(unsigned)e->token.pos.line; - } - // TODO(bill): location data for Type_Named - - } else { - name = make_string_c(type_to_string(t, temporary_allocator())); - } - - - - switch (bt->kind) { - case Type_Slice: - element_count = 2; - elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count); - elements[0] = lb_debug_struct_field(m, str_lit("data"), alloc_type_pointer(bt->Slice.elem), 0*word_bits); - elements[1] = lb_debug_struct_field(m, str_lit("len"), t_int, 1*word_bits); - break; - case Type_DynamicArray: - element_count = 4; - elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count); - elements[0] = lb_debug_struct_field(m, str_lit("data"), alloc_type_pointer(bt->DynamicArray.elem), 0*word_bits); - elements[1] = lb_debug_struct_field(m, str_lit("len"), t_int, 1*word_bits); - elements[2] = lb_debug_struct_field(m, str_lit("cap"), t_int, 2*word_bits); - elements[3] = lb_debug_struct_field(m, str_lit("allocator"), t_allocator, 3*word_bits); - break; - - case Type_Map: - bt = bt->Map.internal_type; - /*fallthrough*/ - case Type_Struct: - if (file == nullptr) { - if (bt->Struct.node) { - file = lb_get_llvm_metadata(m, bt->Struct.node->file); - line_number = cast(unsigned)ast_token(bt->Struct.node).pos.line; - } - } - - type_set_offsets(bt); - { - isize element_offset = 0; - record_scope = lb_get_llvm_metadata(m, bt->Struct.scope); - switch (bt->Struct.soa_kind) { - case StructSoa_Slice: element_offset = 1; break; - case StructSoa_Dynamic: element_offset = 3; break; - } - element_count = cast(unsigned)(bt->Struct.fields.count + element_offset); - elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count); - switch (bt->Struct.soa_kind) { - case StructSoa_Slice: - elements[0] = LLVMDIBuilderCreateMemberType( - m->debug_builder, record_scope, - ".len", 4, - file, 0, - 8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int), - 8*type_size_of(bt)-word_bits, - LLVMDIFlagZero, lb_debug_type(m, t_int) - ); - break; - case StructSoa_Dynamic: - elements[0] = LLVMDIBuilderCreateMemberType( - m->debug_builder, record_scope, - ".len", 4, - file, 0, - 8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int), - 8*type_size_of(bt)-word_bits + 0*word_bits, - LLVMDIFlagZero, lb_debug_type(m, t_int) - ); - elements[1] = LLVMDIBuilderCreateMemberType( - m->debug_builder, record_scope, - ".cap", 4, - file, 0, - 8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int), - 8*type_size_of(bt)-word_bits + 1*word_bits, - LLVMDIFlagZero, lb_debug_type(m, t_int) - ); - elements[2] = LLVMDIBuilderCreateMemberType( - m->debug_builder, record_scope, - ".allocator", 12, - file, 0, - 8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int), - 8*type_size_of(bt)-word_bits + 2*word_bits, - LLVMDIFlagZero, lb_debug_type(m, t_allocator) - ); - break; - } - - for_array(j, bt->Struct.fields) { - Entity *f = bt->Struct.fields[j]; - String fname = f->token.string; - - unsigned field_line = 0; - LLVMDIFlags field_flags = LLVMDIFlagZero; - u64 offset_in_bits = 8*cast(u64)bt->Struct.offsets[j]; - - elements[element_offset+j] = LLVMDIBuilderCreateMemberType( - m->debug_builder, record_scope, - cast(char const *)fname.text, cast(size_t)fname.len, - file, field_line, - 8*cast(u64)type_size_of(f->type), 8*cast(u32)type_align_of(f->type), - offset_in_bits, - field_flags, lb_debug_type(m, f->type) - ); - } - } - break; - case Type_Union: - { - if (file == nullptr) { - GB_ASSERT(bt->Union.node != nullptr); - file = lb_get_llvm_metadata(m, bt->Union.node->file); - line_number = cast(unsigned)ast_token(bt->Union.node).pos.line; - } - - isize index_offset = 1; - if (is_type_union_maybe_pointer(bt)) { - index_offset = 0; - } - record_scope = lb_get_llvm_metadata(m, bt->Union.scope); - element_count = cast(unsigned)bt->Union.variants.count; - if (index_offset > 0) { - element_count += 1; - } - - elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count); - if (index_offset > 0) { - Type *tag_type = union_tag_type(bt); - unsigned field_line = 0; - u64 offset_in_bits = 8*cast(u64)bt->Union.variant_block_size; - LLVMDIFlags field_flags = LLVMDIFlagZero; - - elements[0] = LLVMDIBuilderCreateMemberType( - m->debug_builder, record_scope, - "tag", 3, - file, field_line, - 8*cast(u64)type_size_of(tag_type), 8*cast(u32)type_align_of(tag_type), - offset_in_bits, - field_flags, lb_debug_type(m, tag_type) - ); - } - - for_array(j, bt->Union.variants) { - Type *variant = bt->Union.variants[j]; - - unsigned field_index = cast(unsigned)(index_offset+j); - - char name[16] = {}; - gb_snprintf(name, gb_size_of(name), "v%u", field_index); - isize name_len = gb_strlen(name); - - unsigned field_line = 0; - LLVMDIFlags field_flags = LLVMDIFlagZero; - u64 offset_in_bits = 0; - - elements[field_index] = LLVMDIBuilderCreateMemberType( - m->debug_builder, record_scope, - name, name_len, - file, field_line, - 8*cast(u64)type_size_of(variant), 8*cast(u32)type_align_of(variant), - offset_in_bits, - field_flags, lb_debug_type(m, variant) - ); - } - } - break; - - case Type_BitSet: - { - if (file == nullptr) { - GB_ASSERT(bt->BitSet.node != nullptr); - file = lb_get_llvm_metadata(m, bt->BitSet.node->file); - line_number = cast(unsigned)ast_token(bt->BitSet.node).pos.line; - } - - LLVMMetadataRef bit_set_field_type = lb_debug_type(m, t_bool); - LLVMMetadataRef scope = file; - - Type *elem = base_type(bt->BitSet.elem); - if (elem->kind == Type_Enum) { - element_count = cast(unsigned)elem->Enum.fields.count; - elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count); - for_array(i, elem->Enum.fields) { - Entity *f = elem->Enum.fields[i]; - GB_ASSERT(f->kind == Entity_Constant); - i64 val = exact_value_to_i64(f->Constant.value); - String name = f->token.string; - u64 offset_in_bits = cast(u64)(val - bt->BitSet.lower); - elements[i] = LLVMDIBuilderCreateBitFieldMemberType( - m->debug_builder, - scope, - cast(char const *)name.text, name.len, - file, line_number, - 1, - offset_in_bits, - 0, - LLVMDIFlagZero, - bit_set_field_type - ); - } - } else { - - char name[32] = {}; - - GB_ASSERT(is_type_integer(elem)); - i64 count = bt->BitSet.upper - bt->BitSet.lower + 1; - GB_ASSERT(0 <= count); - - element_count = cast(unsigned)count; - elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count); - for (unsigned i = 0; i < element_count; i++) { - u64 offset_in_bits = i; - i64 val = bt->BitSet.lower + cast(i64)i; - gb_snprintf(name, gb_count_of(name), "%lld", cast(long long)val); - elements[i] = LLVMDIBuilderCreateBitFieldMemberType( - m->debug_builder, - scope, - name, gb_strlen(name), - file, line_number, - 1, - offset_in_bits, - 0, - LLVMDIFlagZero, - bit_set_field_type - ); - } - } - } - } - - - LLVMMetadataRef final_metadata = nullptr; - if (is_union) { - final_metadata = LLVMDIBuilderCreateUnionType( - m->debug_builder, - parent_scope, - cast(char const *)name.text, cast(size_t)name.len, - file, line_number, - size_in_bits, align_in_bits, - flags, - elements, element_count, - runtime_lang, - unique_id, unique_id_len - ); - } else { - final_metadata = LLVMDIBuilderCreateStructType( - m->debug_builder, - parent_scope, - cast(char const *)name.text, cast(size_t)name.len, - file, line_number, - size_in_bits, align_in_bits, - flags, - derived_from, - elements, element_count, - runtime_lang, - vtable_holder, - unique_id, unique_id_len - ); - } - - LLVMMetadataReplaceAllUsesWith(idt.metadata, final_metadata); - lb_set_llvm_metadata(m, idt.type, final_metadata); - } break; - default: - GB_PANIC("invalid incomplete debug type"); - break; - } - } - array_clear(&m->debug_incomplete_types); -} - - -void lb_add_entity(lbModule *m, Entity *e, lbValue val) { - if (e != nullptr) { - map_set(&m->values, hash_entity(e), val); - } -} -void lb_add_member(lbModule *m, String const &name, lbValue val) { - if (name.len > 0) { - string_map_set(&m->members, name, val); - } -} -void lb_add_member(lbModule *m, StringHashKey const &key, lbValue val) { - string_map_set(&m->members, key, val); -} -void lb_add_procedure_value(lbModule *m, lbProcedure *p) { - if (p->entity != nullptr) { - map_set(&m->procedure_values, hash_pointer(p->value), p->entity); - } - string_map_set(&m->procedures, p->name, p); -} - - -LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) { - LLVMTypeRef src = LLVMTypeOf(val); - if (src == dst) { - return val; - } - if (LLVMIsNull(val)) { - return LLVMConstNull(dst); - } - - GB_ASSERT(LLVMSizeOf(dst) == LLVMSizeOf(src)); - LLVMTypeKind kind = LLVMGetTypeKind(dst); - switch (kind) { - case LLVMPointerTypeKind: - return LLVMConstPointerCast(val, dst); - case LLVMStructTypeKind: - return LLVMConstBitCast(val, dst); - default: - GB_PANIC("Unhandled const cast %s to %s", LLVMPrintTypeToString(src), LLVMPrintTypeToString(dst)); - } - - return val; -} -LLVMValueRef llvm_const_named_struct(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) { - unsigned value_count = cast(unsigned)value_count_; - unsigned elem_count = LLVMCountStructElementTypes(t); - GB_ASSERT(value_count == elem_count); - for (unsigned i = 0; i < elem_count; i++) { - LLVMTypeRef elem_type = LLVMStructGetTypeAtIndex(t, i); - values[i] = llvm_const_cast(values[i], elem_type); - } - return LLVMConstNamedStruct(t, values, value_count); -} - -LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) { - unsigned value_count = cast(unsigned)value_count_; - for (unsigned i = 0; i < value_count; i++) { - values[i] = llvm_const_cast(values[i], elem_type); - } - return LLVMConstArray(elem_type, values, value_count); -} - - -lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) { - if (false && lb_is_const(str_elem) && lb_is_const(str_len)) { - LLVMValueRef values[2] = { - str_elem.value, - str_len.value, - }; - lbValue res = {}; - res.type = t_string; - res.value = llvm_const_named_struct(lb_type(p->module, t_string), values, gb_count_of(values)); - return res; - } else { - lbAddr res = lb_add_local_generated(p, t_string, false); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), str_elem); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), str_len); - return lb_addr_load(p, res); - } -} - -LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type) { - String s = make_string_c(name); - - // NOTE(2021-02-25, bill); All this attributes require a type associated with them - // and the current LLVM C API does not expose this functionality yet. - // It is better to ignore the attributes for the time being - if (s == "byval") { - // return nullptr; - } else if (s == "byref") { - return nullptr; - } else if (s == "preallocated") { - return nullptr; - } else if (s == "sret") { - // return nullptr; - } - - unsigned kind = LLVMGetEnumAttributeKindForName(name, s.len); - GB_ASSERT_MSG(kind != 0, "unknown attribute: %s", name); - return LLVMCreateEnumAttribute(ctx, kind, 0); -} - -LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value) { - String s = make_string_c(name); - - // NOTE(2021-02-25, bill); All this attributes require a type associated with them - // and the current LLVM C API does not expose this functionality yet. - // It is better to ignore the attributes for the time being - if (s == "byval") { - GB_PANIC("lb_create_enum_attribute_with_type should be used for %s", name); - } else if (s == "byref") { - GB_PANIC("lb_create_enum_attribute_with_type should be used for %s", name); - } else if (s == "preallocated") { - GB_PANIC("lb_create_enum_attribute_with_type should be used for %s", name); - } else if (s == "sret") { - GB_PANIC("lb_create_enum_attribute_with_type should be used for %s", name); - } - - unsigned kind = LLVMGetEnumAttributeKindForName(name, s.len); - GB_ASSERT_MSG(kind != 0, "unknown attribute: %s", name); - return LLVMCreateEnumAttribute(ctx, kind, value); -} - -void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value) { - LLVMAttributeRef attr = lb_create_enum_attribute(p->module->ctx, name, value); - GB_ASSERT(attr != nullptr); - LLVMAddAttributeAtIndex(p->value, cast(unsigned)index, attr); -} - -void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name) { - lb_add_proc_attribute_at_index(p, index, name, 0); -} - -void lb_add_attribute_to_proc(lbModule *m, LLVMValueRef proc_value, char const *name, u64 value=0) { - LLVMAddAttributeAtIndex(proc_value, LLVMAttributeIndex_FunctionIndex, lb_create_enum_attribute(m->ctx, name, value)); -} - - -void lb_ensure_abi_function_type(lbModule *m, lbProcedure *p) { - if (p->abi_function_type != nullptr) { - return; - } - auto hash = hash_type(p->type); - lbFunctionType **ft_found = map_get(&m->function_type_map, hash); - if (ft_found == nullptr) { - LLVMTypeRef llvm_proc_type = lb_type(p->module, p->type); - ft_found = map_get(&m->function_type_map, hash); - } - GB_ASSERT(ft_found != nullptr); - p->abi_function_type = *ft_found; - GB_ASSERT(p->abi_function_type != nullptr); -} - -lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) { - GB_ASSERT(entity != nullptr); - GB_ASSERT(entity->kind == Entity_Procedure); - if (!entity->Procedure.is_foreign) { - GB_ASSERT(entity->flags |= EntityFlag_ProcBodyChecked); - } - - String link_name = {}; - - if (ignore_body) { - lbModule *other_module = lb_pkg_module(m->gen, entity->pkg); - link_name = lb_get_entity_name(other_module, entity); - } else { - link_name = lb_get_entity_name(m, entity); - } - - { - StringHashKey key = string_hash_string(link_name); - lbValue *found = string_map_get(&m->members, key); - if (found) { - lb_add_entity(m, entity, *found); - return string_map_must_get(&m->procedures, key); - } - } - - - lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); - - p->module = m; - entity->code_gen_module = m; - entity->code_gen_procedure = p; - p->entity = entity; - p->name = link_name; - - DeclInfo *decl = entity->decl_info; - - ast_node(pl, ProcLit, decl->proc_lit); - Type *pt = base_type(entity->type); - GB_ASSERT(pt->kind == Type_Proc); - - p->type = entity->type; - p->type_expr = decl->type_expr; - p->body = pl->body; - p->inlining = pl->inlining; - p->is_foreign = entity->Procedure.is_foreign; - p->is_export = entity->Procedure.is_export; - p->is_entry_point = false; - - gbAllocator a = heap_allocator(); - p->children.allocator = a; - p->params.allocator = a; - p->defer_stmts.allocator = a; - p->blocks.allocator = a; - p->branch_blocks.allocator = a; - p->context_stack.allocator = a; - p->scope_stack.allocator = a; - - if (p->is_foreign) { - lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); - } - - char *c_link_name = alloc_cstring(permanent_allocator(), p->name); - LLVMTypeRef func_ptr_type = lb_type(m, p->type); - LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type); - - p->value = LLVMAddFunction(m->mod, c_link_name, func_type); - - lb_ensure_abi_function_type(m, p); - lb_add_function_type_attributes(p->value, p->abi_function_type, p->abi_function_type->calling_convention); - if (false) { - lbCallingConventionKind cc_kind = lbCallingConvention_C; - // TODO(bill): Clean up this logic - if (!is_arch_wasm()) { - cc_kind = lb_calling_convention_map[pt->Proc.calling_convention]; - } - LLVMSetFunctionCallConv(p->value, cc_kind); - } - - - if (pt->Proc.diverging) { - lb_add_attribute_to_proc(m, p->value, "noreturn"); - } - - if (pt->Proc.calling_convention == ProcCC_Naked) { - lb_add_attribute_to_proc(m, p->value, "naked"); - } - - switch (p->inlining) { - case ProcInlining_inline: - lb_add_attribute_to_proc(m, p->value, "alwaysinline"); - break; - case ProcInlining_no_inline: - lb_add_attribute_to_proc(m, p->value, "noinline"); - break; - } - - if (entity->flags & EntityFlag_Cold) { - lb_add_attribute_to_proc(m, p->value, "cold"); - } - - switch (entity->Procedure.optimization_mode) { - case ProcedureOptimizationMode_None: - lb_add_attribute_to_proc(m, p->value, "optnone"); - break; - case ProcedureOptimizationMode_Minimal: - lb_add_attribute_to_proc(m, p->value, "optnone"); - break; - case ProcedureOptimizationMode_Size: - lb_add_attribute_to_proc(m, p->value, "optsize"); - break; - case ProcedureOptimizationMode_Speed: - // TODO(bill): handle this correctly - lb_add_attribute_to_proc(m, p->value, "optsize"); - break; - } - - - - // lbCallingConventionKind cc_kind = lbCallingConvention_C; - // // TODO(bill): Clean up this logic - // if (build_context.metrics.os != TargetOs_js) { - // cc_kind = lb_calling_convention_map[pt->Proc.calling_convention]; - // } - // LLVMSetFunctionCallConv(p->value, cc_kind); - lbValue proc_value = {p->value, p->type}; - lb_add_entity(m, entity, proc_value); - lb_add_member(m, p->name, proc_value); - lb_add_procedure_value(m, p); - - if (p->is_export) { - LLVMSetLinkage(p->value, LLVMDLLExportLinkage); - LLVMSetDLLStorageClass(p->value, LLVMDLLExportStorageClass); - LLVMSetVisibility(p->value, LLVMDefaultVisibility); - - if (is_arch_wasm()) { - char const *export_name = alloc_cstring(permanent_allocator(), p->name); - LLVMAddTargetDependentFunctionAttr(p->value, "wasm-export-name", export_name); - } - } else if (!p->is_foreign) { - if (!USE_SEPARATE_MODULES) { - LLVMSetLinkage(p->value, LLVMInternalLinkage); - - // NOTE(bill): if a procedure is defined in package runtime and uses a custom link name, - // then it is very likely it is required by LLVM and thus cannot have internal linkage - if (entity->pkg != nullptr && entity->pkg->kind == Package_Runtime && p->body != nullptr) { - GB_ASSERT(entity->kind == Entity_Procedure); - if (entity->Procedure.link_name != "") { - LLVMSetLinkage(p->value, LLVMExternalLinkage); - } - } - } - } - - if (p->is_foreign) { - if (is_arch_wasm()) { - char const *import_name = alloc_cstring(permanent_allocator(), p->name); - char const *module_name = "env"; - if (entity->Procedure.foreign_library != nullptr) { - Entity *foreign_library = entity->Procedure.foreign_library; - GB_ASSERT(foreign_library->kind == Entity_LibraryName); - if (foreign_library->LibraryName.paths.count > 0) { - module_name = alloc_cstring(permanent_allocator(), foreign_library->LibraryName.paths[0]); - } - } - LLVMAddTargetDependentFunctionAttr(p->value, "wasm-import-name", import_name); - LLVMAddTargetDependentFunctionAttr(p->value, "wasm-import-module", module_name); - } - } - - // NOTE(bill): offset==0 is the return value - isize offset = 1; - if (pt->Proc.return_by_pointer) { - offset = 2; - } - - isize parameter_index = 0; - if (pt->Proc.param_count) { - TypeTuple *params = &pt->Proc.params->Tuple; - for (isize i = 0; i < pt->Proc.param_count; i++) { - Entity *e = params->variables[i]; - Type *original_type = e->type; - if (e->kind != Entity_Variable) continue; - - if (i+1 == params->variables.count && pt->Proc.c_vararg) { - continue; - } - - if (e->flags&EntityFlag_NoAlias) { - lb_add_proc_attribute_at_index(p, offset+parameter_index, "noalias"); - } - parameter_index += 1; - } - } - - if (ignore_body) { - p->body = nullptr; - LLVMSetLinkage(p->value, LLVMExternalLinkage); - } - - - if (m->debug_builder) { // Debug Information - Type *bt = base_type(p->type); - - unsigned line = cast(unsigned)entity->token.pos.line; - - LLVMMetadataRef scope = nullptr; - LLVMMetadataRef file = nullptr; - LLVMMetadataRef type = nullptr; - scope = p->module->debug_compile_unit; - type = lb_debug_type_internal_proc(m, bt); - - if (entity->file != nullptr) { - file = lb_get_llvm_metadata(m, entity->file); - scope = file; - } else if (entity->identifier != nullptr && entity->identifier->file != nullptr) { - file = lb_get_llvm_metadata(m, entity->identifier->file); - scope = file; - } else if (entity->scope != nullptr) { - file = lb_get_llvm_metadata(m, entity->scope->file); - scope = file; - } - GB_ASSERT_MSG(file != nullptr, "%.*s", LIT(entity->token.string)); - - // LLVMBool is_local_to_unit = !entity->Procedure.is_export; - LLVMBool is_local_to_unit = false; - LLVMBool is_definition = p->body != nullptr; - unsigned scope_line = line; - u32 flags = LLVMDIFlagStaticMember; - LLVMBool is_optimized = false; - if (bt->Proc.diverging) { - flags |= LLVMDIFlagNoReturn; - } - if (p->body == nullptr) { - flags |= LLVMDIFlagPrototyped; - is_optimized = false; - } - - if (p->body != nullptr) { - p->debug_info = LLVMDIBuilderCreateFunction(m->debug_builder, scope, - cast(char const *)entity->token.string.text, entity->token.string.len, - cast(char const *)p->name.text, p->name.len, - file, line, type, - is_local_to_unit, is_definition, - scope_line, cast(LLVMDIFlags)flags, is_optimized - ); - GB_ASSERT(p->debug_info != nullptr); - LLVMSetSubprogram(p->value, p->debug_info); - lb_set_llvm_metadata(m, p, p->debug_info); - } - } - - return p; -} - -lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type) { - { - lbValue *found = string_map_get(&m->members, link_name); - GB_ASSERT(found == nullptr); - } - - lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); - - p->module = m; - p->name = link_name; - - p->type = type; - p->type_expr = nullptr; - p->body = nullptr; - p->tags = 0; - p->inlining = ProcInlining_none; - p->is_foreign = false; - p->is_export = false; - p->is_entry_point = false; - - gbAllocator a = permanent_allocator(); - p->children.allocator = a; - p->params.allocator = a; - p->defer_stmts.allocator = a; - p->blocks.allocator = a; - p->branch_blocks.allocator = a; - p->context_stack.allocator = a; - - - char *c_link_name = alloc_cstring(permanent_allocator(), p->name); - LLVMTypeRef func_ptr_type = lb_type(m, p->type); - LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type); - - p->value = LLVMAddFunction(m->mod, c_link_name, func_type); - - Type *pt = p->type; - lbCallingConventionKind cc_kind = lbCallingConvention_C; - // TODO(bill): Clean up this logic - if (!is_arch_wasm()) { - cc_kind = lb_calling_convention_map[pt->Proc.calling_convention]; - } - LLVMSetFunctionCallConv(p->value, cc_kind); - lbValue proc_value = {p->value, p->type}; - lb_add_member(m, p->name, proc_value); - lb_add_procedure_value(m, p); - - - // NOTE(bill): offset==0 is the return value - isize offset = 1; - if (pt->Proc.return_by_pointer) { - lb_add_proc_attribute_at_index(p, 1, "sret"); - lb_add_proc_attribute_at_index(p, 1, "noalias"); - offset = 2; - } - - isize parameter_index = 0; - if (pt->Proc.calling_convention == ProcCC_Odin) { - lb_add_proc_attribute_at_index(p, offset+parameter_index, "noalias"); - lb_add_proc_attribute_at_index(p, offset+parameter_index, "nonnull"); - lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture"); - } - - return p; -} - - -lbValue lb_value_param(lbProcedure *p, Entity *e, Type *abi_type, i32 index, lbParamPasskind *kind_) { - lbParamPasskind kind = lbParamPass_Value; - - if (e != nullptr && !are_types_identical(abi_type, e->type)) { - if (is_type_pointer(abi_type)) { - GB_ASSERT(e->kind == Entity_Variable); - Type *av = core_type(type_deref(abi_type)); - if (are_types_identical(av, core_type(e->type))) { - kind = lbParamPass_Pointer; - if (e->flags&EntityFlag_Value) { - kind = lbParamPass_ConstRef; - } - } else { - kind = lbParamPass_BitCast; - } - } else if (is_type_integer(abi_type)) { - kind = lbParamPass_Integer; - } else if (abi_type == t_llvm_bool) { - kind = lbParamPass_Value; - } else if (is_type_boolean(abi_type)) { - kind = lbParamPass_Integer; - } else if (is_type_simd_vector(abi_type)) { - kind = lbParamPass_BitCast; - } else if (is_type_float(abi_type)) { - kind = lbParamPass_BitCast; - } else if (is_type_tuple(abi_type)) { - kind = lbParamPass_Tuple; - } else if (is_type_proc(abi_type)) { - kind = lbParamPass_Value; - } else { - GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type)); - } - } - - if (kind_) *kind_ = kind; - lbValue res = {}; - res.value = LLVMGetParam(p->value, cast(unsigned)index); - res.type = abi_type; - return res; -} - -Type *struct_type_from_systemv_distribute_struct_fields(Type *abi_type) { - GB_ASSERT(is_type_tuple(abi_type)); - Type *final_type = alloc_type_struct(); - final_type->Struct.fields = abi_type->Tuple.variables; - return final_type; -} - - -void lb_start_block(lbProcedure *p, lbBlock *b) { - GB_ASSERT(b != nullptr); - if (!b->appended) { - b->appended = true; - LLVMAppendExistingBasicBlock(p->value, b->block); - } - LLVMPositionBuilderAtEnd(p->builder, b->block); - p->curr_block = b; -} - -LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) { - LLVMContextRef ctx = p->module->ctx; - LLVMTypeRef src_type = LLVMTypeOf(val); - - if (src_type == dst_type) { - return val; - } - - i64 src_size = lb_sizeof(src_type); - i64 dst_size = lb_sizeof(dst_type); - i64 src_align = lb_alignof(src_type); - i64 dst_align = lb_alignof(dst_type); - if (LLVMIsALoadInst(val)) { - src_align = gb_min(src_align, LLVMGetAlignment(val)); - } - - LLVMTypeKind src_kind = LLVMGetTypeKind(src_type); - LLVMTypeKind dst_kind = LLVMGetTypeKind(dst_type); - - if (dst_type == LLVMInt1TypeInContext(ctx)) { - GB_ASSERT(lb_is_type_kind(src_type, LLVMIntegerTypeKind)); - return LLVMBuildICmp(p->builder, LLVMIntNE, val, LLVMConstNull(src_type), ""); - } else if (src_type == LLVMInt1TypeInContext(ctx)) { - GB_ASSERT(lb_is_type_kind(src_type, LLVMIntegerTypeKind)); - return LLVMBuildZExtOrBitCast(p->builder, val, dst_type, ""); - } - - if (src_size != dst_size) { - if ((lb_is_type_kind(src_type, LLVMVectorTypeKind) ^ lb_is_type_kind(dst_type, LLVMVectorTypeKind))) { - // Okay - } else { - goto general_end; - } - } - - - if (src_kind == dst_kind) { - if (src_kind == LLVMPointerTypeKind) { - return LLVMBuildPointerCast(p->builder, val, dst_type, ""); - } else if (src_kind == LLVMArrayTypeKind) { - // ignore - } else if (src_kind != LLVMStructTypeKind) { - return LLVMBuildBitCast(p->builder, val, dst_type, ""); - } - } else { - if (src_kind == LLVMPointerTypeKind && dst_kind == LLVMIntegerTypeKind) { - return LLVMBuildPtrToInt(p->builder, val, dst_type, ""); - } else if (src_kind == LLVMIntegerTypeKind && dst_kind == LLVMPointerTypeKind) { - return LLVMBuildIntToPtr(p->builder, val, dst_type, ""); - } - } - -general_end:; - // make the alignment big if necessary - if (LLVMIsALoadInst(val) && src_align < dst_align) { - LLVMValueRef val_ptr = LLVMGetOperand(val, 0); - if (LLVMGetInstructionOpcode(val_ptr) == LLVMAlloca) { - src_align = gb_max(LLVMGetAlignment(val_ptr), dst_align); - LLVMSetAlignment(val_ptr, cast(unsigned)src_align); - } - } - - src_size = align_formula(src_size, src_align); - dst_size = align_formula(dst_size, dst_align); - - if (LLVMIsALoadInst(val) && (src_size >= dst_size && src_align >= dst_align)) { - LLVMValueRef val_ptr = LLVMGetOperand(val, 0); - val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), ""); - LLVMValueRef loaded_val = LLVMBuildLoad(p->builder, val_ptr, ""); - - // LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align)); - - return loaded_val; - } else { - GB_ASSERT(p->decl_block != p->curr_block); - LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); - - LLVMValueRef ptr = LLVMBuildAlloca(p->builder, dst_type, ""); - LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); - i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type)); - max_align = gb_max(max_align, 4); - LLVMSetAlignment(ptr, cast(unsigned)max_align); - - LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), ""); - LLVMBuildStore(p->builder, val, nptr); - - return LLVMBuildLoad(p->builder, ptr, ""); - } -} - - -void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token) { - if (p->debug_info == nullptr) { - return; - } - if (type == nullptr) { - return; - } - if (type == t_invalid) { - return; - } - if (p->body == nullptr) { - return; - } - - lbModule *m = p->module; - String const &name = token.string; - if (name == "" || name == "_") { - return; - } - - if (lb_get_llvm_metadata(m, ptr) != nullptr) { - // Already been set - return; - } - - - AstFile *file = p->body->file; - - LLVMMetadataRef llvm_scope = lb_get_current_debug_scope(p); - LLVMMetadataRef llvm_file = lb_get_llvm_metadata(m, file); - GB_ASSERT(llvm_scope != nullptr); - if (llvm_file == nullptr) { - llvm_file = LLVMDIScopeGetFile(llvm_scope); - } - - if (llvm_file == nullptr) { - return; - } - - unsigned alignment_in_bits = cast(unsigned)(8*type_align_of(type)); - - LLVMDIFlags flags = LLVMDIFlagZero; - LLVMBool always_preserve = build_context.optimization_level == 0; - - LLVMMetadataRef debug_type = lb_debug_type(m, type); - - LLVMMetadataRef var_info = LLVMDIBuilderCreateAutoVariable( - m->debug_builder, llvm_scope, - cast(char const *)name.text, cast(size_t)name.len, - llvm_file, token.pos.line, - debug_type, - always_preserve, flags, alignment_in_bits - ); - - LLVMValueRef storage = ptr; - LLVMValueRef instr = ptr; - LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos); - LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); - lb_set_llvm_metadata(m, ptr, llvm_expr); - LLVMDIBuilderInsertDeclareBefore(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, instr); -} - -void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) { - if (!p->debug_info || !p->body) { - return; - } - LLVMMetadataRef loc = LLVMGetCurrentDebugLocation2(p->builder); - if (!loc) { - return; - } - TokenPos pos = {}; - - pos.file_id = p->body->file ? p->body->file->id : 0; - pos.line = LLVMDILocationGetLine(loc); - pos.column = LLVMDILocationGetColumn(loc); - - Token token = {}; - token.kind = Token_context; - token.string = str_lit("context"); - token.pos = pos; - - lb_add_debug_local_variable(p, ctx.addr.value, t_context, token); -} - - -void lb_begin_procedure_body(lbProcedure *p) { - DeclInfo *decl = decl_info_of_entity(p->entity); - if (decl != nullptr) { - for_array(i, decl->labels) { - BlockLabel bl = decl->labels[i]; - lbBranchBlocks bb = {bl.label, nullptr, nullptr}; - array_add(&p->branch_blocks, bb); - } - } - - p->builder = LLVMCreateBuilderInContext(p->module->ctx); - - p->decl_block = lb_create_block(p, "decls", true); - p->entry_block = lb_create_block(p, "entry", true); - lb_start_block(p, p->entry_block); - - GB_ASSERT(p->type != nullptr); - - lb_ensure_abi_function_type(p->module, p); - { - lbFunctionType *ft = p->abi_function_type; - - unsigned param_offset = 0; - - lbValue return_ptr_value = {}; - if (ft->ret.kind == lbArg_Indirect) { - // NOTE(bill): this must be parameter 0 - - String name = str_lit("agg.result"); - - Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); - Entity *e = alloc_entity_param(nullptr, make_token_ident(name), ptr_type, false, false); - e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; - - return_ptr_value.value = LLVMGetParam(p->value, 0); - LLVMSetValueName2(return_ptr_value.value, cast(char const *)name.text, name.len); - return_ptr_value.type = ptr_type; - p->return_ptr = lb_addr(return_ptr_value); - - lb_add_entity(p->module, e, return_ptr_value); - - param_offset += 1; - } - - if (p->type->Proc.params != nullptr) { - TypeTuple *params = &p->type->Proc.params->Tuple; - - unsigned param_index = 0; - for_array(i, params->variables) { - Entity *e = params->variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - - lbArgType *arg_type = &ft->args[param_index]; - if (arg_type->kind == lbArg_Ignore) { - continue; - } else if (arg_type->kind == lbArg_Direct) { - lbParamPasskind kind = lbParamPass_Value; - LLVMTypeRef param_type = lb_type(p->module, e->type); - if (param_type != arg_type->type) { - kind = lbParamPass_BitCast; - } - LLVMValueRef value = LLVMGetParam(p->value, param_offset+param_index); - - value = OdinLLVMBuildTransmute(p, value, param_type); - - lbValue param = {}; - param.value = value; - param.type = e->type; - array_add(&p->params, param); - - if (e->token.string.len != 0) { - lbAddr l = lb_add_local(p, e->type, e, false, param_index); - lb_addr_store(p, l, param); - } - - param_index += 1; - } else if (arg_type->kind == lbArg_Indirect) { - LLVMValueRef value_ptr = LLVMGetParam(p->value, param_offset+param_index); - LLVMValueRef value = LLVMBuildLoad(p->builder, value_ptr, ""); - - lbValue param = {}; - param.value = value; - param.type = e->type; - array_add(&p->params, param); - - lbValue ptr = {}; - ptr.value = value_ptr; - ptr.type = alloc_type_pointer(e->type); - - lb_add_entity(p->module, e, ptr); - param_index += 1; - } - } - } - - if (p->type->Proc.has_named_results) { - GB_ASSERT(p->type->Proc.result_count > 0); - TypeTuple *results = &p->type->Proc.results->Tuple; - - for_array(i, results->variables) { - Entity *e = results->variables[i]; - GB_ASSERT(e->kind == Entity_Variable); - - if (e->token.string != "") { - GB_ASSERT(!is_blank_ident(e->token)); - - lbAddr res = {}; - if (return_ptr_value.value) { - lbValue ptr = return_ptr_value; - if (results->variables.count != 1) { - ptr = lb_emit_struct_ep(p, ptr, cast(i32)i); - } - - res = lb_addr(ptr); - lb_add_entity(p->module, e, ptr); - } else { - res = lb_add_local(p, e->type, e); - } - - if (e->Variable.param_value.kind != ParameterValue_Invalid) { - lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); - lb_addr_store(p, res, c); - } - } - } - } - } - if (p->type->Proc.calling_convention == ProcCC_Odin) { - lb_push_context_onto_stack_from_implicit_parameter(p); - } - - lb_start_block(p, p->entry_block); - - if (p->debug_info != nullptr) { - TokenPos pos = {}; - if (p->body != nullptr) { - pos = ast_token(p->body).pos; - } else if (p->type_expr != nullptr) { - pos = ast_token(p->type_expr).pos; - } else if (p->entity != nullptr) { - pos = p->entity->token.pos; - } - if (pos.file_id != 0) { - LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos)); - } - - if (p->context_stack.count != 0) { - lb_add_debug_context_variable(p, lb_find_or_generate_context_ptr(p)); - } - - } - -} - -void lb_end_procedure_body(lbProcedure *p) { - LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); - LLVMBuildBr(p->builder, p->entry_block->block); - LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); - - LLVMValueRef instr = nullptr; - - // Make sure there is a "ret void" at the end of a procedure with no return type - if (p->type->Proc.result_count == 0) { - instr = LLVMGetLastInstruction(p->curr_block->block); - if (!lb_is_instr_terminating(instr)) { - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); - LLVMBuildRetVoid(p->builder); - } - } - - LLVMBasicBlockRef first_block = LLVMGetFirstBasicBlock(p->value); - LLVMBasicBlockRef block = nullptr; - - // Make sure every block terminates, and if not, make it unreachable - for (block = first_block; block != nullptr; block = LLVMGetNextBasicBlock(block)) { - instr = LLVMGetLastInstruction(block); - if (instr == nullptr || !lb_is_instr_terminating(instr)) { - LLVMPositionBuilderAtEnd(p->builder, block); - LLVMBuildUnreachable(p->builder); - } - } - - p->curr_block = nullptr; - p->state_flags = 0; -} -void lb_end_procedure(lbProcedure *p) { - LLVMDisposeBuilder(p->builder); -} - -void lb_add_edge(lbBlock *from, lbBlock *to) { - LLVMValueRef instr = LLVMGetLastInstruction(from->block); - if (instr == nullptr || !LLVMIsATerminatorInst(instr)) { - array_add(&from->succs, to); - array_add(&to->preds, from); - } -} - - -lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append) { - lbBlock *b = gb_alloc_item(permanent_allocator(), lbBlock); - b->block = LLVMCreateBasicBlockInContext(p->module->ctx, name); - b->appended = false; - if (append) { - b->appended = true; - LLVMAppendExistingBasicBlock(p->value, b->block); - } - - b->scope = p->curr_scope; - b->scope_index = p->scope_index; - - b->preds.allocator = heap_allocator(); - b->succs.allocator = heap_allocator(); - - array_add(&p->blocks, b); - - return b; -} - -void lb_emit_jump(lbProcedure *p, lbBlock *target_block) { - if (p->curr_block == nullptr) { - return; - } - LLVMValueRef last_instr = LLVMGetLastInstruction(p->curr_block->block); - if (last_instr != nullptr && LLVMIsATerminatorInst(last_instr)) { - return; - } - - lb_add_edge(p->curr_block, target_block); - LLVMBuildBr(p->builder, target_block->block); - p->curr_block = nullptr; -} - -void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *false_block) { - lbBlock *b = p->curr_block; - if (b == nullptr) { - return; - } - LLVMValueRef last_instr = LLVMGetLastInstruction(p->curr_block->block); - if (last_instr != nullptr && LLVMIsATerminatorInst(last_instr)) { - return; - } - - lb_add_edge(b, true_block); - lb_add_edge(b, false_block); - - LLVMValueRef cv = cond.value; - cv = LLVMBuildTruncOrBitCast(p->builder, cv, lb_type(p->module, t_llvm_bool), ""); - LLVMBuildCondBr(p->builder, cv, true_block->block, false_block->block); -} - -bool lb_is_expr_untyped_const(Ast *expr) { - auto const &tv = type_and_value_of_expr(expr); - if (is_type_untyped(tv.type)) { - return tv.value.kind != ExactValue_Invalid; - } - return false; -} - -lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t) { - GB_ASSERT(is_type_typed(t)); - auto const &tv = type_and_value_of_expr(expr); - return lb_const_value(m, t, tv.value); -} - -lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block) { - GB_ASSERT(cond != nullptr); - GB_ASSERT(true_block != nullptr); - GB_ASSERT(false_block != nullptr); - - switch (cond->kind) { - case_ast_node(pe, ParenExpr, cond); - return lb_build_cond(p, pe->expr, true_block, false_block); - case_end; - - case_ast_node(ue, UnaryExpr, cond); - if (ue->op.kind == Token_Not) { - return lb_build_cond(p, ue->expr, false_block, true_block); - } - case_end; - - case_ast_node(be, BinaryExpr, cond); - if (be->op.kind == Token_CmpAnd) { - lbBlock *block = lb_create_block(p, "cmp.and"); - lb_build_cond(p, be->left, block, false_block); - lb_start_block(p, block); - return lb_build_cond(p, be->right, true_block, false_block); - } else if (be->op.kind == Token_CmpOr) { - lbBlock *block = lb_create_block(p, "cmp.or"); - lb_build_cond(p, be->left, true_block, block); - lb_start_block(p, block); - return lb_build_cond(p, be->right, true_block, false_block); - } - case_end; - } - - lbValue v = {}; - if (lb_is_expr_untyped_const(cond)) { - v = lb_expr_untyped_const_to_typed(p->module, cond, t_llvm_bool); - } else { - v = lb_build_expr(p, cond); - } - - v = lb_emit_conv(p, v, t_llvm_bool); - - lb_emit_if(p, v, true_block, false_block); - - return v; -} - -void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment) { - bool is_inlinable = false; - - i64 const_len = 0; - if (LLVMIsConstant(len)) { - const_len = cast(i64)LLVMConstIntGetSExtValue(len); - // TODO(bill): Determine when it is better to do the `*.inline` versions - if (const_len <= 4*build_context.word_size) { - is_inlinable = true; - } - } - - char const *name = "llvm.memset"; - if (is_inlinable) { - name = "llvm.memset.inline"; - } - - LLVMTypeRef types[2] = { - lb_type(p->module, t_rawptr), - lb_type(p->module, t_int) - }; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[4] = {}; - args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], ""); - args[1] = LLVMConstInt(LLVMInt8TypeInContext(p->module->ctx), 0, false); - args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, ""); - args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, false); // is_volatile parameter - - LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); -} - -void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment) { - LLVMTypeRef llvm_type = lb_type(p->module, type); - - LLVMTypeKind kind = LLVMGetTypeKind(llvm_type); - - switch (kind) { - case LLVMStructTypeKind: - case LLVMArrayTypeKind: - { - // NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too - i32 sz = cast(i32)type_size_of(type); - lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment); - } - break; - default: - LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr); - break; - } -} - -lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 param_index, bool force_no_init) { - GB_ASSERT(p->decl_block != p->curr_block); - LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); - - char const *name = ""; - if (e != nullptr) { - // name = alloc_cstring(permanent_allocator(), e->token.string); - } - - LLVMTypeRef llvm_type = lb_type(p->module, type); - LLVMValueRef ptr = LLVMBuildAlloca(p->builder, llvm_type, name); - - // unsigned alignment = 16; // TODO(bill): Make this configurable - unsigned alignment = cast(unsigned)lb_alignof(llvm_type); - LLVMSetAlignment(ptr, alignment); - - LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); - - - if (!zero_init && !force_no_init) { - // If there is any padding of any kind, just zero init regardless of zero_init parameter - LLVMTypeKind kind = LLVMGetTypeKind(llvm_type); - if (kind == LLVMStructTypeKind) { - i64 sz = type_size_of(type); - if (type_size_of_struct_pretend_is_packed(type) != sz) { - zero_init = true; - } - } else if (kind == LLVMArrayTypeKind) { - zero_init = true; - } - } - - if (zero_init) { - lb_mem_zero_ptr(p, ptr, type, alignment); - } - - lbValue val = {}; - val.value = ptr; - val.type = alloc_type_pointer(type); - - if (e != nullptr) { - lb_add_entity(p->module, e, val); - lb_add_debug_local_variable(p, ptr, type, e->token); - } - - return lb_addr(val); -} - -lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init) { - return lb_add_local(p, type, nullptr, zero_init); -} - -lbAddr lb_add_local_generated_temp(lbProcedure *p, Type *type, i64 min_alignment) { - lbAddr res = lb_add_local(p, type, nullptr, false, 0, true); - lb_try_update_alignment(res.addr, cast(unsigned)min_alignment); - return res; -} - - -void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) { - GB_ASSERT(pd->body != nullptr); - lbModule *m = p->module; - auto *min_dep_set = &m->info->minimum_dependency_set; - - if (ptr_set_exists(min_dep_set, e) == false) { - // NOTE(bill): Nothing depends upon it so doesn't need to be built - return; - } - - // NOTE(bill): Generate a new name - // parent.name-guid - String original_name = e->token.string; - String pd_name = original_name; - if (e->Procedure.link_name.len > 0) { - pd_name = e->Procedure.link_name; - } - - - isize name_len = p->name.len + 1 + pd_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); - - i32 guid = cast(i32)p->children.count; - name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%d", LIT(p->name), LIT(pd_name), guid); - String name = make_string(cast(u8 *)name_text, name_len-1); - - e->Procedure.link_name = name; - - lbProcedure *nested_proc = lb_create_procedure(p->module, e); - e->code_gen_procedure = nested_proc; - - lbValue value = {}; - value.value = nested_proc->value; - value.type = nested_proc->type; - - lb_add_entity(m, e, value); - array_add(&p->children, nested_proc); - array_add(&m->procedures_to_generate, nested_proc); -} +#include "llvm_backend_general.cpp" +#include "llvm_backend_debug.cpp" +#include "llvm_backend_const.cpp" +#include "llvm_backend_type.cpp" +#include "llvm_backend_utility.cpp" +#include "llvm_backend_expr.cpp" +#include "llvm_backend_stmt.cpp" +#include "llvm_backend_proc.cpp" void lb_add_foreign_library_path(lbModule *m, Entity *e) { @@ -3790,2541 +54,6 @@ void lb_add_foreign_library_path(lbModule *m, Entity *e) { } } - - -void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) { - if (vd == nullptr || vd->is_mutable) { - return; - } - - auto *min_dep_set = &p->module->info->minimum_dependency_set; - - static i32 global_guid = 0; - - for_array(i, vd->names) { - Ast *ident = vd->names[i]; - GB_ASSERT(ident->kind == Ast_Ident); - Entity *e = entity_of_node(ident); - GB_ASSERT(e != nullptr); - if (e->kind != Entity_TypeName) { - continue; - } - - bool polymorphic_struct = false; - if (e->type != nullptr && e->kind == Entity_TypeName) { - Type *bt = base_type(e->type); - if (bt->kind == Type_Struct) { - polymorphic_struct = bt->Struct.is_polymorphic; - } - } - - if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { - continue; - } - - if (e->TypeName.ir_mangled_name.len != 0) { - // NOTE(bill): Already set - continue; - } - - lb_set_nested_type_name_ir_mangled_name(e, p); - } - - for_array(i, vd->names) { - Ast *ident = vd->names[i]; - GB_ASSERT(ident->kind == Ast_Ident); - Entity *e = entity_of_node(ident); - GB_ASSERT(e != nullptr); - if (e->kind != Entity_Procedure) { - continue; - } - GB_ASSERT (vd->values[i] != nullptr); - - Ast *value = unparen_expr(vd->values[i]); - if (value->kind != Ast_ProcLit) { - continue; // It's an alias - } - - CheckerInfo *info = p->module->info; - DeclInfo *decl = decl_info_of_entity(e); - ast_node(pl, ProcLit, decl->proc_lit); - if (pl->body != nullptr) { - auto *found = map_get(&info->gen_procs, hash_pointer(ident)); - if (found) { - auto procs = *found; - for_array(i, procs) { - Entity *e = procs[i]; - if (!ptr_set_exists(min_dep_set, e)) { - continue; - } - DeclInfo *d = decl_info_of_entity(e); - lb_build_nested_proc(p, &d->proc_lit->ProcLit, e); - } - } else { - lb_build_nested_proc(p, pl, e); - } - } else { - - // FFI - Foreign function interace - String original_name = e->token.string; - String name = original_name; - - if (e->Procedure.is_foreign) { - lb_add_foreign_library_path(p->module, e->Procedure.foreign_library); - } - - if (e->Procedure.link_name.len > 0) { - name = e->Procedure.link_name; - } - - lbValue *prev_value = string_map_get(&p->module->members, name); - if (prev_value != nullptr) { - // NOTE(bill): Don't do mutliple declarations in the IR - return; - } - - e->Procedure.link_name = name; - - lbProcedure *nested_proc = lb_create_procedure(p->module, e); - - lbValue value = {}; - value.value = nested_proc->value; - value.type = nested_proc->type; - - array_add(&p->module->procedures_to_generate, nested_proc); - array_add(&p->children, nested_proc); - string_map_set(&p->module->members, name, value); - } - } -} - - -void lb_build_stmt_list(lbProcedure *p, Slice<Ast *> const &stmts) { - for_array(i, stmts) { - Ast *stmt = stmts[i]; - switch (stmt->kind) { - case_ast_node(vd, ValueDecl, stmt); - lb_build_constant_value_decl(p, vd); - case_end; - case_ast_node(fb, ForeignBlockDecl, stmt); - ast_node(block, BlockStmt, fb->body); - lb_build_stmt_list(p, block->stmts); - case_end; - } - } - for_array(i, stmts) { - lb_build_stmt(p, stmts[i]); - } -} - -lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) { - GB_ASSERT(ident->kind == Ast_Ident); - Entity *e = entity_of_node(ident); - GB_ASSERT(e->kind == Entity_Label); - for_array(i, p->branch_blocks) { - lbBranchBlocks *b = &p->branch_blocks[i]; - if (b->label == e->Label.node) { - return *b; - } - } - - GB_PANIC("Unreachable"); - lbBranchBlocks empty = {}; - return empty; -} - - -lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) { - lbTargetList *tl = gb_alloc_item(permanent_allocator(), lbTargetList); - tl->prev = p->target_list; - tl->break_ = break_; - tl->continue_ = continue_; - tl->fallthrough_ = fallthrough_; - p->target_list = tl; - - if (label != nullptr) { // Set label blocks - GB_ASSERT(label->kind == Ast_Label); - - for_array(i, p->branch_blocks) { - lbBranchBlocks *b = &p->branch_blocks[i]; - GB_ASSERT(b->label != nullptr && label != nullptr); - GB_ASSERT(b->label->kind == Ast_Label); - if (b->label == label) { - b->break_ = break_; - b->continue_ = continue_; - return tl; - } - } - - GB_PANIC("Unreachable"); - } - - return tl; -} - -void lb_pop_target_list(lbProcedure *p) { - p->target_list = p->target_list->prev; -} - - - - -void lb_open_scope(lbProcedure *p, Scope *s) { - lbModule *m = p->module; - if (m->debug_builder) { - LLVMMetadataRef curr_metadata = lb_get_llvm_metadata(m, s); - if (s != nullptr && s->node != nullptr && curr_metadata == nullptr) { - Token token = ast_token(s->node); - unsigned line = cast(unsigned)token.pos.line; - unsigned column = cast(unsigned)token.pos.column; - - LLVMMetadataRef file = nullptr; - if (s->node->file != nullptr) { - file = lb_get_llvm_metadata(m, s->node->file); - } - LLVMMetadataRef scope = nullptr; - if (p->scope_stack.count > 0) { - scope = lb_get_llvm_metadata(m, p->scope_stack[p->scope_stack.count-1]); - } - if (scope == nullptr) { - scope = lb_get_llvm_metadata(m, p); - } - GB_ASSERT_MSG(scope != nullptr, "%.*s", LIT(p->name)); - - if (m->debug_builder) { - LLVMMetadataRef res = LLVMDIBuilderCreateLexicalBlock(m->debug_builder, scope, - file, line, column - ); - lb_set_llvm_metadata(m, s, res); - } - } - } - - p->scope_index += 1; - array_add(&p->scope_stack, s); - -} - -void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) { - lb_emit_defer_stmts(p, kind, block); - GB_ASSERT(p->scope_index > 0); - - // NOTE(bill): Remove `context`s made in that scope - while (p->context_stack.count > 0) { - lbContextData *ctx = &p->context_stack[p->context_stack.count-1]; - if (ctx->scope_index >= p->scope_index) { - array_pop(&p->context_stack); - } else { - break; - } - - } - - p->scope_index -= 1; - array_pop(&p->scope_stack); -} - -void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) { - TypeAndValue tv = type_and_value_of_expr(ws->cond); - GB_ASSERT(is_type_boolean(tv.type)); - GB_ASSERT(tv.value.kind == ExactValue_Bool); - if (tv.value.value_bool) { - lb_build_stmt_list(p, ws->body->BlockStmt.stmts); - } else if (ws->else_stmt) { - switch (ws->else_stmt->kind) { - case Ast_BlockStmt: - lb_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts); - break; - case Ast_WhenStmt: - lb_build_when_stmt(p, &ws->else_stmt->WhenStmt); - break; - default: - GB_PANIC("Invalid 'else' statement in 'when' statement"); - break; - } - } -} - - - -void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr, - lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { - lbModule *m = p->module; - - lbValue count = {}; - Type *expr_type = base_type(type_deref(expr.type)); - switch (expr_type->kind) { - case Type_Array: - count = lb_const_int(m, t_int, expr_type->Array.count); - break; - } - - lbValue val = {}; - lbValue idx = {}; - lbBlock *loop = nullptr; - lbBlock *done = nullptr; - lbBlock *body = nullptr; - - - lbAddr index = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1)); - - loop = lb_create_block(p, "for.index.loop"); - lb_emit_jump(p, loop); - lb_start_block(p, loop); - - lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int); - lb_addr_store(p, index, incr); - - body = lb_create_block(p, "for.index.body"); - done = lb_create_block(p, "for.index.done"); - if (count.value == nullptr) { - GB_ASSERT(count_ptr.value != nullptr); - count = lb_emit_load(p, count_ptr); - } - lbValue cond = lb_emit_comp(p, Token_Lt, incr, count); - lb_emit_if(p, cond, body, done); - lb_start_block(p, body); - - idx = lb_addr_load(p, index); - switch (expr_type->kind) { - case Type_Array: { - if (val_type != nullptr) { - val = lb_emit_load(p, lb_emit_array_ep(p, expr, idx)); - } - break; - } - case Type_EnumeratedArray: { - if (val_type != nullptr) { - val = lb_emit_load(p, lb_emit_array_ep(p, expr, idx)); - // NOTE(bill): Override the idx value for the enumeration - Type *index_type = expr_type->EnumeratedArray.index; - if (compare_exact_values(Token_NotEq, expr_type->EnumeratedArray.min_value, exact_value_u64(0))) { - idx = lb_emit_arith(p, Token_Add, idx, lb_const_value(m, index_type, expr_type->EnumeratedArray.min_value), index_type); - } - } - break; - } - case Type_Slice: { - if (val_type != nullptr) { - lbValue elem = lb_slice_elem(p, expr); - val = lb_emit_load(p, lb_emit_ptr_offset(p, elem, idx)); - } - break; - } - case Type_DynamicArray: { - if (val_type != nullptr) { - lbValue elem = lb_emit_struct_ep(p, expr, 0); - elem = lb_emit_load(p, elem); - val = lb_emit_load(p, lb_emit_ptr_offset(p, elem, idx)); - } - break; - } - case Type_Map: { - lbValue entries = lb_map_entries_ptr(p, expr); - lbValue elem = lb_emit_struct_ep(p, entries, 0); - elem = lb_emit_load(p, elem); - - lbValue entry = lb_emit_ptr_offset(p, elem, idx); - idx = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2)); - val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 3)); - - break; - } - case Type_Struct: { - GB_ASSERT(is_type_soa_struct(expr_type)); - break; - } - - default: - GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type)); - break; - } - - if (val_) *val_ = val; - if (idx_) *idx_ = idx; - if (loop_) *loop_ = loop; - if (done_) *done_ = done; -} - - -void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type, - lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { - lbModule *m = p->module; - lbValue count = lb_const_int(m, t_int, 0); - Type *expr_type = base_type(expr.type); - switch (expr_type->kind) { - case Type_Basic: - count = lb_string_len(p, expr); - break; - default: - GB_PANIC("Cannot do range_string of %s", type_to_string(expr_type)); - break; - } - - lbValue val = {}; - lbValue idx = {}; - lbBlock *loop = nullptr; - lbBlock *done = nullptr; - lbBlock *body = nullptr; - - - lbAddr offset_ = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); - - loop = lb_create_block(p, "for.string.loop"); - lb_emit_jump(p, loop); - lb_start_block(p, loop); - - - - body = lb_create_block(p, "for.string.body"); - done = lb_create_block(p, "for.string.done"); - - lbValue offset = lb_addr_load(p, offset_); - lbValue cond = lb_emit_comp(p, Token_Lt, offset, count); - lb_emit_if(p, cond, body, done); - lb_start_block(p, body); - - - lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset); - lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int); - auto args = array_make<lbValue>(permanent_allocator(), 1); - args[0] = lb_emit_string(p, str_elem, str_len); - lbValue rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args); - lbValue len = lb_emit_struct_ev(p, rune_and_len, 1); - lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int)); - - - idx = offset; - if (val_type != nullptr) { - val = lb_emit_struct_ev(p, rune_and_len, 0); - } - - if (val_) *val_ = val; - if (idx_) *idx_ = idx; - if (loop_) *loop_ = loop; - if (done_) *done_ = done; -} - - -void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, - AstRangeStmt *rs, Scope *scope) { - bool ADD_EXTRA_WRAPPING_CHECK = true; - - lbModule *m = p->module; - - lb_open_scope(p, scope); - - Type *val0_type = nullptr; - Type *val1_type = nullptr; - if (rs->vals.count > 0 && rs->vals[0] != nullptr && !is_blank_ident(rs->vals[0])) { - val0_type = type_of_expr(rs->vals[0]); - } - if (rs->vals.count > 1 && rs->vals[1] != nullptr && !is_blank_ident(rs->vals[1])) { - val1_type = type_of_expr(rs->vals[1]); - } - - if (val0_type != nullptr) { - Entity *e = entity_of_node(rs->vals[0]); - lb_add_local(p, e->type, e, true); - } - if (val1_type != nullptr) { - Entity *e = entity_of_node(rs->vals[1]); - lb_add_local(p, e->type, e, true); - } - - TokenKind op = Token_Lt; - switch (node->op.kind) { - case Token_Ellipsis: op = Token_LtEq; break; - case Token_RangeFull: op = Token_LtEq; break; - case Token_RangeHalf: op = Token_Lt; break; - default: GB_PANIC("Invalid interval operator"); break; - } - - lbValue lower = lb_build_expr(p, node->left); - lbValue upper = {}; // initialized each time in the loop - - lbAddr value = lb_add_local_generated(p, val0_type ? val0_type : lower.type, false); - lb_addr_store(p, value, lower); - - lbAddr index = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, index, lb_const_int(m, t_int, 0)); - - lbBlock *loop = lb_create_block(p, "for.interval.loop"); - lbBlock *body = lb_create_block(p, "for.interval.body"); - lbBlock *done = lb_create_block(p, "for.interval.done"); - - lb_emit_jump(p, loop); - lb_start_block(p, loop); - - upper = lb_build_expr(p, node->right); - lbValue curr_value = lb_addr_load(p, value); - lbValue cond = lb_emit_comp(p, op, curr_value, upper); - lb_emit_if(p, cond, body, done); - lb_start_block(p, body); - - lbValue val = lb_addr_load(p, value); - lbValue idx = lb_addr_load(p, index); - if (val0_type) lb_store_range_stmt_val(p, rs->vals[0], val); - if (val1_type) lb_store_range_stmt_val(p, rs->vals[1], idx); - - { - // NOTE: this check block will most likely be optimized out, and is here - // to make this code easier to read - lbBlock *check = nullptr; - lbBlock *post = lb_create_block(p, "for.interval.post"); - - lbBlock *continue_block = post; - - if (ADD_EXTRA_WRAPPING_CHECK && - op == Token_LtEq) { - check = lb_create_block(p, "for.interval.check"); - continue_block = check; - } - - lb_push_target_list(p, rs->label, done, continue_block, nullptr); - - lb_build_stmt(p, rs->body); - - lb_close_scope(p, lbDeferExit_Default, nullptr); - lb_pop_target_list(p); - - if (check != nullptr) { - lb_emit_jump(p, check); - lb_start_block(p, check); - - lbValue check_cond = lb_emit_comp(p, Token_NotEq, curr_value, upper); - lb_emit_if(p, check_cond, post, done); - } else { - lb_emit_jump(p, post); - } - - lb_start_block(p, post); - lb_emit_increment(p, value.addr); - lb_emit_increment(p, index.addr); - lb_emit_jump(p, loop); - } - - lb_start_block(p, done); -} - -void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { - lbModule *m = p->module; - - Type *t = enum_type; - GB_ASSERT(is_type_enum(t)); - Type *enum_ptr = alloc_type_pointer(t); - t = base_type(t); - Type *core_elem = core_type(t); - GB_ASSERT(t->kind == Type_Enum); - i64 enum_count = t->Enum.fields.count; - lbValue max_count = lb_const_int(m, t_int, enum_count); - - lbValue ti = lb_type_info(m, t); - lbValue variant = lb_emit_struct_ep(p, ti, 4); - lbValue eti_ptr = lb_emit_conv(p, variant, t_type_info_enum_ptr); - lbValue values = lb_emit_load(p, lb_emit_struct_ep(p, eti_ptr, 2)); - lbValue values_data = lb_slice_elem(p, values); - - lbAddr offset_ = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); - - lbBlock *loop = lb_create_block(p, "for.enum.loop"); - lb_emit_jump(p, loop); - lb_start_block(p, loop); - - lbBlock *body = lb_create_block(p, "for.enum.body"); - lbBlock *done = lb_create_block(p, "for.enum.done"); - - lbValue offset = lb_addr_load(p, offset_); - lbValue cond = lb_emit_comp(p, Token_Lt, offset, max_count); - lb_emit_if(p, cond, body, done); - lb_start_block(p, body); - - lbValue val_ptr = lb_emit_ptr_offset(p, values_data, offset); - lb_emit_increment(p, offset_.addr); - - lbValue val = {}; - if (val_type != nullptr) { - GB_ASSERT(are_types_identical(enum_type, val_type)); - - if (is_type_integer(core_elem)) { - lbValue i = lb_emit_load(p, lb_emit_conv(p, val_ptr, t_i64_ptr)); - val = lb_emit_conv(p, i, t); - } else { - GB_PANIC("TODO(bill): enum core type %s", type_to_string(core_elem)); - } - } - - if (val_) *val_ = val; - if (idx_) *idx_ = offset; - if (loop_) *loop_ = loop; - if (done_) *done_ = done; -} - -void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1_type, - lbValue *val0_, lbValue *val1_, lbBlock **loop_, lbBlock **done_) { - lbBlock *loop = lb_create_block(p, "for.tuple.loop"); - lb_emit_jump(p, loop); - lb_start_block(p, loop); - - lbBlock *body = lb_create_block(p, "for.tuple.body"); - lbBlock *done = lb_create_block(p, "for.tuple.done"); - - lbValue tuple_value = lb_build_expr(p, expr); - Type *tuple = tuple_value.type; - GB_ASSERT(tuple->kind == Type_Tuple); - i32 tuple_count = cast(i32)tuple->Tuple.variables.count; - i32 cond_index = tuple_count-1; - - lbValue cond = lb_emit_struct_ev(p, tuple_value, cond_index); - lb_emit_if(p, cond, body, done); - lb_start_block(p, body); - - - if (val0_) *val0_ = lb_emit_struct_ev(p, tuple_value, 0); - if (val1_) *val1_ = lb_emit_struct_ev(p, tuple_value, 1); - if (loop_) *loop_ = loop; - if (done_) *done_ = done; -} - -void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *scope) { - Ast *expr = unparen_expr(rs->expr); - TypeAndValue tav = type_and_value_of_expr(expr); - - lbBlock *loop = nullptr; - lbBlock *body = nullptr; - lbBlock *done = nullptr; - - lb_open_scope(p, scope); - - - Type *val_types[2] = {}; - if (rs->vals.count > 0 && rs->vals[0] != nullptr && !is_blank_ident(rs->vals[0])) { - val_types[0] = type_of_expr(rs->vals[0]); - } - if (rs->vals.count > 1 && rs->vals[1] != nullptr && !is_blank_ident(rs->vals[1])) { - val_types[1] = type_of_expr(rs->vals[1]); - } - - - - lbAddr array = lb_build_addr(p, expr); - if (is_type_pointer(type_deref(lb_addr_type(array)))) { - array = lb_addr(lb_addr_load(p, array)); - } - lbValue count = lb_soa_struct_len(p, lb_addr_load(p, array)); - - - lbAddr index = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, index, lb_const_int(p->module, t_int, cast(u64)-1)); - - loop = lb_create_block(p, "for.soa.loop"); - lb_emit_jump(p, loop); - lb_start_block(p, loop); - - lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int); - lb_addr_store(p, index, incr); - - body = lb_create_block(p, "for.soa.body"); - done = lb_create_block(p, "for.soa.done"); - - lbValue cond = lb_emit_comp(p, Token_Lt, incr, count); - lb_emit_if(p, cond, body, done); - lb_start_block(p, body); - - - if (val_types[0]) { - Entity *e = entity_of_node(rs->vals[0]); - if (e != nullptr) { - lbAddr soa_val = lb_addr_soa_variable(array.addr, lb_addr_load(p, index), nullptr); - map_set(&p->module->soa_values, hash_entity(e), soa_val); - } - } - if (val_types[1]) { - lb_store_range_stmt_val(p, rs->vals[1], lb_addr_load(p, index)); - } - - - lb_push_target_list(p, rs->label, done, loop, nullptr); - - lb_build_stmt(p, rs->body); - - lb_close_scope(p, lbDeferExit_Default, nullptr); - lb_pop_target_list(p); - lb_emit_jump(p, loop); - lb_start_block(p, done); - -} - -void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) { - Ast *expr = unparen_expr(rs->expr); - - if (is_ast_range(expr)) { - lb_build_range_interval(p, &expr->BinaryExpr, rs, scope); - return; - } - - Type *expr_type = type_of_expr(expr); - if (expr_type != nullptr) { - Type *et = base_type(type_deref(expr_type)); - if (is_type_soa_struct(et)) { - lb_build_range_stmt_struct_soa(p, rs, scope); - return; - } - } - - lb_open_scope(p, scope); - - Type *val0_type = nullptr; - Type *val1_type = nullptr; - if (rs->vals.count > 0 && rs->vals[0] != nullptr && !is_blank_ident(rs->vals[0])) { - val0_type = type_of_expr(rs->vals[0]); - } - if (rs->vals.count > 1 && rs->vals[1] != nullptr && !is_blank_ident(rs->vals[1])) { - val1_type = type_of_expr(rs->vals[1]); - } - - if (val0_type != nullptr) { - Entity *e = entity_of_node(rs->vals[0]); - lb_add_local(p, e->type, e, true); - } - if (val1_type != nullptr) { - Entity *e = entity_of_node(rs->vals[1]); - lb_add_local(p, e->type, e, true); - } - - lbValue val = {}; - lbValue key = {}; - lbBlock *loop = nullptr; - lbBlock *done = nullptr; - bool is_map = false; - TypeAndValue tav = type_and_value_of_expr(expr); - - if (tav.mode == Addressing_Type) { - lb_build_range_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done); - } else { - Type *expr_type = type_of_expr(expr); - Type *et = base_type(type_deref(expr_type)); - switch (et->kind) { - case Type_Map: { - is_map = true; - lbValue map = lb_build_addr_ptr(p, expr); - if (is_type_pointer(type_deref(map.type))) { - map = lb_emit_load(p, map); - } - lbValue entries_ptr = lb_map_entries_ptr(p, map); - lbValue count_ptr = lb_emit_struct_ep(p, entries_ptr, 1); - lb_build_range_indexed(p, map, val1_type, count_ptr, &val, &key, &loop, &done); - break; - } - case Type_Array: { - lbValue array = lb_build_addr_ptr(p, expr); - if (is_type_pointer(type_deref(array.type))) { - array = lb_emit_load(p, array); - } - lbAddr count_ptr = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count)); - lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done); - break; - } - case Type_EnumeratedArray: { - lbValue array = lb_build_addr_ptr(p, expr); - if (is_type_pointer(type_deref(array.type))) { - array = lb_emit_load(p, array); - } - lbAddr count_ptr = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->EnumeratedArray.count)); - lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done); - break; - } - case Type_DynamicArray: { - lbValue count_ptr = {}; - lbValue array = lb_build_addr_ptr(p, expr); - if (is_type_pointer(type_deref(array.type))) { - array = lb_emit_load(p, array); - } - count_ptr = lb_emit_struct_ep(p, array, 1); - lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done); - break; - } - case Type_Slice: { - lbValue count_ptr = {}; - lbValue slice = lb_build_expr(p, expr); - if (is_type_pointer(slice.type)) { - count_ptr = lb_emit_struct_ep(p, slice, 1); - slice = lb_emit_load(p, slice); - } else { - count_ptr = lb_add_local_generated(p, t_int, false).addr; - lb_emit_store(p, count_ptr, lb_slice_len(p, slice)); - } - lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done); - break; - } - case Type_Basic: { - lbValue string = lb_build_expr(p, expr); - if (is_type_pointer(string.type)) { - string = lb_emit_load(p, string); - } - if (is_type_untyped(expr_type)) { - lbAddr s = lb_add_local_generated(p, default_type(string.type), false); - lb_addr_store(p, s, string); - string = lb_addr_load(p, s); - } - Type *t = base_type(string.type); - GB_ASSERT(!is_type_cstring(t)); - lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done); - break; - } - case Type_Tuple: - lb_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done); - break; - default: - GB_PANIC("Cannot range over %s", type_to_string(expr_type)); - break; - } - } - - - if (is_map) { - if (val0_type) lb_store_range_stmt_val(p, rs->vals[0], key); - if (val1_type) lb_store_range_stmt_val(p, rs->vals[1], val); - } else { - if (val0_type) lb_store_range_stmt_val(p, rs->vals[0], val); - if (val1_type) lb_store_range_stmt_val(p, rs->vals[1], key); - } - - lb_push_target_list(p, rs->label, done, loop, nullptr); - - lb_build_stmt(p, rs->body); - - lb_close_scope(p, lbDeferExit_Default, nullptr); - lb_pop_target_list(p); - lb_emit_jump(p, loop); - lb_start_block(p, done); -} - -void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *scope) { - lbModule *m = p->module; - - lb_open_scope(p, scope); // Open scope here - - Type *val0_type = nullptr; - Type *val1_type = nullptr; - if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) { - val0_type = type_of_expr(rs->val0); - } - if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) { - val1_type = type_of_expr(rs->val1); - } - - if (val0_type != nullptr) { - Entity *e = entity_of_node(rs->val0); - lb_add_local(p, e->type, e, true); - } - if (val1_type != nullptr) { - Entity *e = entity_of_node(rs->val1); - lb_add_local(p, e->type, e, true); - } - - lbValue val = {}; - lbValue key = {}; - lbBlock *loop = nullptr; - lbBlock *done = nullptr; - Ast *expr = unparen_expr(rs->expr); - - TypeAndValue tav = type_and_value_of_expr(expr); - - if (is_ast_range(expr)) { - - lbAddr val0_addr = {}; - lbAddr val1_addr = {}; - if (val0_type) val0_addr = lb_build_addr(p, rs->val0); - if (val1_type) val1_addr = lb_build_addr(p, rs->val1); - - TokenKind op = expr->BinaryExpr.op.kind; - Ast *start_expr = expr->BinaryExpr.left; - Ast *end_expr = expr->BinaryExpr.right; - GB_ASSERT(start_expr->tav.mode == Addressing_Constant); - GB_ASSERT(end_expr->tav.mode == Addressing_Constant); - - ExactValue start = start_expr->tav.value; - ExactValue end = end_expr->tav.value; - if (op != Token_RangeHalf) { // .. [start, end] (or ..=) - ExactValue index = exact_value_i64(0); - for (ExactValue val = start; - compare_exact_values(Token_LtEq, val, end); - val = exact_value_increment_one(val), index = exact_value_increment_one(index)) { - - if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, val)); - if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, index)); - - lb_build_stmt(p, rs->body); - } - } else { // ..< [start, end) - ExactValue index = exact_value_i64(0); - for (ExactValue val = start; - compare_exact_values(Token_Lt, val, end); - val = exact_value_increment_one(val), index = exact_value_increment_one(index)) { - - if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, val)); - if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, index)); - - lb_build_stmt(p, rs->body); - } - } - - - } else if (tav.mode == Addressing_Type) { - GB_ASSERT(is_type_enum(type_deref(tav.type))); - Type *et = type_deref(tav.type); - Type *bet = base_type(et); - - lbAddr val0_addr = {}; - lbAddr val1_addr = {}; - if (val0_type) val0_addr = lb_build_addr(p, rs->val0); - if (val1_type) val1_addr = lb_build_addr(p, rs->val1); - - for_array(i, bet->Enum.fields) { - Entity *field = bet->Enum.fields[i]; - GB_ASSERT(field->kind == Entity_Constant); - if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, field->Constant.value)); - if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(i))); - - lb_build_stmt(p, rs->body); - } - } else { - lbAddr val0_addr = {}; - lbAddr val1_addr = {}; - if (val0_type) val0_addr = lb_build_addr(p, rs->val0); - if (val1_type) val1_addr = lb_build_addr(p, rs->val1); - - GB_ASSERT(expr->tav.mode == Addressing_Constant); - - Type *t = base_type(expr->tav.type); - - - switch (t->kind) { - case Type_Basic: - GB_ASSERT(is_type_string(t)); - { - ExactValue value = expr->tav.value; - GB_ASSERT(value.kind == ExactValue_String); - String str = value.value_string; - Rune codepoint = 0; - isize offset = 0; - do { - isize width = utf8_decode(str.text+offset, str.len-offset, &codepoint); - if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, exact_value_i64(codepoint))); - if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(offset))); - lb_build_stmt(p, rs->body); - - offset += width; - } while (offset < str.len); - } - break; - case Type_Array: - if (t->Array.count > 0) { - lbValue val = lb_build_expr(p, expr); - lbValue val_addr = lb_address_from_load_or_generate_local(p, val); - - for (i64 i = 0; i < t->Array.count; i++) { - if (val0_type) { - // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32 - lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i); - lb_addr_store(p, val0_addr, lb_emit_load(p, elem)); - } - if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(i))); - - lb_build_stmt(p, rs->body); - } - - } - break; - case Type_EnumeratedArray: - if (t->EnumeratedArray.count > 0) { - lbValue val = lb_build_expr(p, expr); - lbValue val_addr = lb_address_from_load_or_generate_local(p, val); - - for (i64 i = 0; i < t->EnumeratedArray.count; i++) { - if (val0_type) { - // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32 - lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i); - lb_addr_store(p, val0_addr, lb_emit_load(p, elem)); - } - if (val1_type) { - ExactValue idx = exact_value_add(exact_value_i64(i), t->EnumeratedArray.min_value); - lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, idx)); - } - - lb_build_stmt(p, rs->body); - } - - } - break; - default: - GB_PANIC("Invalid '#unroll for' type"); - break; - } - } - - - lb_close_scope(p, lbDeferExit_Default, nullptr); -} - -bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) { - if (ss->tag == nullptr) { - return false; - } - bool is_typeid = false; - TypeAndValue tv = type_and_value_of_expr(ss->tag); - if (is_type_integer(core_type(tv.type))) { - // okay - } else if (is_type_typeid(tv.type)) { - // okay - is_typeid = true; - } else { - return false; - } - - ast_node(body, BlockStmt, ss->body); - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - - if (cc->list.count == 0) { - if (default_found_) *default_found_ = true; - continue; - } - - for_array(j, cc->list) { - Ast *expr = unparen_expr(cc->list[j]); - if (is_ast_range(expr)) { - return false; - } - if (expr->tav.mode == Addressing_Type) { - GB_ASSERT(is_typeid); - continue; - } - tv = type_and_value_of_expr(expr); - if (tv.mode != Addressing_Constant) { - return false; - } - if (!is_type_integer(core_type(tv.type))) { - return false; - } - } - - } - - return true; -} - - -void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) { - lb_open_scope(p, scope); - - if (ss->init != nullptr) { - lb_build_stmt(p, ss->init); - } - lbValue tag = lb_const_bool(p->module, t_llvm_bool, true); - if (ss->tag != nullptr) { - tag = lb_build_expr(p, ss->tag); - } - lbBlock *done = lb_create_block(p, "switch.done"); // NOTE(bill): Append later - - ast_node(body, BlockStmt, ss->body); - - isize case_count = body->stmts.count; - Slice<Ast *> default_stmts = {}; - lbBlock *default_fall = nullptr; - lbBlock *default_block = nullptr; - lbBlock *fall = nullptr; - - bool default_found = false; - bool is_trivial = lb_switch_stmt_can_be_trivial_jump_table(ss, &default_found); - - auto body_blocks = slice_make<lbBlock *>(permanent_allocator(), body->stmts.count); - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - - body_blocks[i] = lb_create_block(p, cc->list.count == 0 ? "switch.default.body" : "switch.case.body"); - if (cc->list.count == 0) { - default_block = body_blocks[i]; - } - } - - - LLVMValueRef switch_instr = nullptr; - if (is_trivial) { - isize num_cases = 0; - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - num_cases += cc->list.count; - } - - LLVMBasicBlockRef end_block = done->block; - if (default_block) { - end_block = default_block->block; - } - - switch_instr = LLVMBuildSwitch(p->builder, tag.value, end_block, cast(unsigned)num_cases); - } - - - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - - lbBlock *body = body_blocks[i]; - fall = done; - if (i+1 < case_count) { - fall = body_blocks[i+1]; - } - - if (cc->list.count == 0) { - // default case - default_stmts = cc->stmts; - default_fall = fall; - if (switch_instr == nullptr) { - default_block = body; - } else { - GB_ASSERT(default_block != nullptr); - } - continue; - } - - lbBlock *next_cond = nullptr; - for_array(j, cc->list) { - Ast *expr = unparen_expr(cc->list[j]); - - if (switch_instr != nullptr) { - lbValue on_val = {}; - if (expr->tav.mode == Addressing_Type) { - GB_ASSERT(is_type_typeid(tag.type)); - lbValue e = lb_typeid(p->module, expr->tav.type); - on_val = lb_emit_conv(p, e, tag.type); - } else { - GB_ASSERT(expr->tav.mode == Addressing_Constant); - GB_ASSERT(!is_ast_range(expr)); - - on_val = lb_build_expr(p, expr); - on_val = lb_emit_conv(p, on_val, tag.type); - } - - GB_ASSERT(LLVMIsConstant(on_val.value)); - LLVMAddCase(switch_instr, on_val.value, body->block); - continue; - } - - next_cond = lb_create_block(p, "switch.case.next"); - - lbValue cond = {}; - if (is_ast_range(expr)) { - ast_node(ie, BinaryExpr, expr); - TokenKind op = Token_Invalid; - switch (ie->op.kind) { - case Token_Ellipsis: op = Token_LtEq; break; - case Token_RangeFull: op = Token_LtEq; break; - case Token_RangeHalf: op = Token_Lt; break; - default: GB_PANIC("Invalid interval operator"); break; - } - lbValue lhs = lb_build_expr(p, ie->left); - lbValue rhs = lb_build_expr(p, ie->right); - - lbValue cond_lhs = lb_emit_comp(p, Token_LtEq, lhs, tag); - lbValue cond_rhs = lb_emit_comp(p, op, tag, rhs); - cond = lb_emit_arith(p, Token_And, cond_lhs, cond_rhs, t_bool); - } else { - if (expr->tav.mode == Addressing_Type) { - GB_ASSERT(is_type_typeid(tag.type)); - lbValue e = lb_typeid(p->module, expr->tav.type); - e = lb_emit_conv(p, e, tag.type); - cond = lb_emit_comp(p, Token_CmpEq, tag, e); - } else { - cond = lb_emit_comp(p, Token_CmpEq, tag, lb_build_expr(p, expr)); - } - } - - lb_emit_if(p, cond, body, next_cond); - lb_start_block(p, next_cond); - } - lb_start_block(p, body); - - lb_push_target_list(p, ss->label, done, nullptr, fall); - lb_open_scope(p, body->scope); - lb_build_stmt_list(p, cc->stmts); - lb_close_scope(p, lbDeferExit_Default, body); - lb_pop_target_list(p); - - lb_emit_jump(p, done); - if (switch_instr == nullptr) { - lb_start_block(p, next_cond); - } - } - - if (default_block != nullptr) { - if (switch_instr == nullptr) { - lb_emit_jump(p, default_block); - } - lb_start_block(p, default_block); - - lb_push_target_list(p, ss->label, done, nullptr, default_fall); - lb_open_scope(p, default_block->scope); - lb_build_stmt_list(p, default_stmts); - lb_close_scope(p, lbDeferExit_Default, default_block); - lb_pop_target_list(p); - } - - lb_emit_jump(p, done); - lb_close_scope(p, lbDeferExit_Default, done); - lb_start_block(p, done); -} - -void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) { - Entity *e = implicit_entity_of_node(clause); - GB_ASSERT(e != nullptr); - if (e->flags & EntityFlag_Value) { - // by value - GB_ASSERT(are_types_identical(e->type, value.type)); - lbAddr x = lb_add_local(p, e->type, e, false); - lb_addr_store(p, x, value); - } else { - // by reference - GB_ASSERT(are_types_identical(e->type, type_deref(value.type))); - lb_add_entity(p->module, e, value); - } -} - -lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value) { - Entity *e = entity_of_node(stmt_val); - if (e == nullptr) { - return {}; - } - - if ((e->flags & EntityFlag_Value) == 0) { - if (LLVMIsALoadInst(value.value)) { - lbValue ptr = lb_address_from_load_or_generate_local(p, value); - lb_add_entity(p->module, e, ptr); - return lb_addr(ptr); - } - } - - // by value - lbAddr addr = lb_add_local(p, e->type, e, false); - lb_addr_store(p, addr, value); - return addr; -} - -void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, lbBlock *done) { - ast_node(cc, CaseClause, clause); - - lb_push_target_list(p, label, done, nullptr, nullptr); - lb_open_scope(p, body->scope); - lb_build_stmt_list(p, cc->stmts); - lb_close_scope(p, lbDeferExit_Default, body); - lb_pop_target_list(p); - - lb_emit_jump(p, done); -} - - - -void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) { - lbModule *m = p->module; - - ast_node(as, AssignStmt, ss->tag); - GB_ASSERT(as->lhs.count == 1); - GB_ASSERT(as->rhs.count == 1); - - lbValue parent = lb_build_expr(p, as->rhs[0]); - bool is_parent_ptr = is_type_pointer(parent.type); - - TypeSwitchKind switch_kind = check_valid_type_switch_type(parent.type); - GB_ASSERT(switch_kind != TypeSwitch_Invalid); - - lbValue parent_value = parent; - - lbValue parent_ptr = parent; - if (!is_parent_ptr) { - parent_ptr = lb_address_from_load_or_generate_local(p, parent); - } - - lbValue tag = {}; - lbValue union_data = {}; - if (switch_kind == TypeSwitch_Union) { - union_data = lb_emit_conv(p, parent_ptr, t_rawptr); - if (is_type_union_maybe_pointer(type_deref(parent_ptr.type))) { - tag = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, union_data), t_int); - } else { - lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent_ptr); - tag = lb_emit_load(p, tag_ptr); - } - } else if (switch_kind == TypeSwitch_Any) { - tag = lb_emit_load(p, lb_emit_struct_ep(p, parent_ptr, 1)); - } else { - GB_PANIC("Unknown switch kind"); - } - - ast_node(body, BlockStmt, ss->body); - - lbBlock *done = lb_create_block(p, "typeswitch.done"); - lbBlock *else_block = done; - lbBlock *default_block = nullptr; - isize num_cases = 0; - - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - num_cases += cc->list.count; - if (cc->list.count == 0) { - GB_ASSERT(default_block == nullptr); - default_block = lb_create_block(p, "typeswitch.default.body"); - else_block = default_block; - } - } - - GB_ASSERT(tag.value != nullptr); - LLVMValueRef switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases); - - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; - ast_node(cc, CaseClause, clause); - if (cc->list.count == 0) { - lb_start_block(p, default_block); - lb_store_type_case_implicit(p, clause, parent_value); - lb_type_case_body(p, ss->label, clause, p->curr_block, done); - continue; - } - - lbBlock *body = lb_create_block(p, "typeswitch.body"); - Type *case_type = nullptr; - for_array(type_index, cc->list) { - case_type = type_of_expr(cc->list[type_index]); - lbValue on_val = {}; - if (switch_kind == TypeSwitch_Union) { - Type *ut = base_type(type_deref(parent.type)); - on_val = lb_const_union_tag(m, ut, case_type); - - } else if (switch_kind == TypeSwitch_Any) { - on_val = lb_typeid(m, case_type); - } - GB_ASSERT(on_val.value != nullptr); - LLVMAddCase(switch_instr, on_val.value, body->block); - } - - Entity *case_entity = implicit_entity_of_node(clause); - - lbValue value = parent_value; - - lb_start_block(p, body); - - bool by_reference = (case_entity->flags & EntityFlag_Value) == 0; - - if (cc->list.count == 1) { - lbValue data = {}; - if (switch_kind == TypeSwitch_Union) { - data = union_data; - } else if (switch_kind == TypeSwitch_Any) { - data = lb_emit_load(p, lb_emit_struct_ep(p, parent_ptr, 0)); - } - - Type *ct = case_entity->type; - Type *ct_ptr = alloc_type_pointer(ct); - - value = lb_emit_conv(p, data, ct_ptr); - if (!by_reference) { - value = lb_emit_load(p, value); - } - } - - lb_store_type_case_implicit(p, clause, value); - lb_type_case_body(p, ss->label, clause, body, done); - } - - lb_emit_jump(p, done); - lb_start_block(p, done); -} - - -lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) { - lbModule *m = p->module; - - lbBlock *rhs = lb_create_block(p, "logical.cmp.rhs"); - lbBlock *done = lb_create_block(p, "logical.cmp.done"); - - type = default_type(type); - - lbValue short_circuit = {}; - if (op == Token_CmpAnd) { - lb_build_cond(p, left, rhs, done); - short_circuit = lb_const_bool(m, type, false); - } else if (op == Token_CmpOr) { - lb_build_cond(p, left, done, rhs); - short_circuit = lb_const_bool(m, type, true); - } - - if (rhs->preds.count == 0) { - lb_start_block(p, done); - return short_circuit; - } - - if (done->preds.count == 0) { - lb_start_block(p, rhs); - if (lb_is_expr_untyped_const(right)) { - return lb_expr_untyped_const_to_typed(m, right, type); - } - return lb_build_expr(p, right); - } - - Array<LLVMValueRef> incoming_values = {}; - Array<LLVMBasicBlockRef> incoming_blocks = {}; - array_init(&incoming_values, heap_allocator(), done->preds.count+1); - array_init(&incoming_blocks, heap_allocator(), done->preds.count+1); - - for_array(i, done->preds) { - incoming_values[i] = short_circuit.value; - incoming_blocks[i] = done->preds[i]->block; - } - - lb_start_block(p, rhs); - lbValue edge = {}; - if (lb_is_expr_untyped_const(right)) { - edge = lb_expr_untyped_const_to_typed(m, right, type); - } else { - edge = lb_build_expr(p, right); - } - - incoming_values[done->preds.count] = edge.value; - incoming_blocks[done->preds.count] = p->curr_block->block; - - lb_emit_jump(p, done); - lb_start_block(p, done); - - lbValue res = {}; - res.type = type; - res.value = LLVMBuildPhi(p->builder, lb_type(m, type), ""); - GB_ASSERT(incoming_values.count == incoming_blocks.count); - LLVMAddIncoming(res.value, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count); - - return res; -} - -lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, Ast *ast) { - lbCopyElisionHint prev = p->copy_elision_hint; - p->copy_elision_hint.used = false; - p->copy_elision_hint.ptr = {}; - p->copy_elision_hint.ast = nullptr; -#if 0 - if (addr.kind == lbAddr_Default && addr.addr.value != nullptr) { - p->copy_elision_hint.ptr = lb_addr_get_ptr(p, addr); - p->copy_elision_hint.ast = unparen_expr(ast); - } -#endif - return prev; -} - -void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint) { - p->copy_elision_hint = prev_hint; -} - -lbValue lb_consume_copy_elision_hint(lbProcedure *p) { - lbValue return_ptr = p->copy_elision_hint.ptr; - p->copy_elision_hint.used = true; - p->copy_elision_hint.ptr = {}; - p->copy_elision_hint.ast = nullptr; - return return_ptr; -} - -void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { - for_array(i, vd->names) { - lbValue value = {}; - if (vd->values.count > 0) { - GB_ASSERT(vd->names.count == vd->values.count); - Ast *ast_value = vd->values[i]; - GB_ASSERT(ast_value->tav.mode == Addressing_Constant || - ast_value->tav.mode == Addressing_Invalid); - - bool allow_local = false; - value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, allow_local); - } - - Ast *ident = vd->names[i]; - GB_ASSERT(!is_blank_ident(ident)); - Entity *e = entity_of_node(ident); - GB_ASSERT(e->flags & EntityFlag_Static); - String name = e->token.string; - - String mangled_name = {}; - { - gbString str = gb_string_make_length(permanent_allocator(), p->name.text, p->name.len); - str = gb_string_appendc(str, "-"); - str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id); - mangled_name.text = cast(u8 *)str; - mangled_name.len = gb_string_length(str); - } - - char *c_name = alloc_cstring(permanent_allocator(), mangled_name); - - LLVMValueRef global = LLVMAddGlobal(p->module->mod, lb_type(p->module, e->type), c_name); - LLVMSetInitializer(global, LLVMConstNull(lb_type(p->module, e->type))); - if (value.value != nullptr) { - LLVMSetInitializer(global, value.value); - } else { - } - if (e->Variable.thread_local_model != "") { - LLVMSetThreadLocal(global, true); - - String m = e->Variable.thread_local_model; - LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel; - if (m == "default") { - mode = LLVMGeneralDynamicTLSModel; - } else if (m == "localdynamic") { - mode = LLVMLocalDynamicTLSModel; - } else if (m == "initialexec") { - mode = LLVMInitialExecTLSModel; - } else if (m == "localexec") { - mode = LLVMLocalExecTLSModel; - } else { - GB_PANIC("Unhandled thread local mode %.*s", LIT(m)); - } - LLVMSetThreadLocalMode(global, mode); - } else { - LLVMSetLinkage(global, LLVMInternalLinkage); - } - - - lbValue global_val = {global, alloc_type_pointer(e->type)}; - lb_add_entity(p->module, e, global_val); - lb_add_member(p->module, mangled_name, global_val); - } -} - - -void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> const &values) { - if (values.count == 0) { - return; - } - - auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count); - - for_array(i, values) { - Ast *rhs = values[i]; - if (is_type_tuple(type_of_expr(rhs))) { - lbValue init = lb_build_expr(p, rhs); - Type *t = init.type; - GB_ASSERT(t->kind == Type_Tuple); - for_array(i, t->Tuple.variables) { - Entity *e = t->Tuple.variables[i]; - lbValue v = lb_emit_struct_ev(p, init, cast(i32)i); - array_add(&inits, v); - } - } else { - auto prev_hint = lb_set_copy_elision_hint(p, lvals[inits.count], rhs); - lbValue init = lb_build_expr(p, rhs); - if (p->copy_elision_hint.used) { - lvals[inits.count] = {}; // zero lval - } - lb_reset_copy_elision_hint(p, prev_hint); - array_add(&inits, init); - } - } - - GB_ASSERT(lvals.count == inits.count); - for_array(i, inits) { - lbAddr lval = lvals[i]; - lbValue init = inits[i]; - lb_addr_store(p, lval, init); - } -} - -void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res) { - lbFunctionType *ft = lb_get_function_type(p->module, p, p->type); - bool return_by_pointer = ft->ret.kind == lbArg_Indirect; - - if (return_by_pointer) { - if (res.value != nullptr) { - LLVMBuildStore(p->builder, res.value, p->return_ptr.addr.value); - } else { - LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value); - } - - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); - - LLVMBuildRetVoid(p->builder); - } else { - LLVMValueRef ret_val = res.value; - ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.type); - if (p->abi_function_type->ret.cast_type != nullptr) { - ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.cast_type); - } - - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); - LLVMBuildRet(p->builder, ret_val); - } -} -void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) { - lb_ensure_abi_function_type(p->module, p); - - lbValue res = {}; - - TypeTuple *tuple = &p->type->Proc.results->Tuple; - isize return_count = p->type->Proc.result_count; - isize res_count = return_results.count; - - lbFunctionType *ft = lb_get_function_type(p->module, p, p->type); - bool return_by_pointer = ft->ret.kind == lbArg_Indirect; - - if (return_count == 0) { - // No return values - - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); - - LLVMBuildRetVoid(p->builder); - return; - } else if (return_count == 1) { - Entity *e = tuple->variables[0]; - if (res_count == 0) { - lbValue found = map_must_get(&p->module->values, hash_entity(e)); - res = lb_emit_load(p, found); - } else { - res = lb_build_expr(p, return_results[0]); - res = lb_emit_conv(p, res, e->type); - } - if (p->type->Proc.has_named_results) { - // NOTE(bill): store the named values before returning - if (e->token.string != "") { - lbValue found = map_must_get(&p->module->values, hash_entity(e)); - lb_emit_store(p, found, lb_emit_conv(p, res, e->type)); - } - } - - } else { - auto results = array_make<lbValue>(permanent_allocator(), 0, return_count); - - if (res_count != 0) { - for (isize res_index = 0; res_index < res_count; res_index++) { - lbValue res = lb_build_expr(p, return_results[res_index]); - Type *t = res.type; - if (t->kind == Type_Tuple) { - for_array(i, t->Tuple.variables) { - Entity *e = t->Tuple.variables[i]; - lbValue v = lb_emit_struct_ev(p, res, cast(i32)i); - array_add(&results, v); - } - } else { - array_add(&results, res); - } - } - } else { - for (isize res_index = 0; res_index < return_count; res_index++) { - Entity *e = tuple->variables[res_index]; - lbValue found = map_must_get(&p->module->values, hash_entity(e)); - lbValue res = lb_emit_load(p, found); - array_add(&results, res); - } - } - - GB_ASSERT(results.count == return_count); - - if (p->type->Proc.has_named_results) { - auto named_results = slice_make<lbValue>(temporary_allocator(), results.count); - auto values = slice_make<lbValue>(temporary_allocator(), results.count); - - // NOTE(bill): store the named values before returning - for_array(i, p->type->Proc.results->Tuple.variables) { - Entity *e = p->type->Proc.results->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - - if (e->token.string == "") { - continue; - } - named_results[i] = map_must_get(&p->module->values, hash_entity(e)); - values[i] = lb_emit_conv(p, results[i], e->type); - } - - for_array(i, named_results) { - lb_emit_store(p, named_results[i], values[i]); - } - } - - Type *ret_type = p->type->Proc.results; - - // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops - if (return_by_pointer) { - res = p->return_ptr.addr; - } else { - res = lb_add_local_generated(p, ret_type, false).addr; - } - - auto result_values = slice_make<lbValue>(temporary_allocator(), results.count); - auto result_eps = slice_make<lbValue>(temporary_allocator(), results.count); - - for_array(i, results) { - result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type); - } - for_array(i, results) { - result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i); - } - for_array(i, result_values) { - lb_emit_store(p, result_eps[i], result_values[i]); - } - - if (return_by_pointer) { - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); - LLVMBuildRetVoid(p->builder); - return; - } - - res = lb_emit_load(p, res); - } - lb_build_return_stmt_internal(p, res); -} - -void lb_build_if_stmt(lbProcedure *p, Ast *node) { - ast_node(is, IfStmt, node); - lb_open_scope(p, node->scope); // Scope #1 - defer (lb_close_scope(p, lbDeferExit_Default, nullptr)); - - if (is->init != nullptr) { - // TODO(bill): Should this have a separate block to begin with? - #if 1 - lbBlock *init = lb_create_block(p, "if.init"); - lb_emit_jump(p, init); - lb_start_block(p, init); - #endif - lb_build_stmt(p, is->init); - } - lbBlock *then = lb_create_block(p, "if.then"); - lbBlock *done = lb_create_block(p, "if.done"); - lbBlock *else_ = done; - if (is->else_stmt != nullptr) { - else_ = lb_create_block(p, "if.else"); - } - - lbValue cond = lb_build_cond(p, is->cond, then, else_); - - if (is->label != nullptr) { - lbTargetList *tl = lb_push_target_list(p, is->label, done, nullptr, nullptr); - tl->is_block = true; - } - - if (LLVMIsConstant(cond.value)) { - // NOTE(bill): Do a compile time short circuit for when the condition is constantly known. - // This done manually rather than relying on the SSA passes because sometimes the SSA passes - // miss some even if they are constantly known, especially with few optimization passes. - - bool const_cond = LLVMConstIntGetZExtValue(cond.value) != 0; - - LLVMValueRef if_instr = LLVMGetLastInstruction(p->curr_block->block); - GB_ASSERT(LLVMGetInstructionOpcode(if_instr) == LLVMBr); - GB_ASSERT(LLVMIsConditional(if_instr)); - LLVMInstructionEraseFromParent(if_instr); - - - if (const_cond) { - lb_emit_jump(p, then); - lb_start_block(p, then); - - lb_build_stmt(p, is->body); - lb_emit_jump(p, done); - } else { - if (is->else_stmt != nullptr) { - lb_emit_jump(p, else_); - lb_start_block(p, else_); - - lb_open_scope(p, is->else_stmt->scope); - lb_build_stmt(p, is->else_stmt); - lb_close_scope(p, lbDeferExit_Default, nullptr); - } - lb_emit_jump(p, done); - - } - } else { - lb_start_block(p, then); - - lb_build_stmt(p, is->body); - - lb_emit_jump(p, done); - - if (is->else_stmt != nullptr) { - lb_start_block(p, else_); - - lb_open_scope(p, is->else_stmt->scope); - lb_build_stmt(p, is->else_stmt); - lb_close_scope(p, lbDeferExit_Default, nullptr); - - lb_emit_jump(p, done); - } - } - - if (is->label != nullptr) { - lb_pop_target_list(p); - } - - lb_start_block(p, done); -} - -void lb_build_for_stmt(lbProcedure *p, Ast *node) { - ast_node(fs, ForStmt, node); - - lb_open_scope(p, node->scope); // Open Scope here - - if (fs->init != nullptr) { - #if 1 - lbBlock *init = lb_create_block(p, "for.init"); - lb_emit_jump(p, init); - lb_start_block(p, init); - #endif - lb_build_stmt(p, fs->init); - } - lbBlock *body = lb_create_block(p, "for.body"); - lbBlock *done = lb_create_block(p, "for.done"); // NOTE(bill): Append later - lbBlock *loop = body; - if (fs->cond != nullptr) { - loop = lb_create_block(p, "for.loop"); - } - lbBlock *post = loop; - if (fs->post != nullptr) { - post = lb_create_block(p, "for.post"); - } - - - lb_emit_jump(p, loop); - lb_start_block(p, loop); - - if (loop != body) { - lb_build_cond(p, fs->cond, body, done); - lb_start_block(p, body); - } - - lb_push_target_list(p, fs->label, done, post, nullptr); - - lb_build_stmt(p, fs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); - - lb_pop_target_list(p); - - lb_emit_jump(p, post); - - if (fs->post != nullptr) { - lb_start_block(p, post); - lb_build_stmt(p, fs->post); - lb_emit_jump(p, loop); - } - - lb_start_block(p, done); -} - -void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) { - Type *lhs_type = lb_addr_type(lhs); - Type *rhs_type = value.type; - Type *array_type = base_type(lhs_type); - GB_ASSERT(is_type_array_like(array_type)); - i64 count = get_array_type_count(array_type); - Type *elem_type = base_array_type(array_type); - - lbValue rhs = lb_emit_conv(p, value, lhs_type); - - bool inline_array_arith = type_size_of(array_type) <= build_context.max_align; - - - if (lhs.kind == lbAddr_Swizzle) { - GB_ASSERT(is_type_array(lhs_type)); - - struct ValueAndIndex { - lbValue value; - u8 index; - }; - - bool indices_handled[4] = {}; - i32 indices[4] = {}; - i32 index_count = 0; - for (u8 i = 0; i < lhs.swizzle.count; i++) { - u8 index = lhs.swizzle.indices[i]; - if (indices_handled[index]) { - continue; - } - indices[index_count++] = index; - } - gb_sort_array(indices, index_count, gb_i32_cmp(0)); - - lbValue lhs_ptrs[4] = {}; - lbValue x_loads[4] = {}; - lbValue y_loads[4] = {}; - lbValue ops[4] = {}; - - for (i32 i = 0; i < index_count; i++) { - lhs_ptrs[i] = lb_emit_array_epi(p, lhs.addr, indices[i]); - } - for (i32 i = 0; i < index_count; i++) { - x_loads[i] = lb_emit_load(p, lhs_ptrs[i]); - } - for (i32 i = 0; i < index_count; i++) { - y_loads[i].value = LLVMBuildExtractValue(p->builder, rhs.value, i, ""); - y_loads[i].type = elem_type; - } - for (i32 i = 0; i < index_count; i++) { - ops[i] = lb_emit_arith(p, op, x_loads[i], y_loads[i], elem_type); - } - for (i32 i = 0; i < index_count; i++) { - lb_emit_store(p, lhs_ptrs[i], ops[i]); - } - return; - } - - - lbValue x = lb_addr_get_ptr(p, lhs); - - - if (inline_array_arith) { - #if 1 - #if 1 - unsigned n = cast(unsigned)count; - - auto lhs_ptrs = slice_make<lbValue>(temporary_allocator(), n); - auto x_loads = slice_make<lbValue>(temporary_allocator(), n); - auto y_loads = slice_make<lbValue>(temporary_allocator(), n); - auto ops = slice_make<lbValue>(temporary_allocator(), n); - - for (unsigned i = 0; i < n; i++) { - lhs_ptrs[i] = lb_emit_array_epi(p, x, i); - } - for (unsigned i = 0; i < n; i++) { - x_loads[i] = lb_emit_load(p, lhs_ptrs[i]); - } - for (unsigned i = 0; i < n; i++) { - y_loads[i].value = LLVMBuildExtractValue(p->builder, rhs.value, i, ""); - y_loads[i].type = elem_type; - } - for (unsigned i = 0; i < n; i++) { - ops[i] = lb_emit_arith(p, op, x_loads[i], y_loads[i], elem_type); - } - for (unsigned i = 0; i < n; i++) { - lb_emit_store(p, lhs_ptrs[i], ops[i]); - } - - #else - lbValue y = lb_address_from_load_or_generate_local(p, rhs); - - unsigned n = cast(unsigned)count; - - auto lhs_ptrs = slice_make<lbValue>(temporary_allocator(), n); - auto rhs_ptrs = slice_make<lbValue>(temporary_allocator(), n); - auto x_loads = slice_make<lbValue>(temporary_allocator(), n); - auto y_loads = slice_make<lbValue>(temporary_allocator(), n); - auto ops = slice_make<lbValue>(temporary_allocator(), n); - - for (unsigned i = 0; i < n; i++) { - lhs_ptrs[i] = lb_emit_array_epi(p, x, i); - } - for (unsigned i = 0; i < n; i++) { - rhs_ptrs[i] = lb_emit_array_epi(p, y, i); - } - for (unsigned i = 0; i < n; i++) { - x_loads[i] = lb_emit_load(p, lhs_ptrs[i]); - } - for (unsigned i = 0; i < n; i++) { - y_loads[i] = lb_emit_load(p, rhs_ptrs[i]); - } - for (unsigned i = 0; i < n; i++) { - ops[i] = lb_emit_arith(p, op, x_loads[i], y_loads[i], elem_type); - } - for (unsigned i = 0; i < n; i++) { - lb_emit_store(p, lhs_ptrs[i], ops[i]); - } - #endif - #else - lbValue y = lb_address_from_load_or_generate_local(p, rhs); - - for (i64 i = 0; i < count; i++) { - lbValue a_ptr = lb_emit_array_epi(p, x, i); - lbValue b_ptr = lb_emit_array_epi(p, y, i); - - lbValue a = lb_emit_load(p, a_ptr); - lbValue b = lb_emit_load(p, b_ptr); - lbValue c = lb_emit_arith(p, op, a, b, elem_type); - lb_emit_store(p, a_ptr, c); - } - #endif - } else { - lbValue y = lb_address_from_load_or_generate_local(p, rhs); - - auto loop_data = lb_loop_start(p, cast(isize)count, t_i32); - - lbValue a_ptr = lb_emit_array_ep(p, x, loop_data.idx); - lbValue b_ptr = lb_emit_array_ep(p, y, loop_data.idx); - - lbValue a = lb_emit_load(p, a_ptr); - lbValue b = lb_emit_load(p, b_ptr); - lbValue c = lb_emit_arith(p, op, a, b, elem_type); - lb_emit_store(p, a_ptr, c); - - lb_loop_end(p, loop_data); - } -} -void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) { - if (as->op.kind == Token_Eq) { - auto lvals = array_make<lbAddr>(permanent_allocator(), 0, as->lhs.count); - - for_array(i, as->lhs) { - Ast *lhs = as->lhs[i]; - lbAddr lval = {}; - if (!is_blank_ident(lhs)) { - lval = lb_build_addr(p, lhs); - } - array_add(&lvals, lval); - } - lb_build_assignment(p, lvals, as->rhs); - return; - } - GB_ASSERT(as->lhs.count == 1); - GB_ASSERT(as->rhs.count == 1); - // NOTE(bill): Only 1 += 1 is allowed, no tuples - // +=, -=, etc - i32 op_ = cast(i32)as->op.kind; - op_ += Token_Add - Token_AddEq; // Convert += to + - TokenKind op = cast(TokenKind)op_; - if (op == Token_CmpAnd || op == Token_CmpOr) { - Type *type = as->lhs[0]->tav.type; - lbValue new_value = lb_emit_logical_binary_expr(p, op, as->lhs[0], as->rhs[0], type); - - lbAddr lhs = lb_build_addr(p, as->lhs[0]); - lb_addr_store(p, lhs, new_value); - } else { - lbAddr lhs = lb_build_addr(p, as->lhs[0]); - lbValue value = lb_build_expr(p, as->rhs[0]); - - Type *lhs_type = lb_addr_type(lhs); - if (is_type_array(lhs_type)) { - lb_build_assign_stmt_array(p, op, lhs, value); - return; - } else { - lbValue old_value = lb_addr_load(p, lhs); - Type *type = old_value.type; - - lbValue change = lb_emit_conv(p, value, type); - lbValue new_value = lb_emit_arith(p, op, old_value, change, type); - lb_addr_store(p, lhs, new_value); - } - } -} - - -void lb_build_stmt(lbProcedure *p, Ast *node) { - Ast *prev_stmt = p->curr_stmt; - defer (p->curr_stmt = prev_stmt); - p->curr_stmt = node; - - if (p->curr_block != nullptr) { - LLVMValueRef last_instr = LLVMGetLastInstruction(p->curr_block->block); - if (lb_is_instr_terminating(last_instr)) { - return; - } - } - - LLVMMetadataRef prev_debug_location = nullptr; - if (p->debug_info != nullptr) { - prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder); - LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node)); - } - defer (if (prev_debug_location != nullptr) { - LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location); - }); - - u16 prev_state_flags = p->state_flags; - defer (p->state_flags = prev_state_flags); - - if (node->state_flags != 0) { - u16 in = node->state_flags; - u16 out = p->state_flags; - - if (in & StateFlag_bounds_check) { - out |= StateFlag_bounds_check; - out &= ~StateFlag_no_bounds_check; - } else if (in & StateFlag_no_bounds_check) { - out |= StateFlag_no_bounds_check; - out &= ~StateFlag_bounds_check; - } - - p->state_flags = out; - } - - switch (node->kind) { - case_ast_node(bs, EmptyStmt, node); - case_end; - - case_ast_node(us, UsingStmt, node); - case_end; - - case_ast_node(ws, WhenStmt, node); - lb_build_when_stmt(p, ws); - case_end; - - - case_ast_node(bs, BlockStmt, node); - lbBlock *done = nullptr; - if (bs->label != nullptr) { - done = lb_create_block(p, "block.done"); - lbTargetList *tl = lb_push_target_list(p, bs->label, done, nullptr, nullptr); - tl->is_block = true; - } - - lb_open_scope(p, node->scope); - lb_build_stmt_list(p, bs->stmts); - lb_close_scope(p, lbDeferExit_Default, nullptr); - - if (done != nullptr) { - lb_emit_jump(p, done); - lb_start_block(p, done); - } - - if (bs->label != nullptr) { - lb_pop_target_list(p); - } - case_end; - - case_ast_node(vd, ValueDecl, node); - if (!vd->is_mutable) { - return; - } - - bool is_static = false; - if (vd->names.count > 0) { - Entity *e = entity_of_node(vd->names[0]); - if (e->flags & EntityFlag_Static) { - // NOTE(bill): If one of the entities is static, they all are - is_static = true; - } - } - - if (is_static) { - lb_build_static_variables(p, vd); - return; - } - - auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count); - - for_array(i, vd->names) { - Ast *name = vd->names[i]; - lbAddr lval = {}; - if (!is_blank_ident(name)) { - Entity *e = entity_of_node(name); - bool zero_init = true; // Always do it - lval = lb_add_local(p, e->type, e, zero_init); - } - array_add(&lvals, lval); - } - lb_build_assignment(p, lvals, vd->values); - case_end; - - case_ast_node(as, AssignStmt, node); - lb_build_assign_stmt(p, as); - case_end; - - case_ast_node(es, ExprStmt, node); - lb_build_expr(p, es->expr); - case_end; - - case_ast_node(ds, DeferStmt, node); - lb_add_defer_node(p, p->scope_index, ds->stmt); - case_end; - - case_ast_node(rs, ReturnStmt, node); - lb_build_return_stmt(p, rs->results); - case_end; - - case_ast_node(is, IfStmt, node); - lb_build_if_stmt(p, node); - case_end; - - case_ast_node(fs, ForStmt, node); - lb_build_for_stmt(p, node); - case_end; - - case_ast_node(rs, RangeStmt, node); - lb_build_range_stmt(p, rs, node->scope); - case_end; - - case_ast_node(rs, UnrollRangeStmt, node); - lb_build_unroll_range_stmt(p, rs, node->scope); - case_end; - - case_ast_node(ss, SwitchStmt, node); - lb_build_switch_stmt(p, ss, node->scope); - case_end; - - case_ast_node(ss, TypeSwitchStmt, node); - lb_build_type_switch_stmt(p, ss); - case_end; - - case_ast_node(bs, BranchStmt, node); - lbBlock *block = nullptr; - - if (bs->label != nullptr) { - lbBranchBlocks bb = lb_lookup_branch_blocks(p, bs->label); - switch (bs->token.kind) { - case Token_break: block = bb.break_; break; - case Token_continue: block = bb.continue_; break; - case Token_fallthrough: - GB_PANIC("fallthrough cannot have a label"); - break; - } - } else { - for (lbTargetList *t = p->target_list; t != nullptr && block == nullptr; t = t->prev) { - if (t->is_block) { - continue; - } - - switch (bs->token.kind) { - case Token_break: block = t->break_; break; - case Token_continue: block = t->continue_; break; - case Token_fallthrough: block = t->fallthrough_; break; - } - } - } - if (block != nullptr) { - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); - } - lb_emit_jump(p, block); - case_end; - } -} - -lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y) { - cond = lb_emit_conv(p, cond, t_llvm_bool); - lbValue res = {}; - res.value = LLVMBuildSelect(p->builder, cond.value, x.value, y.value, ""); - res.type = x.type; - return res; -} - -lbValue lb_const_nil(lbModule *m, Type *type) { - LLVMValueRef v = LLVMConstNull(lb_type(m, type)); - return lbValue{v, type}; -} - -lbValue lb_const_undef(lbModule *m, Type *type) { - LLVMValueRef v = LLVMGetUndef(lb_type(m, type)); - return lbValue{v, type}; -} - - -lbValue lb_const_int(lbModule *m, Type *type, u64 value) { - lbValue res = {}; - res.value = LLVMConstInt(lb_type(m, type), cast(unsigned long long)value, !is_type_unsigned(type)); - res.type = type; - return res; -} - -lbValue lb_const_string(lbModule *m, String const &value) { - return lb_const_value(m, t_string, exact_value_string(value)); -} - - -lbValue lb_const_bool(lbModule *m, Type *type, bool value) { - lbValue res = {}; - res.value = LLVMConstInt(lb_type(m, type), value, false); - res.type = type; - return res; -} - -LLVMValueRef lb_const_f16(lbModule *m, f32 f, Type *type=t_f16) { - GB_ASSERT(type_size_of(type) == 2); - - u16 u = f32_to_f16(f); - if (is_type_different_to_arch_endianness(type)) { - u = gb_endian_swap16(u); - } - LLVMValueRef i = LLVMConstInt(LLVMInt16TypeInContext(m->ctx), u, false); - return LLVMConstBitCast(i, lb_type(m, type)); -} - -LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) { - GB_ASSERT(type_size_of(type) == 4); - u32 u = bit_cast<u32>(f); - if (is_type_different_to_arch_endianness(type)) { - u = gb_endian_swap32(u); - } - LLVMValueRef i = LLVMConstInt(LLVMInt32TypeInContext(m->ctx), u, false); - return LLVMConstBitCast(i, lb_type(m, type)); -} - -lbValue lb_emit_min(lbProcedure *p, Type *t, lbValue x, lbValue y) { - x = lb_emit_conv(p, x, t); - y = lb_emit_conv(p, y, t); - return lb_emit_select(p, lb_emit_comp(p, Token_Lt, x, y), x, y); -} -lbValue lb_emit_max(lbProcedure *p, Type *t, lbValue x, lbValue y) { - x = lb_emit_conv(p, x, t); - y = lb_emit_conv(p, y, t); - return lb_emit_select(p, lb_emit_comp(p, Token_Gt, x, y), x, y); -} - - -lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue max) { - lbValue z = {}; - z = lb_emit_max(p, t, x, min); - z = lb_emit_min(p, t, z, max); - return z; -} - - - -LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { - StringHashKey key = string_hash_string(str); - LLVMValueRef *found = string_map_get(&m->const_strings, key); - if (found != nullptr) { - return *found; - } else { - LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef data = LLVMConstStringInContext(m->ctx, - cast(char const *)str.text, - cast(unsigned)str.len, - false); - - - isize max_len = 7+8+1; - char *name = gb_alloc_array(permanent_allocator(), char, max_len); - - u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1); - isize len = gb_snprintf(name, max_len, "csbs$%x", id); - len -= 1; - - LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); - LLVMSetInitializer(global_data, data); - LLVMSetLinkage(global_data, LLVMInternalLinkage); - - LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2); - string_map_set(&m->const_strings, key, ptr); - return ptr; - } -} - -lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) { - LLVMValueRef ptr = nullptr; - if (str.len != 0) { - ptr = lb_find_or_add_entity_string_ptr(m, str); - } else { - ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); - } - LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), str.len, true); - LLVMValueRef values[2] = {ptr, str_len}; - - lbValue res = {}; - res.value = llvm_const_named_struct(lb_type(m, t_string), values, 2); - res.type = t_string; - return res; -} - -lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) { - LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef data = LLVMConstStringInContext(m->ctx, - cast(char const *)str.text, - cast(unsigned)str.len, - false); - - - char *name = nullptr; - { - isize max_len = 7+8+1; - name = gb_alloc_array(permanent_allocator(), char, max_len); - u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1); - isize len = gb_snprintf(name, max_len, "csbs$%x", id); - len -= 1; - } - LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); - LLVMSetInitializer(global_data, data); - LLVMSetLinkage(global_data, LLVMInternalLinkage); - - LLVMValueRef ptr = nullptr; - if (str.len != 0) { - ptr = LLVMConstInBoundsGEP(global_data, indices, 2); - } else { - ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); - } - LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), str.len, true); - LLVMValueRef values[2] = {ptr, len}; - - lbValue res = {}; - res.value = llvm_const_named_struct(lb_type(m, t_u8_slice), values, 2); - res.type = t_u8_slice; - return res; -} - -isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) { - isize index = type_info_index(info, type, false); - if (index >= 0) { - auto *set = &info->minimum_dependency_type_info_set; - for_array(i, set->entries) { - if (set->entries[i].ptr == index) { - return i+1; - } - } - } - if (err_on_not_found) { - GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index); - } - return -1; -} - -lbValue lb_typeid(lbModule *m, Type *type) { - type = default_type(type); - - u64 id = cast(u64)lb_type_info_index(m->info, type); - GB_ASSERT(id >= 0); - - u64 kind = Typeid_Invalid; - u64 named = is_type_named(type) && type->kind != Type_Basic; - u64 special = 0; - u64 reserved = 0; - - Type *bt = base_type(type); - TypeKind tk = bt->kind; - switch (tk) { - case Type_Basic: { - u32 flags = bt->Basic.flags; - if (flags & BasicFlag_Boolean) kind = Typeid_Boolean; - if (flags & BasicFlag_Integer) kind = Typeid_Integer; - if (flags & BasicFlag_Unsigned) kind = Typeid_Integer; - if (flags & BasicFlag_Float) kind = Typeid_Float; - if (flags & BasicFlag_Complex) kind = Typeid_Complex; - if (flags & BasicFlag_Pointer) kind = Typeid_Pointer; - if (flags & BasicFlag_String) kind = Typeid_String; - if (flags & BasicFlag_Rune) kind = Typeid_Rune; - } break; - case Type_Pointer: kind = Typeid_Pointer; break; - case Type_Array: kind = Typeid_Array; break; - case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break; - case Type_Slice: kind = Typeid_Slice; break; - case Type_DynamicArray: kind = Typeid_Dynamic_Array; break; - case Type_Map: kind = Typeid_Map; break; - case Type_Struct: kind = Typeid_Struct; break; - case Type_Enum: kind = Typeid_Enum; break; - case Type_Union: kind = Typeid_Union; break; - case Type_Tuple: kind = Typeid_Tuple; break; - case Type_Proc: kind = Typeid_Procedure; break; - case Type_BitSet: kind = Typeid_Bit_Set; break; - case Type_SimdVector: kind = Typeid_Simd_Vector; break; - case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; - case Type_RelativeSlice: kind = Typeid_Relative_Slice; break; - } - - if (is_type_cstring(type)) { - special = 1; - } else if (is_type_integer(type) && !is_type_unsigned(type)) { - special = 1; - } - - u64 data = 0; - if (build_context.word_size == 4) { - GB_ASSERT(id <= (1u<<24u)); - data |= (id &~ (1u<<24)) << 0u; // index - data |= (kind &~ (1u<<5)) << 24u; // kind - data |= (named &~ (1u<<1)) << 29u; // kind - data |= (special &~ (1u<<1)) << 30u; // kind - data |= (reserved &~ (1u<<1)) << 31u; // kind - } else { - GB_ASSERT(build_context.word_size == 8); - GB_ASSERT(id <= (1ull<<56u)); - data |= (id &~ (1ull<<56)) << 0ul; // index - data |= (kind &~ (1ull<<5)) << 56ull; // kind - data |= (named &~ (1ull<<1)) << 61ull; // kind - data |= (special &~ (1ull<<1)) << 62ull; // kind - data |= (reserved &~ (1ull<<1)) << 63ull; // kind - } - - lbValue res = {}; - res.value = LLVMConstInt(lb_type(m, t_typeid), data, false); - res.type = t_typeid; - return res; -} - -lbValue lb_type_info(lbModule *m, Type *type) { - type = default_type(type); - - isize index = lb_type_info_index(m->info, type); - GB_ASSERT(index >= 0); - - LLVMTypeRef it = lb_type(m, t_int); - LLVMValueRef indices[2] = { - LLVMConstInt(it, 0, false), - LLVMConstInt(it, index, true), - }; - - lbValue value = {}; - value.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)); - value.type = t_type_info_ptr; - return value; -} - -LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, bool allow_local) { - bool is_local = allow_local && m->curr_procedure != nullptr; - bool is_const = true; - if (is_local) { - for (isize i = 0; i < count; i++) { - GB_ASSERT(values[i] != nullptr); - if (!LLVMIsConstant(values[i])) { - is_const = false; - break; - } - } - } - - if (!is_const) { - lbProcedure *p = m->curr_procedure; - GB_ASSERT(p != nullptr); - lbAddr v = lb_add_local_generated(p, type, false); - lbValue ptr = lb_addr_get_ptr(p, v); - for (isize i = 0; i < count; i++) { - lbValue elem = lb_emit_array_epi(p, ptr, i); - LLVMBuildStore(p->builder, values[i], elem.value); - } - return lb_addr_load(p, v).value; - } - - return llvm_const_array(lb_type(m, elem_type), values, cast(unsigned int)count); -} - -lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) { - GB_ASSERT(is_type_proc(e->type)); - e = strip_entity_wrapping(e); - GB_ASSERT(e != nullptr); - - auto *found = map_get(&m->values, hash_entity(e)); - if (found) { - return *found; - } - - bool ignore_body = false; - - lbModule *other_module = m; - if (USE_SEPARATE_MODULES) { - other_module = lb_pkg_module(m->gen, e->pkg); - } - if (other_module == m) { - debugf("Missing Procedure (lb_find_procedure_value_from_entity): %.*s\n", LIT(e->token.string)); - } - ignore_body = other_module != m; - - lbProcedure *missing_proc = lb_create_procedure(m, e, ignore_body); - if (!ignore_body) { - array_add(&m->missing_procedures_to_check, missing_proc); - } - found = map_get(&m->values, hash_entity(e)); - if (found) { - return *found; - } - - GB_PANIC("Error in: %s, missing procedure %.*s\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); - return {}; -} - void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name) { if (other_module == nullptr) { return; @@ -6342,2271 +71,6 @@ void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, } } -lbValue lb_find_value_from_entity(lbModule *m, Entity *e) { - e = strip_entity_wrapping(e); - GB_ASSERT(e != nullptr); - - GB_ASSERT(e->token.string != "_"); - - if (e->kind == Entity_Procedure) { - return lb_find_procedure_value_from_entity(m, e); - } - - auto *found = map_get(&m->values, hash_entity(e)); - if (found) { - return *found; - } - - if (USE_SEPARATE_MODULES) { - lbModule *other_module = lb_pkg_module(m->gen, e->pkg); - - // TODO(bill): correct this logic - bool is_external = other_module != m; - if (!is_external) { - if (e->code_gen_module != nullptr) { - other_module = e->code_gen_module; - } else { - other_module = nullptr; - } - is_external = other_module != m; - } - - if (is_external) { - String name = lb_get_entity_name(other_module, e); - - lbValue g = {}; - g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); - g.type = alloc_type_pointer(e->type); - lb_add_entity(m, e, g); - lb_add_member(m, name, g); - - LLVMSetLinkage(g.value, LLVMExternalLinkage); - - lb_set_entity_from_other_modules_linkage_correctly(other_module, e, name); - - // LLVMSetLinkage(other_g.value, LLVMExternalLinkage); - - if (e->Variable.thread_local_model != "") { - LLVMSetThreadLocal(g.value, true); - - String m = e->Variable.thread_local_model; - LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel; - if (m == "default") { - mode = LLVMGeneralDynamicTLSModel; - } else if (m == "localdynamic") { - mode = LLVMLocalDynamicTLSModel; - } else if (m == "initialexec") { - mode = LLVMInitialExecTLSModel; - } else if (m == "localexec") { - mode = LLVMLocalExecTLSModel; - } else { - GB_PANIC("Unhandled thread local mode %.*s", LIT(m)); - } - LLVMSetThreadLocalMode(g.value, mode); - } - - - return g; - } - } - - GB_PANIC("\n\tError in: %s, missing value '%.*s'\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); - return {}; -} - - -LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) { - if (big_int_is_zero(a)) { - return LLVMConstNull(lb_type(m, original_type)); - } - - size_t sz = cast(size_t)type_size_of(original_type); - u64 rop64[4] = {}; // 2 u64 is the maximum we will ever need, so doubling it will be fine :P - u8 *rop = cast(u8 *)rop64; - - size_t max_count = 0; - size_t written = 0; - size_t size = 1; - size_t nails = 0; - mp_endian endian = MP_LITTLE_ENDIAN; - - max_count = mp_pack_count(a, nails, size); - GB_ASSERT_MSG(sz >= max_count, "max_count: %tu, sz: %tu, written: %tu", max_count, sz, written); - GB_ASSERT(gb_size_of(rop64) >= sz); - - mp_err err = mp_pack(rop, sz, &written, - MP_LSB_FIRST, - size, endian, nails, - a); - GB_ASSERT(err == MP_OKAY); - - if (!is_type_endian_little(original_type)) { - for (size_t i = 0; i < sz/2; i++) { - u8 tmp = rop[i]; - rop[i] = rop[sz-1-i]; - rop[sz-1-i] = tmp; - } - } - - LLVMValueRef value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)(sz+7/8), cast(u64 *)rop); - if (big_int_is_neg(a)) { - value = LLVMConstNeg(value); - } - - return value; -} - - -lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) { - LLVMContextRef ctx = m->ctx; - - type = default_type(type); - Type *original_type = type; - - lbValue res = {}; - res.type = original_type; - type = core_type(type); - value = convert_exact_value_for_type(value, type); - - if (value.kind == ExactValue_Typeid) { - return lb_typeid(m, value.value_typeid); - } - - if (value.kind == ExactValue_Invalid) { - return lb_const_nil(m, type); - } - - if (value.kind == ExactValue_Procedure) { - Ast *expr = unparen_expr(value.value_procedure); - if (expr->kind == Ast_ProcLit) { - return lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr); - } - Entity *e = entity_from_expr(expr); - return lb_find_procedure_value_from_entity(m, e); - } - - bool is_local = allow_local && m->curr_procedure != nullptr; - - // GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type)); - - if (is_type_slice(type)) { - if (value.kind == ExactValue_String) { - GB_ASSERT(is_type_u8_slice(type)); - res.value = lb_find_or_add_entity_string_byte_slice(m, value.value_string).value; - return res; - } else { - ast_node(cl, CompoundLit, value.value_compound); - - isize count = cl->elems.count; - if (count == 0) { - return lb_const_nil(m, type); - } - count = gb_max(cast(isize)cl->max_count, count); - Type *elem = base_type(type)->Slice.elem; - Type *t = alloc_type_array(elem, count); - lbValue backing_array = lb_const_value(m, t, value, allow_local); - - LLVMValueRef array_data = nullptr; - - if (is_local) { - // NOTE(bill, 2020-06-08): This is a bit of a hack but a "constant" slice needs - // its backing data on the stack - lbProcedure *p = m->curr_procedure; - LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); - - LLVMTypeRef llvm_type = lb_type(m, t); - array_data = LLVMBuildAlloca(p->builder, llvm_type, ""); - LLVMSetAlignment(array_data, 16); // TODO(bill): Make this configurable - LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); - LLVMBuildStore(p->builder, backing_array.value, array_data); - - { - LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef ptr = LLVMBuildInBoundsGEP(p->builder, array_data, indices, 2, ""); - LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); - lbAddr slice = lb_add_local_generated(p, type, false); - lb_fill_slice(p, slice, {ptr, alloc_type_pointer(elem)}, {len, t_int}); - return lb_addr_load(p, slice); - } - } else { - isize max_len = 7+8+1; - char *str = gb_alloc_array(permanent_allocator(), char, max_len); - u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1); - isize len = gb_snprintf(str, max_len, "csba$%x", id); - - String name = make_string(cast(u8 *)str, len-1); - - Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value); - array_data = LLVMAddGlobal(m->mod, lb_type(m, t), str); - LLVMSetInitializer(array_data, backing_array.value); - - lbValue g = {}; - g.value = array_data; - g.type = t; - - lb_add_entity(m, e, g); - lb_add_member(m, name, g); - - { - LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef ptr = LLVMConstInBoundsGEP(array_data, indices, 2); - LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); - LLVMValueRef values[2] = {ptr, len}; - - res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2); - return res; - } - } - - - } - } else if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { - if (is_type_rune_array(type) && value.kind == ExactValue_String) { - i64 count = type->Array.count; - Type *elem = type->Array.elem; - LLVMTypeRef et = lb_type(m, elem); - - Rune rune; - isize offset = 0; - isize width = 1; - String s = value.value_string; - - LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count); - - for (i64 i = 0; i < count && offset < s.len; i++) { - width = utf8_decode(s.text+offset, s.len-offset, &rune); - offset += width; - - elems[i] = LLVMConstInt(et, rune, true); - - } - GB_ASSERT(offset == s.len); - - res.value = llvm_const_array(et, elems, cast(unsigned)count); - return res; - } - GB_PANIC("This should not have happened!\n"); - - LLVMValueRef data = LLVMConstStringInContext(ctx, - cast(char const *)value.value_string.text, - cast(unsigned)value.value_string.len, - false /*DontNullTerminate*/); - res.value = data; - return res; - } else if (is_type_u8_array(type) && value.kind == ExactValue_String) { - GB_ASSERT(type->Array.count == value.value_string.len); - LLVMValueRef data = LLVMConstStringInContext(ctx, - cast(char const *)value.value_string.text, - cast(unsigned)value.value_string.len, - true /*DontNullTerminate*/); - res.value = data; - return res; - } else if (is_type_array(type) && - value.kind != ExactValue_Invalid && - value.kind != ExactValue_String && - value.kind != ExactValue_Compound) { - - i64 count = type->Array.count; - Type *elem = type->Array.elem; - - - lbValue single_elem = lb_const_value(m, elem, value, allow_local); - - LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count); - for (i64 i = 0; i < count; i++) { - elems[i] = single_elem.value; - } - - res.value = llvm_const_array(lb_type(m, elem), elems, cast(unsigned)count); - return res; - } - - switch (value.kind) { - case ExactValue_Invalid: - res.value = LLVMConstNull(lb_type(m, original_type)); - return res; - case ExactValue_Bool: - res.value = LLVMConstInt(lb_type(m, original_type), value.value_bool, false); - return res; - case ExactValue_String: - { - LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, value.value_string); - lbValue res = {}; - res.type = default_type(original_type); - if (is_type_cstring(res.type)) { - res.value = ptr; - } else { - if (value.value_string.len == 0) { - ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); - } - LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), value.value_string.len, true); - LLVMValueRef values[2] = {ptr, str_len}; - GB_ASSERT(is_type_string(original_type)); - - res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2); - } - - return res; - } - - case ExactValue_Integer: - if (is_type_pointer(type)) { - LLVMTypeRef t = lb_type(m, original_type); - LLVMValueRef i = lb_big_int_to_llvm(m, t_uintptr, &value.value_integer); - res.value = LLVMConstIntToPtr(i, t); - } else { - res.value = lb_big_int_to_llvm(m, original_type, &value.value_integer); - } - return res; - case ExactValue_Float: - if (is_type_different_to_arch_endianness(type)) { - u64 u = bit_cast<u64>(value.value_float); - u = gb_endian_swap64(u); - res.value = LLVMConstReal(lb_type(m, original_type), bit_cast<f64>(u)); - } else { - res.value = LLVMConstReal(lb_type(m, original_type), value.value_float); - } - return res; - case ExactValue_Complex: - { - LLVMValueRef values[2] = {}; - switch (8*type_size_of(type)) { - case 32: - values[0] = lb_const_f16(m, cast(f32)value.value_complex->real); - values[1] = lb_const_f16(m, cast(f32)value.value_complex->imag); - break; - case 64: - values[0] = lb_const_f32(m, cast(f32)value.value_complex->real); - values[1] = lb_const_f32(m, cast(f32)value.value_complex->imag); - break; - case 128: - values[0] = LLVMConstReal(lb_type(m, t_f64), value.value_complex->real); - values[1] = LLVMConstReal(lb_type(m, t_f64), value.value_complex->imag); - break; - } - - res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2); - return res; - } - break; - case ExactValue_Quaternion: - { - LLVMValueRef values[4] = {}; - switch (8*type_size_of(type)) { - case 64: - // @QuaternionLayout - values[3] = lb_const_f16(m, cast(f32)value.value_quaternion->real); - values[0] = lb_const_f16(m, cast(f32)value.value_quaternion->imag); - values[1] = lb_const_f16(m, cast(f32)value.value_quaternion->jmag); - values[2] = lb_const_f16(m, cast(f32)value.value_quaternion->kmag); - break; - case 128: - // @QuaternionLayout - values[3] = lb_const_f32(m, cast(f32)value.value_quaternion->real); - values[0] = lb_const_f32(m, cast(f32)value.value_quaternion->imag); - values[1] = lb_const_f32(m, cast(f32)value.value_quaternion->jmag); - values[2] = lb_const_f32(m, cast(f32)value.value_quaternion->kmag); - break; - case 256: - // @QuaternionLayout - values[3] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->real); - values[0] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->imag); - values[1] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->jmag); - values[2] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->kmag); - break; - } - - res.value = llvm_const_named_struct(lb_type(m, original_type), values, 4); - return res; - } - break; - - case ExactValue_Pointer: - res.value = LLVMConstIntToPtr(LLVMConstInt(lb_type(m, t_uintptr), value.value_pointer, false), lb_type(m, original_type)); - return res; - - case ExactValue_Compound: - if (is_type_slice(type)) { - return lb_const_value(m, type, value, allow_local); - } else if (is_type_array(type)) { - ast_node(cl, CompoundLit, value.value_compound); - Type *elem_type = type->Array.elem; - isize elem_count = cl->elems.count; - if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) { - return lb_const_nil(m, original_type); - } - if (cl->elems[0]->kind == Ast_FieldValue) { - // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand - LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count); - - isize value_index = 0; - for (i64 i = 0; i < type->Array.count; i++) { - bool found = false; - - for (isize j = 0; j < elem_count; j++) { - Ast *elem = cl->elems[j]; - ast_node(fv, FieldValue, elem); - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - if (lo == i) { - TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; - for (i64 k = lo; k < hi; k++) { - values[value_index++] = val; - } - - found = true; - i += (hi-lo-1); - break; - } - } else { - TypeAndValue index_tav = fv->field->tav; - GB_ASSERT(index_tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(index_tav.value); - if (index == i) { - TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; - values[value_index++] = val; - found = true; - break; - } - } - } - - if (!found) { - values[value_index++] = LLVMConstNull(lb_type(m, elem_type)); - } - } - - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, allow_local); - return res; - } else { - GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); - - LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count); - - for (isize i = 0; i < elem_count; i++) { - TypeAndValue tav = cl->elems[i]->tav; - GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value; - } - for (isize i = elem_count; i < type->Array.count; i++) { - values[i] = LLVMConstNull(lb_type(m, elem_type)); - } - - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, allow_local); - return res; - } - } else if (is_type_enumerated_array(type)) { - ast_node(cl, CompoundLit, value.value_compound); - Type *elem_type = type->EnumeratedArray.elem; - isize elem_count = cl->elems.count; - if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) { - return lb_const_nil(m, original_type); - } - if (cl->elems[0]->kind == Ast_FieldValue) { - // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand - LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->EnumeratedArray.count); - - isize value_index = 0; - - i64 total_lo = exact_value_to_i64(type->EnumeratedArray.min_value); - i64 total_hi = exact_value_to_i64(type->EnumeratedArray.max_value); - - for (i64 i = total_lo; i <= total_hi; i++) { - bool found = false; - - for (isize j = 0; j < elem_count; j++) { - Ast *elem = cl->elems[j]; - ast_node(fv, FieldValue, elem); - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - if (lo == i) { - TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; - for (i64 k = lo; k < hi; k++) { - values[value_index++] = val; - } - - found = true; - i += (hi-lo-1); - break; - } - } else { - TypeAndValue index_tav = fv->field->tav; - GB_ASSERT(index_tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(index_tav.value); - if (index == i) { - TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; - values[value_index++] = val; - found = true; - break; - } - } - } - - if (!found) { - values[value_index++] = LLVMConstNull(lb_type(m, elem_type)); - } - } - - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, allow_local); - return res; - } else { - GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count); - - LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->EnumeratedArray.count); - - for (isize i = 0; i < elem_count; i++) { - TypeAndValue tav = cl->elems[i]->tav; - GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value; - } - for (isize i = elem_count; i < type->EnumeratedArray.count; i++) { - values[i] = LLVMConstNull(lb_type(m, elem_type)); - } - - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, allow_local); - return res; - } - } else if (is_type_simd_vector(type)) { - ast_node(cl, CompoundLit, value.value_compound); - - Type *elem_type = type->SimdVector.elem; - isize elem_count = cl->elems.count; - if (elem_count == 0) { - return lb_const_nil(m, original_type); - } - GB_ASSERT(elem_type_can_be_constant(elem_type)); - - isize total_elem_count = cast(isize)type->SimdVector.count; - LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, total_elem_count); - - for (isize i = 0; i < elem_count; i++) { - TypeAndValue tav = cl->elems[i]->tav; - GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value; - } - LLVMTypeRef et = lb_type(m, elem_type); - - for (isize i = elem_count; i < type->SimdVector.count; i++) { - values[i] = LLVMConstNull(et); - } - for (isize i = 0; i < total_elem_count; i++) { - values[i] = llvm_const_cast(values[i], et); - } - - res.value = LLVMConstVector(values, cast(unsigned)total_elem_count); - return res; - } else if (is_type_struct(type)) { - ast_node(cl, CompoundLit, value.value_compound); - - if (cl->elems.count == 0) { - return lb_const_nil(m, original_type); - } - - if (is_type_raw_union(type)) { - return lb_const_nil(m, original_type); - } - - isize offset = 0; - if (type->Struct.custom_align > 0) { - offset = 1; - } - - isize value_count = type->Struct.fields.count + offset; - LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, value_count); - bool *visited = gb_alloc_array(temporary_allocator(), bool, value_count); - - if (cl->elems.count > 0) { - if (cl->elems[0]->kind == Ast_FieldValue) { - isize elem_count = cl->elems.count; - for (isize i = 0; i < elem_count; i++) { - ast_node(fv, FieldValue, cl->elems[i]); - String name = fv->field->Ident.token.string; - - TypeAndValue tav = fv->value->tav; - GB_ASSERT(tav.mode != Addressing_Invalid); - - Selection sel = lookup_field(type, name, false); - Entity *f = type->Struct.fields[sel.index[0]]; - if (elem_type_can_be_constant(f->type)) { - values[offset+f->Variable.field_index] = lb_const_value(m, f->type, tav.value, allow_local).value; - visited[offset+f->Variable.field_index] = true; - } - } - } else { - for_array(i, cl->elems) { - Entity *f = type->Struct.fields[i]; - TypeAndValue tav = cl->elems[i]->tav; - ExactValue val = {}; - if (tav.mode != Addressing_Invalid) { - val = tav.value; - } - if (elem_type_can_be_constant(f->type)) { - values[offset+f->Variable.field_index] = lb_const_value(m, f->type, val, allow_local).value; - visited[offset+f->Variable.field_index] = true; - } - } - } - } - - for (isize i = 0; i < type->Struct.fields.count; i++) { - if (!visited[offset+i]) { - GB_ASSERT(values[offset+i] == nullptr); - values[offset+i] = lb_const_nil(m, get_struct_field_type(type, i)).value; - } - } - - if (type->Struct.custom_align > 0) { - values[0] = LLVMConstNull(lb_alignment_prefix_type_hack(m, type->Struct.custom_align)); - } - - bool is_constant = true; - - for (isize i = 0; i < value_count; i++) { - LLVMValueRef val = values[i]; - if (!LLVMIsConstant(val)) { - GB_ASSERT(is_local); - GB_ASSERT(LLVMGetInstructionOpcode(val) == LLVMLoad); - is_constant = false; - } - } - - if (is_constant) { - res.value = llvm_const_named_struct(lb_type(m, original_type), values, cast(unsigned)value_count); - return res; - } else { - // TODO(bill): THIS IS HACK BUT IT WORKS FOR WHAT I NEED - LLVMValueRef *old_values = values; - LLVMValueRef *new_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, value_count); - for (isize i = 0; i < value_count; i++) { - LLVMValueRef old_value = old_values[i]; - if (LLVMIsConstant(old_value)) { - new_values[i] = old_value; - } else { - new_values[i] = LLVMConstNull(LLVMTypeOf(old_value)); - } - } - LLVMValueRef constant_value = llvm_const_named_struct(lb_type(m, original_type), new_values, cast(unsigned)value_count); - - - GB_ASSERT(is_local); - lbProcedure *p = m->curr_procedure; - lbAddr v = lb_add_local_generated(p, res.type, true); - LLVMBuildStore(p->builder, constant_value, v.addr.value); - for (isize i = 0; i < value_count; i++) { - LLVMValueRef val = old_values[i]; - if (!LLVMIsConstant(val)) { - LLVMValueRef dst = LLVMBuildStructGEP(p->builder, v.addr.value, cast(unsigned)i, ""); - LLVMBuildStore(p->builder, val, dst); - } - } - return lb_addr_load(p, v); - - } - } else if (is_type_bit_set(type)) { - ast_node(cl, CompoundLit, value.value_compound); - if (cl->elems.count == 0) { - return lb_const_nil(m, original_type); - } - - i64 sz = type_size_of(type); - if (sz == 0) { - return lb_const_nil(m, original_type); - } - - u64 bits = 0; - for_array(i, cl->elems) { - Ast *e = cl->elems[i]; - GB_ASSERT(e->kind != Ast_FieldValue); - - TypeAndValue tav = e->tav; - if (tav.mode != Addressing_Constant) { - continue; - } - GB_ASSERT(tav.value.kind == ExactValue_Integer); - i64 v = big_int_to_i64(&tav.value.value_integer); - i64 lower = type->BitSet.lower; - bits |= 1ull<<cast(u64)(v-lower); - } - if (is_type_different_to_arch_endianness(type)) { - i64 size = type_size_of(type); - switch (size) { - case 2: bits = cast(u64)gb_endian_swap16(cast(u16)bits); break; - case 4: bits = cast(u64)gb_endian_swap32(cast(u32)bits); break; - case 8: bits = cast(u64)gb_endian_swap64(cast(u64)bits); break; - } - } - - res.value = LLVMConstInt(lb_type(m, original_type), bits, false); - return res; - } else { - return lb_const_nil(m, original_type); - } - break; - case ExactValue_Procedure: - { - Ast *expr = value.value_procedure; - GB_ASSERT(expr != nullptr); - if (expr->kind == Ast_ProcLit) { - return lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr); - } - } - break; - case ExactValue_Typeid: - return lb_typeid(m, value.value_typeid); - } - - return lb_const_nil(m, original_type); -} - -lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, TokenPos const &pos) { - lbModule *m = p->module; - - LLVMValueRef fields[4] = {}; - fields[0]/*file*/ = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)).value; - fields[1]/*line*/ = lb_const_int(m, t_i32, pos.line).value; - fields[2]/*column*/ = lb_const_int(m, t_i32, pos.column).value; - fields[3]/*procedure*/ = lb_find_or_add_entity_string(p->module, procedure).value; - - lbValue res = {}; - res.value = llvm_const_named_struct(lb_type(m, t_source_code_location), fields, gb_count_of(fields)); - res.type = t_source_code_location; - return res; -} - -lbValue lb_emit_source_code_location(lbProcedure *p, Ast *node) { - String proc_name = {}; - if (p->entity) { - proc_name = p->entity->token.string; - } - TokenPos pos = {}; - if (node) { - pos = ast_token(node).pos; - } - return lb_emit_source_code_location(p, proc_name, pos); -} - - -lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type) { - switch (op) { - case Token_Add: - return x; - case Token_Not: // Boolean not - case Token_Xor: // Bitwise not - case Token_Sub: // Number negation - break; - case Token_Pointer: - GB_PANIC("This should be handled elsewhere"); - break; - } - - if (is_type_array_like(x.type)) { - // IMPORTANT TODO(bill): This is very wasteful with regards to stack memory - Type *tl = base_type(x.type); - lbValue val = lb_address_from_load_or_generate_local(p, x); - GB_ASSERT(is_type_array_like(type)); - Type *elem_type = base_array_type(type); - - // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops - lbAddr res_addr = lb_add_local(p, type, nullptr, false, 0, true); - lbValue res = lb_addr_get_ptr(p, res_addr); - - bool inline_array_arith = type_size_of(type) <= build_context.max_align; - - i32 count = cast(i32)get_array_type_count(tl); - - LLVMTypeRef vector_type = nullptr; - if (op != Token_Not && lb_try_vector_cast(p->module, val, &vector_type)) { - LLVMValueRef vp = LLVMBuildPointerCast(p->builder, val.value, LLVMPointerType(vector_type, 0), ""); - LLVMValueRef v = LLVMBuildLoad2(p->builder, vector_type, vp, ""); - - LLVMValueRef opv = nullptr; - switch (op) { - case Token_Xor: - opv = LLVMBuildNot(p->builder, v, ""); - break; - case Token_Sub: - if (is_type_float(elem_type)) { - opv = LLVMBuildFNeg(p->builder, v, ""); - } else { - opv = LLVMBuildNeg(p->builder, v, ""); - } - break; - } - - if (opv != nullptr) { - LLVMSetAlignment(res.value, cast(unsigned)lb_alignof(vector_type)); - LLVMValueRef res_ptr = LLVMBuildPointerCast(p->builder, res.value, LLVMPointerType(vector_type, 0), ""); - LLVMBuildStore(p->builder, opv, res_ptr); - return lb_emit_conv(p, lb_emit_load(p, res), type); - } - } - - if (inline_array_arith) { - // inline - for (i32 i = 0; i < count; i++) { - lbValue e = lb_emit_load(p, lb_emit_array_epi(p, val, i)); - lbValue z = lb_emit_unary_arith(p, op, e, elem_type); - lb_emit_store(p, lb_emit_array_epi(p, res, i), z); - } - } else { - auto loop_data = lb_loop_start(p, count, t_i32); - - lbValue e = lb_emit_load(p, lb_emit_array_ep(p, val, loop_data.idx)); - lbValue z = lb_emit_unary_arith(p, op, e, elem_type); - lb_emit_store(p, lb_emit_array_ep(p, res, loop_data.idx), z); - - lb_loop_end(p, loop_data); - } - return lb_emit_load(p, res); - - } - - if (op == Token_Xor) { - lbValue cmp = {}; - cmp.value = LLVMBuildNot(p->builder, x.value, ""); - cmp.type = x.type; - return lb_emit_conv(p, cmp, type); - } - - if (op == Token_Not) { - lbValue cmp = {}; - LLVMValueRef zero = LLVMConstInt(lb_type(p->module, x.type), 0, false); - cmp.value = LLVMBuildICmp(p->builder, LLVMIntEQ, x.value, zero, ""); - cmp.type = t_llvm_bool; - return lb_emit_conv(p, cmp, type); - } - - if (op == Token_Sub && is_type_integer(type) && is_type_different_to_arch_endianness(type)) { - Type *platform_type = integer_endian_type_to_platform_type(type); - lbValue v = lb_emit_byte_swap(p, x, platform_type); - - lbValue res = {}; - res.value = LLVMBuildNeg(p->builder, v.value, ""); - res.type = platform_type; - - return lb_emit_byte_swap(p, res, type); - } - - if (op == Token_Sub && is_type_float(type) && is_type_different_to_arch_endianness(type)) { - Type *platform_type = integer_endian_type_to_platform_type(type); - lbValue v = lb_emit_byte_swap(p, x, platform_type); - - lbValue res = {}; - res.value = LLVMBuildFNeg(p->builder, v.value, ""); - res.type = platform_type; - - return lb_emit_byte_swap(p, res, type); - } - - lbValue res = {}; - - switch (op) { - case Token_Not: // Boolean not - case Token_Xor: // Bitwise not - res.value = LLVMBuildNot(p->builder, x.value, ""); - res.type = x.type; - return res; - case Token_Sub: // Number negation - if (is_type_integer(x.type)) { - res.value = LLVMBuildNeg(p->builder, x.value, ""); - } else if (is_type_float(x.type)) { - res.value = LLVMBuildFNeg(p->builder, x.value, ""); - } else if (is_type_complex(x.type)) { - LLVMValueRef v0 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 0, ""), ""); - LLVMValueRef v1 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 1, ""), ""); - - lbAddr addr = lb_add_local_generated(p, x.type, false); - LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP(p->builder, addr.addr.value, 0, "")); - LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP(p->builder, addr.addr.value, 1, "")); - return lb_addr_load(p, addr); - - } else if (is_type_quaternion(x.type)) { - LLVMValueRef v0 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 0, ""), ""); - LLVMValueRef v1 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 1, ""), ""); - LLVMValueRef v2 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 2, ""), ""); - LLVMValueRef v3 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 3, ""), ""); - - lbAddr addr = lb_add_local_generated(p, x.type, false); - LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP(p->builder, addr.addr.value, 0, "")); - LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP(p->builder, addr.addr.value, 1, "")); - LLVMBuildStore(p->builder, v2, LLVMBuildStructGEP(p->builder, addr.addr.value, 2, "")); - LLVMBuildStore(p->builder, v3, LLVMBuildStructGEP(p->builder, addr.addr.value, 3, "")); - return lb_addr_load(p, addr); - - } else { - GB_PANIC("Unhandled type %s", type_to_string(x.type)); - } - res.type = x.type; - return res; - } - - return res; -} - -bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, lbValue *res_) { - GB_ASSERT(is_type_array_like(type)); - Type *elem_type = base_array_type(type); - - // NOTE(bill): Shift operations cannot be easily dealt with due to Odin's semantics - if (op == Token_Shl || op == Token_Shr) { - return false; - } - - if (!LLVMIsALoadInst(lhs.value) || !LLVMIsALoadInst(rhs.value)) { - return false; - } - - lbValue lhs_ptr = {}; - lbValue rhs_ptr = {}; - lhs_ptr.value = LLVMGetOperand(lhs.value, 0); - lhs_ptr.type = alloc_type_pointer(lhs.type); - rhs_ptr.value = LLVMGetOperand(rhs.value, 0); - rhs_ptr.type = alloc_type_pointer(rhs.type); - - LLVMTypeRef vector_type0 = nullptr; - LLVMTypeRef vector_type1 = nullptr; - if (lb_try_vector_cast(p->module, lhs_ptr, &vector_type0) && - lb_try_vector_cast(p->module, rhs_ptr, &vector_type1)) { - GB_ASSERT(vector_type0 == vector_type1); - LLVMTypeRef vector_type = vector_type0; - - LLVMValueRef lhs_vp = LLVMBuildPointerCast(p->builder, lhs_ptr.value, LLVMPointerType(vector_type, 0), ""); - LLVMValueRef rhs_vp = LLVMBuildPointerCast(p->builder, rhs_ptr.value, LLVMPointerType(vector_type, 0), ""); - LLVMValueRef x = LLVMBuildLoad2(p->builder, vector_type, lhs_vp, ""); - LLVMValueRef y = LLVMBuildLoad2(p->builder, vector_type, rhs_vp, ""); - LLVMValueRef z = nullptr; - - Type *integral_type = base_type(elem_type); - if (is_type_simd_vector(integral_type)) { - integral_type = core_array_type(integral_type); - } - if (is_type_bit_set(integral_type)) { - switch (op) { - case Token_Add: op = Token_Or; break; - case Token_Sub: op = Token_AndNot; break; - } - } - - if (is_type_float(integral_type)) { - switch (op) { - case Token_Add: - z = LLVMBuildFAdd(p->builder, x, y, ""); - break; - case Token_Sub: - z = LLVMBuildFSub(p->builder, x, y, ""); - break; - case Token_Mul: - z = LLVMBuildFMul(p->builder, x, y, ""); - break; - case Token_Quo: - z = LLVMBuildFDiv(p->builder, x, y, ""); - break; - case Token_Mod: - z = LLVMBuildFRem(p->builder, x, y, ""); - break; - default: - GB_PANIC("Unsupported vector operation"); - break; - } - - } else { - - switch (op) { - case Token_Add: - z = LLVMBuildAdd(p->builder, x, y, ""); - break; - case Token_Sub: - z = LLVMBuildSub(p->builder, x, y, ""); - break; - case Token_Mul: - z = LLVMBuildMul(p->builder, x, y, ""); - break; - case Token_Quo: - if (is_type_unsigned(integral_type)) { - z = LLVMBuildUDiv(p->builder, x, y, ""); - } else { - z = LLVMBuildSDiv(p->builder, x, y, ""); - } - break; - case Token_Mod: - if (is_type_unsigned(integral_type)) { - z = LLVMBuildURem(p->builder, x, y, ""); - } else { - z = LLVMBuildSRem(p->builder, x, y, ""); - } - break; - case Token_ModMod: - if (is_type_unsigned(integral_type)) { - z = LLVMBuildURem(p->builder, x, y, ""); - } else { - LLVMValueRef a = LLVMBuildSRem(p->builder, x, y, ""); - LLVMValueRef b = LLVMBuildAdd(p->builder, a, y, ""); - z = LLVMBuildSRem(p->builder, b, y, ""); - } - break; - case Token_And: - z = LLVMBuildAnd(p->builder, x, y, ""); - break; - case Token_AndNot: - z = LLVMBuildAnd(p->builder, x, LLVMBuildNot(p->builder, y, ""), ""); - break; - case Token_Or: - z = LLVMBuildOr(p->builder, x, y, ""); - break; - case Token_Xor: - z = LLVMBuildXor(p->builder, x, y, ""); - break; - default: - GB_PANIC("Unsupported vector operation"); - break; - } - } - - - if (z != nullptr) { - lbAddr res = lb_add_local_generated_temp(p, type, lb_alignof(vector_type)); - - LLVMValueRef vp = LLVMBuildPointerCast(p->builder, res.addr.value, LLVMPointerType(vector_type, 0), ""); - LLVMBuildStore(p->builder, z, vp); - lbValue v = lb_addr_load(p, res); - if (res_) *res_ = v; - return true; - } - } - - return false; -} - - -lbValue lb_emit_arith_array(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) { - GB_ASSERT(is_type_array_like(lhs.type) || is_type_array_like(rhs.type)); - - lhs = lb_emit_conv(p, lhs, type); - rhs = lb_emit_conv(p, rhs, type); - - GB_ASSERT(is_type_array_like(type)); - Type *elem_type = base_array_type(type); - - i64 count = get_array_type_count(type); - unsigned n = cast(unsigned)count; - - // NOTE(bill, 2021-06-12): Try to do a direct operation as a vector, if possible - lbValue direct_vector_res = {}; - if (lb_try_direct_vector_arith(p, op, lhs, rhs, type, &direct_vector_res)) { - return direct_vector_res; - } - - bool inline_array_arith = type_size_of(type) <= build_context.max_align; - if (inline_array_arith) { - - auto dst_ptrs = slice_make<lbValue>(temporary_allocator(), n); - - auto a_loads = slice_make<lbValue>(temporary_allocator(), n); - auto b_loads = slice_make<lbValue>(temporary_allocator(), n); - auto c_ops = slice_make<lbValue>(temporary_allocator(), n); - - for (unsigned i = 0; i < n; i++) { - a_loads[i].value = LLVMBuildExtractValue(p->builder, lhs.value, i, ""); - a_loads[i].type = elem_type; - } - for (unsigned i = 0; i < n; i++) { - b_loads[i].value = LLVMBuildExtractValue(p->builder, rhs.value, i, ""); - b_loads[i].type = elem_type; - } - for (unsigned i = 0; i < n; i++) { - c_ops[i] = lb_emit_arith(p, op, a_loads[i], b_loads[i], elem_type); - } - - lbAddr res = lb_add_local_generated(p, type, false); - for (unsigned i = 0; i < n; i++) { - dst_ptrs[i] = lb_emit_array_epi(p, res.addr, i); - } - for (unsigned i = 0; i < n; i++) { - lb_emit_store(p, dst_ptrs[i], c_ops[i]); - } - - - return lb_addr_load(p, res); - } else { - lbValue x = lb_address_from_load_or_generate_local(p, lhs); - lbValue y = lb_address_from_load_or_generate_local(p, rhs); - - lbAddr res = lb_add_local_generated(p, type, false); - - auto loop_data = lb_loop_start(p, cast(isize)count, t_i32); - - lbValue a_ptr = lb_emit_array_ep(p, x, loop_data.idx); - lbValue b_ptr = lb_emit_array_ep(p, y, loop_data.idx); - lbValue dst_ptr = lb_emit_array_ep(p, res.addr, loop_data.idx); - - lbValue a = lb_emit_load(p, a_ptr); - lbValue b = lb_emit_load(p, b_ptr); - lbValue c = lb_emit_arith(p, op, a, b, elem_type); - lb_emit_store(p, dst_ptr, c); - - lb_loop_end(p, loop_data); - - return lb_addr_load(p, res); - } -} - - - -lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) { - lbModule *m = p->module; - - if (is_type_array_like(lhs.type) || is_type_array_like(rhs.type)) { - return lb_emit_arith_array(p, op, lhs, rhs, type); - } else if (is_type_complex(type)) { - lhs = lb_emit_conv(p, lhs, type); - rhs = lb_emit_conv(p, rhs, type); - - Type *ft = base_complex_elem_type(type); - - if (op == Token_Quo) { - auto args = array_make<lbValue>(permanent_allocator(), 2); - args[0] = lhs; - args[1] = rhs; - - switch (type_size_of(ft)) { - case 4: return lb_emit_runtime_call(p, "quo_complex64", args); - case 8: return lb_emit_runtime_call(p, "quo_complex128", args); - default: GB_PANIC("Unknown float type"); break; - } - } - - lbAddr res = lb_add_local_generated(p, type, false); // NOTE: initialized in full later - lbValue a = lb_emit_struct_ev(p, lhs, 0); - lbValue b = lb_emit_struct_ev(p, lhs, 1); - lbValue c = lb_emit_struct_ev(p, rhs, 0); - lbValue d = lb_emit_struct_ev(p, rhs, 1); - - lbValue real = {}; - lbValue imag = {}; - - switch (op) { - case Token_Add: - real = lb_emit_arith(p, Token_Add, a, c, ft); - imag = lb_emit_arith(p, Token_Add, b, d, ft); - break; - case Token_Sub: - real = lb_emit_arith(p, Token_Sub, a, c, ft); - imag = lb_emit_arith(p, Token_Sub, b, d, ft); - break; - case Token_Mul: { - lbValue x = lb_emit_arith(p, Token_Mul, a, c, ft); - lbValue y = lb_emit_arith(p, Token_Mul, b, d, ft); - real = lb_emit_arith(p, Token_Sub, x, y, ft); - lbValue z = lb_emit_arith(p, Token_Mul, b, c, ft); - lbValue w = lb_emit_arith(p, Token_Mul, a, d, ft); - imag = lb_emit_arith(p, Token_Add, z, w, ft); - break; - } - } - - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), real); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), imag); - - return lb_addr_load(p, res); - } else if (is_type_quaternion(type)) { - lhs = lb_emit_conv(p, lhs, type); - rhs = lb_emit_conv(p, rhs, type); - - Type *ft = base_complex_elem_type(type); - - if (op == Token_Add || op == Token_Sub) { - lbAddr res = lb_add_local_generated(p, type, false); // NOTE: initialized in full later - lbValue x0 = lb_emit_struct_ev(p, lhs, 0); - lbValue x1 = lb_emit_struct_ev(p, lhs, 1); - lbValue x2 = lb_emit_struct_ev(p, lhs, 2); - lbValue x3 = lb_emit_struct_ev(p, lhs, 3); - - lbValue y0 = lb_emit_struct_ev(p, rhs, 0); - lbValue y1 = lb_emit_struct_ev(p, rhs, 1); - lbValue y2 = lb_emit_struct_ev(p, rhs, 2); - lbValue y3 = lb_emit_struct_ev(p, rhs, 3); - - lbValue z0 = lb_emit_arith(p, op, x0, y0, ft); - lbValue z1 = lb_emit_arith(p, op, x1, y1, ft); - lbValue z2 = lb_emit_arith(p, op, x2, y2, ft); - lbValue z3 = lb_emit_arith(p, op, x3, y3, ft); - - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), z0); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), z1); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 2), z2); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 3), z3); - - return lb_addr_load(p, res); - } else if (op == Token_Mul) { - auto args = array_make<lbValue>(permanent_allocator(), 2); - args[0] = lhs; - args[1] = rhs; - - switch (8*type_size_of(ft)) { - case 32: return lb_emit_runtime_call(p, "mul_quaternion128", args); - case 64: return lb_emit_runtime_call(p, "mul_quaternion256", args); - default: GB_PANIC("Unknown float type"); break; - } - } else if (op == Token_Quo) { - auto args = array_make<lbValue>(permanent_allocator(), 2); - args[0] = lhs; - args[1] = rhs; - - switch (8*type_size_of(ft)) { - case 32: return lb_emit_runtime_call(p, "quo_quaternion128", args); - case 64: return lb_emit_runtime_call(p, "quo_quaternion256", args); - default: GB_PANIC("Unknown float type"); break; - } - } - } - - if (is_type_integer(type) && is_type_different_to_arch_endianness(type)) { - switch (op) { - case Token_AndNot: - case Token_And: - case Token_Or: - case Token_Xor: - goto handle_op; - } - - Type *platform_type = integer_endian_type_to_platform_type(type); - lbValue x = lb_emit_byte_swap(p, lhs, integer_endian_type_to_platform_type(lhs.type)); - lbValue y = lb_emit_byte_swap(p, rhs, integer_endian_type_to_platform_type(rhs.type)); - - lbValue res = lb_emit_arith(p, op, x, y, platform_type); - - return lb_emit_byte_swap(p, res, type); - } - - if (is_type_float(type) && is_type_different_to_arch_endianness(type)) { - Type *platform_type = integer_endian_type_to_platform_type(type); - lbValue x = lb_emit_conv(p, lhs, integer_endian_type_to_platform_type(lhs.type)); - lbValue y = lb_emit_conv(p, rhs, integer_endian_type_to_platform_type(rhs.type)); - - lbValue res = lb_emit_arith(p, op, x, y, platform_type); - - return lb_emit_byte_swap(p, res, type); - } - - - -handle_op: - lhs = lb_emit_conv(p, lhs, type); - rhs = lb_emit_conv(p, rhs, type); - - lbValue res = {}; - res.type = type; - - // NOTE(bill): Bit Set Aliases for + and - - if (is_type_bit_set(type)) { - switch (op) { - case Token_Add: op = Token_Or; break; - case Token_Sub: op = Token_AndNot; break; - } - } - - Type *integral_type = type; - if (is_type_simd_vector(integral_type)) { - integral_type = core_array_type(integral_type); - } - - switch (op) { - case Token_Add: - if (is_type_float(integral_type)) { - res.value = LLVMBuildFAdd(p->builder, lhs.value, rhs.value, ""); - return res; - } - res.value = LLVMBuildAdd(p->builder, lhs.value, rhs.value, ""); - return res; - case Token_Sub: - if (is_type_float(integral_type)) { - res.value = LLVMBuildFSub(p->builder, lhs.value, rhs.value, ""); - return res; - } - res.value = LLVMBuildSub(p->builder, lhs.value, rhs.value, ""); - return res; - case Token_Mul: - if (is_type_float(integral_type)) { - res.value = LLVMBuildFMul(p->builder, lhs.value, rhs.value, ""); - return res; - } - res.value = LLVMBuildMul(p->builder, lhs.value, rhs.value, ""); - return res; - case Token_Quo: - if (is_type_float(integral_type)) { - res.value = LLVMBuildFDiv(p->builder, lhs.value, rhs.value, ""); - return res; - } else if (is_type_unsigned(integral_type)) { - res.value = LLVMBuildUDiv(p->builder, lhs.value, rhs.value, ""); - return res; - } - res.value = LLVMBuildSDiv(p->builder, lhs.value, rhs.value, ""); - return res; - case Token_Mod: - if (is_type_float(integral_type)) { - res.value = LLVMBuildFRem(p->builder, lhs.value, rhs.value, ""); - return res; - } else if (is_type_unsigned(integral_type)) { - res.value = LLVMBuildURem(p->builder, lhs.value, rhs.value, ""); - return res; - } - res.value = LLVMBuildSRem(p->builder, lhs.value, rhs.value, ""); - return res; - case Token_ModMod: - if (is_type_unsigned(integral_type)) { - res.value = LLVMBuildURem(p->builder, lhs.value, rhs.value, ""); - return res; - } else { - LLVMValueRef a = LLVMBuildSRem(p->builder, lhs.value, rhs.value, ""); - LLVMValueRef b = LLVMBuildAdd(p->builder, a, rhs.value, ""); - LLVMValueRef c = LLVMBuildSRem(p->builder, b, rhs.value, ""); - res.value = c; - return res; - } - - case Token_And: - res.value = LLVMBuildAnd(p->builder, lhs.value, rhs.value, ""); - return res; - case Token_Or: - res.value = LLVMBuildOr(p->builder, lhs.value, rhs.value, ""); - return res; - case Token_Xor: - res.value = LLVMBuildXor(p->builder, lhs.value, rhs.value, ""); - return res; - case Token_Shl: - { - rhs = lb_emit_conv(p, rhs, lhs.type); - LLVMValueRef lhsval = lhs.value; - LLVMValueRef bits = rhs.value; - - LLVMValueRef bit_size = LLVMConstInt(lb_type(p->module, rhs.type), 8*type_size_of(lhs.type), false); - - LLVMValueRef width_test = LLVMBuildICmp(p->builder, LLVMIntULT, bits, bit_size, ""); - - res.value = LLVMBuildShl(p->builder, lhsval, bits, ""); - LLVMValueRef zero = LLVMConstNull(lb_type(p->module, lhs.type)); - res.value = LLVMBuildSelect(p->builder, width_test, res.value, zero, ""); - return res; - } - case Token_Shr: - { - rhs = lb_emit_conv(p, rhs, lhs.type); - LLVMValueRef lhsval = lhs.value; - LLVMValueRef bits = rhs.value; - bool is_unsigned = is_type_unsigned(integral_type); - - LLVMValueRef bit_size = LLVMConstInt(lb_type(p->module, rhs.type), 8*type_size_of(lhs.type), false); - - LLVMValueRef width_test = LLVMBuildICmp(p->builder, LLVMIntULT, bits, bit_size, ""); - - if (is_unsigned) { - res.value = LLVMBuildLShr(p->builder, lhsval, bits, ""); - } else { - res.value = LLVMBuildAShr(p->builder, lhsval, bits, ""); - } - - LLVMValueRef zero = LLVMConstNull(lb_type(p->module, lhs.type)); - res.value = LLVMBuildSelect(p->builder, width_test, res.value, zero, ""); - return res; - } - case Token_AndNot: - { - LLVMValueRef new_rhs = LLVMBuildNot(p->builder, rhs.value, ""); - res.value = LLVMBuildAnd(p->builder, lhs.value, new_rhs, ""); - return res; - } - break; - } - - GB_PANIC("unhandled operator of lb_emit_arith"); - - return {}; -} - -lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { - ast_node(be, BinaryExpr, expr); - - TypeAndValue tv = type_and_value_of_expr(expr); - - switch (be->op.kind) { - case Token_Add: - case Token_Sub: - case Token_Mul: - case Token_Quo: - case Token_Mod: - case Token_ModMod: - case Token_And: - case Token_Or: - case Token_Xor: - case Token_AndNot: { - Type *type = default_type(tv.type); - lbValue left = lb_build_expr(p, be->left); - lbValue right = lb_build_expr(p, be->right); - return lb_emit_arith(p, be->op.kind, left, right, type); - } - - case Token_Shl: - case Token_Shr: { - lbValue left, right; - Type *type = default_type(tv.type); - left = lb_build_expr(p, be->left); - - if (lb_is_expr_untyped_const(be->right)) { - // NOTE(bill): RHS shift operands can still be untyped - // Just bypass the standard lb_build_expr - right = lb_expr_untyped_const_to_typed(p->module, be->right, type); - } else { - right = lb_build_expr(p, be->right); - } - return lb_emit_arith(p, be->op.kind, left, right, type); - } - - case Token_CmpEq: - case Token_NotEq: - if (is_type_untyped_nil(be->right->tav.type)) { - lbValue left = lb_build_expr(p, be->left); - lbValue cmp = lb_emit_comp_against_nil(p, be->op.kind, left); - Type *type = default_type(tv.type); - return lb_emit_conv(p, cmp, type); - } else if (is_type_untyped_nil(be->left->tav.type)) { - lbValue right = lb_build_expr(p, be->right); - lbValue cmp = lb_emit_comp_against_nil(p, be->op.kind, right); - Type *type = default_type(tv.type); - return lb_emit_conv(p, cmp, type); - } - /*fallthrough*/ - case Token_Lt: - case Token_LtEq: - case Token_Gt: - case Token_GtEq: - { - lbValue left = {}; - lbValue right = {}; - - if (be->left->tav.mode == Addressing_Type) { - left = lb_typeid(p->module, be->left->tav.type); - } - if (be->right->tav.mode == Addressing_Type) { - right = lb_typeid(p->module, be->right->tav.type); - } - if (left.value == nullptr) left = lb_build_expr(p, be->left); - if (right.value == nullptr) right = lb_build_expr(p, be->right); - lbValue cmp = lb_emit_comp(p, be->op.kind, left, right); - Type *type = default_type(tv.type); - return lb_emit_conv(p, cmp, type); - } - - case Token_CmpAnd: - case Token_CmpOr: - return lb_emit_logical_binary_expr(p, be->op.kind, be->left, be->right, tv.type); - - case Token_in: - case Token_not_in: - { - lbValue left = lb_build_expr(p, be->left); - Type *type = default_type(tv.type); - lbValue right = lb_build_expr(p, be->right); - Type *rt = base_type(right.type); - if (is_type_pointer(rt)) { - right = lb_emit_load(p, right); - rt = type_deref(rt); - } - - switch (rt->kind) { - case Type_Map: - { - lbValue addr = lb_address_from_load_or_generate_local(p, right); - lbValue h = lb_gen_map_header(p, addr, rt); - lbValue key = lb_gen_map_hash(p, left, rt->Map.key); - - auto args = array_make<lbValue>(permanent_allocator(), 2); - args[0] = h; - args[1] = key; - - lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); - if (be->op.kind == Token_in) { - return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); - } else { - return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_CmpEq, ptr), t_bool); - } - } - break; - case Type_BitSet: - { - Type *key_type = rt->BitSet.elem; - GB_ASSERT(are_types_identical(left.type, key_type)); - - Type *it = bit_set_to_int(rt); - left = lb_emit_conv(p, left, it); - - lbValue lower = lb_const_value(p->module, it, exact_value_i64(rt->BitSet.lower)); - lbValue key = lb_emit_arith(p, Token_Sub, left, lower, it); - lbValue bit = lb_emit_arith(p, Token_Shl, lb_const_int(p->module, it, 1), key, it); - bit = lb_emit_conv(p, bit, it); - - lbValue old_value = lb_emit_transmute(p, right, it); - lbValue new_value = lb_emit_arith(p, Token_And, old_value, bit, it); - - if (be->op.kind == Token_in) { - return lb_emit_conv(p, lb_emit_comp(p, Token_NotEq, new_value, lb_const_int(p->module, new_value.type, 0)), t_bool); - } else { - return lb_emit_conv(p, lb_emit_comp(p, Token_CmpEq, new_value, lb_const_int(p->module, new_value.type, 0)), t_bool); - } - } - break; - default: - GB_PANIC("Invalid 'in' type"); - } - break; - } - break; - default: - GB_PANIC("Invalid binary expression"); - break; - } - return {}; -} - - -String lookup_subtype_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) { - Type *prev_src = src; - // Type *prev_dst = dst; - src = base_type(type_deref(src)); - // dst = base_type(type_deref(dst)); - bool src_is_ptr = src != prev_src; - // bool dst_is_ptr = dst != prev_dst; - - GB_ASSERT(is_type_struct(src) || is_type_union(src)); - for_array(i, src->Struct.fields) { - Entity *f = src->Struct.fields[i]; - if (f->kind == Entity_Variable && f->flags & EntityFlag_Using) { - if (are_types_identical(dst, f->type)) { - return f->token.string; - } - if (src_is_ptr && is_type_pointer(dst)) { - if (are_types_identical(type_deref(dst), f->type)) { - return f->token.string; - } - } - if (is_type_struct(f->type)) { - String name = lookup_subtype_polymorphic_field(info, dst, f->type); - if (name.len > 0) { - return name; - } - } - } - } - return str_lit(""); -} - -lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) { - GB_ASSERT(is_type_pointer(value.type)); - GB_ASSERT(is_type_pointer(t)); - GB_ASSERT(lb_is_const(value)); - - lbValue res = {}; - res.value = LLVMConstPointerCast(value.value, lb_type(m, t)); - res.type = t; - return res; -} - -lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { - lbModule *m = p->module; - t = reduce_tuple_to_single_type(t); - - Type *src_type = value.type; - if (are_types_identical(t, src_type)) { - return value; - } - - Type *src = core_type(src_type); - Type *dst = core_type(t); - GB_ASSERT(src != nullptr); - GB_ASSERT(dst != nullptr); - - if (is_type_untyped_nil(src)) { - return lb_const_nil(m, t); - } - if (is_type_untyped_undef(src)) { - return lb_const_undef(m, t); - } - - if (LLVMIsConstant(value.value)) { - if (is_type_any(dst)) { - Type *st = default_type(src_type); - lbAddr default_value = lb_add_local_generated(p, st, false); - lb_addr_store(p, default_value, value); - lbValue data = lb_emit_conv(p, default_value.addr, t_rawptr); - lbValue id = lb_typeid(m, st); - - lbAddr res = lb_add_local_generated(p, t, false); - lbValue a0 = lb_emit_struct_ep(p, res.addr, 0); - lbValue a1 = lb_emit_struct_ep(p, res.addr, 1); - lb_emit_store(p, a0, data); - lb_emit_store(p, a1, id); - return lb_addr_load(p, res); - } else if (dst->kind == Type_Basic) { - if (src->Basic.kind == Basic_string && dst->Basic.kind == Basic_cstring) { - String str = lb_get_const_string(m, value); - lbValue res = {}; - res.type = t; - res.value = llvm_cstring(m, str); - return res; - } - // if (is_type_float(dst)) { - // return value; - // } else if (is_type_integer(dst)) { - // return value; - // } - // ExactValue ev = value->Constant.value; - // if (is_type_float(dst)) { - // ev = exact_value_to_float(ev); - // } else if (is_type_complex(dst)) { - // ev = exact_value_to_complex(ev); - // } else if (is_type_quaternion(dst)) { - // ev = exact_value_to_quaternion(ev); - // } else if (is_type_string(dst)) { - // // Handled elsewhere - // GB_ASSERT_MSG(ev.kind == ExactValue_String, "%d", ev.kind); - // } else if (is_type_integer(dst)) { - // ev = exact_value_to_integer(ev); - // } else if (is_type_pointer(dst)) { - // // IMPORTANT NOTE(bill): LLVM doesn't support pointer constants expect 'null' - // lbValue i = lb_add_module_constant(p->module, t_uintptr, ev); - // return lb_emit(p, lb_instr_conv(p, irConv_inttoptr, i, t_uintptr, dst)); - // } - // return lb_const_value(p->module, t, ev); - } - } - - if (are_types_identical(src, dst)) { - if (!are_types_identical(src_type, t)) { - return lb_emit_transmute(p, value, t); - } - return value; - } - - - - // bool <-> llvm bool - if (is_type_boolean(src) && dst == t_llvm_bool) { - lbValue res = {}; - res.value = LLVMBuildTrunc(p->builder, value.value, lb_type(m, dst), ""); - res.type = dst; - return res; - } - if (src == t_llvm_bool && is_type_boolean(dst)) { - lbValue res = {}; - res.value = LLVMBuildZExt(p->builder, value.value, lb_type(m, dst), ""); - res.type = dst; - return res; - } - - - // integer -> integer - if (is_type_integer(src) && is_type_integer(dst)) { - GB_ASSERT(src->kind == Type_Basic && - dst->kind == Type_Basic); - i64 sz = type_size_of(default_type(src)); - i64 dz = type_size_of(default_type(dst)); - - - if (sz == dz) { - if (dz > 1 && !types_have_same_internal_endian(src, dst)) { - return lb_emit_byte_swap(p, value, t); - } - lbValue res = {}; - res.value = value.value; - res.type = t; - return res; - } - - if (sz > 1 && is_type_different_to_arch_endianness(src)) { - Type *platform_src_type = integer_endian_type_to_platform_type(src); - value = lb_emit_byte_swap(p, value, platform_src_type); - } - LLVMOpcode op = LLVMTrunc; - - if (dz < sz) { - op = LLVMTrunc; - } else if (dz == sz) { - // NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment - // NOTE(bill): Copy the value just for type correctness - op = LLVMBitCast; - } else if (dz > sz) { - op = is_type_unsigned(src) ? LLVMZExt : LLVMSExt; // zero extent - } - - if (dz > 1 && is_type_different_to_arch_endianness(dst)) { - Type *platform_dst_type = integer_endian_type_to_platform_type(dst); - lbValue res = {}; - res.value = LLVMBuildCast(p->builder, op, value.value, lb_type(m, platform_dst_type), ""); - res.type = t; - return lb_emit_byte_swap(p, res, t); - } else { - lbValue res = {}; - res.value = LLVMBuildCast(p->builder, op, value.value, lb_type(m, t), ""); - res.type = t; - return res; - } - } - - - // boolean -> boolean/integer - if (is_type_boolean(src) && (is_type_boolean(dst) || is_type_integer(dst))) { - LLVMValueRef b = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, value.type)), ""); - lbValue res = {}; - res.value = LLVMBuildIntCast2(p->builder, value.value, lb_type(m, t), false, ""); - res.type = t; - return res; - } - - if (is_type_cstring(src) && is_type_u8_ptr(dst)) { - return lb_emit_transmute(p, value, dst); - } - if (is_type_u8_ptr(src) && is_type_cstring(dst)) { - return lb_emit_transmute(p, value, dst); - } - if (is_type_cstring(src) && is_type_rawptr(dst)) { - return lb_emit_transmute(p, value, dst); - } - if (is_type_rawptr(src) && is_type_cstring(dst)) { - return lb_emit_transmute(p, value, dst); - } - - if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) { - lbValue c = lb_emit_conv(p, value, t_cstring); - auto args = array_make<lbValue>(permanent_allocator(), 1); - args[0] = c; - lbValue s = lb_emit_runtime_call(p, "cstring_to_string", args); - return lb_emit_conv(p, s, dst); - } - - - // integer -> boolean - if (is_type_integer(src) && is_type_boolean(dst)) { - lbValue res = {}; - res.value = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, value.type)), ""); - res.type = t_llvm_bool; - return lb_emit_conv(p, res, t); - } - - // float -> float - if (is_type_float(src) && is_type_float(dst)) { - i64 sz = type_size_of(src); - i64 dz = type_size_of(dst); - - - if (dz == sz) { - if (types_have_same_internal_endian(src, dst)) { - lbValue res = {}; - res.type = t; - res.value = value.value; - return res; - } else { - return lb_emit_byte_swap(p, value, t); - } - } - - if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) { - Type *platform_src_type = integer_endian_type_to_platform_type(src); - Type *platform_dst_type = integer_endian_type_to_platform_type(dst); - lbValue res = {}; - res = lb_emit_conv(p, value, platform_src_type); - res = lb_emit_conv(p, res, platform_dst_type); - if (is_type_different_to_arch_endianness(dst)) { - res = lb_emit_byte_swap(p, res, t); - } - return lb_emit_conv(p, res, t); - } - - - lbValue res = {}; - res.type = t; - - if (dz >= sz) { - res.value = LLVMBuildFPExt(p->builder, value.value, lb_type(m, t), ""); - } else { - res.value = LLVMBuildFPTrunc(p->builder, value.value, lb_type(m, t), ""); - } - return res; - } - - if (is_type_complex(src) && is_type_complex(dst)) { - Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, dst, false); - lbValue gp = lb_addr_get_ptr(p, gen); - lbValue real = lb_emit_conv(p, lb_emit_struct_ev(p, value, 0), ft); - lbValue imag = lb_emit_conv(p, lb_emit_struct_ev(p, value, 1), ft); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 1), imag); - return lb_addr_load(p, gen); - } - - if (is_type_quaternion(src) && is_type_quaternion(dst)) { - // @QuaternionLayout - Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, dst, false); - lbValue gp = lb_addr_get_ptr(p, gen); - lbValue q0 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 0), ft); - lbValue q1 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 1), ft); - lbValue q2 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 2), ft); - lbValue q3 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 3), ft); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), q0); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 1), q1); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 2), q2); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), q3); - return lb_addr_load(p, gen); - } - - if (is_type_integer(src) && is_type_complex(dst)) { - Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, dst, true); - lbValue gp = lb_addr_get_ptr(p, gen); - lbValue real = lb_emit_conv(p, value, ft); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real); - return lb_addr_load(p, gen); - } - if (is_type_float(src) && is_type_complex(dst)) { - Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, dst, true); - lbValue gp = lb_addr_get_ptr(p, gen); - lbValue real = lb_emit_conv(p, value, ft); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real); - return lb_addr_load(p, gen); - } - - - if (is_type_integer(src) && is_type_quaternion(dst)) { - Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, dst, true); - lbValue gp = lb_addr_get_ptr(p, gen); - lbValue real = lb_emit_conv(p, value, ft); - // @QuaternionLayout - lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), real); - return lb_addr_load(p, gen); - } - if (is_type_float(src) && is_type_quaternion(dst)) { - Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, dst, true); - lbValue gp = lb_addr_get_ptr(p, gen); - lbValue real = lb_emit_conv(p, value, ft); - // @QuaternionLayout - lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), real); - return lb_addr_load(p, gen); - } - if (is_type_complex(src) && is_type_quaternion(dst)) { - Type *ft = base_complex_elem_type(dst); - lbAddr gen = lb_add_local_generated(p, dst, true); - lbValue gp = lb_addr_get_ptr(p, gen); - lbValue real = lb_emit_conv(p, lb_emit_struct_ev(p, value, 0), ft); - lbValue imag = lb_emit_conv(p, lb_emit_struct_ev(p, value, 1), ft); - // @QuaternionLayout - lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), real); - lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), imag); - return lb_addr_load(p, gen); - } - - // float <-> integer - if (is_type_float(src) && is_type_integer(dst)) { - if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) { - Type *platform_src_type = integer_endian_type_to_platform_type(src); - Type *platform_dst_type = integer_endian_type_to_platform_type(dst); - lbValue res = {}; - res = lb_emit_conv(p, value, platform_src_type); - res = lb_emit_conv(p, res, platform_dst_type); - if (is_type_different_to_arch_endianness(dst)) { - res = lb_emit_byte_swap(p, res, t); - } - return lb_emit_conv(p, res, t); - } - - lbValue res = {}; - res.type = t; - if (is_type_unsigned(dst)) { - res.value = LLVMBuildFPToUI(p->builder, value.value, lb_type(m, t), ""); - } else { - res.value = LLVMBuildFPToSI(p->builder, value.value, lb_type(m, t), ""); - } - return res; - } - if (is_type_integer(src) && is_type_float(dst)) { - if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) { - Type *platform_src_type = integer_endian_type_to_platform_type(src); - Type *platform_dst_type = integer_endian_type_to_platform_type(dst); - lbValue res = {}; - res = lb_emit_conv(p, value, platform_src_type); - res = lb_emit_conv(p, res, platform_dst_type); - if (is_type_different_to_arch_endianness(dst)) { - res = lb_emit_byte_swap(p, res, t); - } - return lb_emit_conv(p, res, t); - } - - if (is_type_integer_128bit(src)) { - auto args = array_make<lbValue>(temporary_allocator(), 1); - args[0] = value; - char const *call = "floattidf"; - if (is_type_unsigned(src)) { - call = "floattidf_unsigned"; - } - lbValue res_f64 = lb_emit_runtime_call(p, call, args); - return lb_emit_conv(p, res_f64, t); - } - - lbValue res = {}; - res.type = t; - if (is_type_unsigned(src)) { - res.value = LLVMBuildUIToFP(p->builder, value.value, lb_type(m, t), ""); - } else { - res.value = LLVMBuildSIToFP(p->builder, value.value, lb_type(m, t), ""); - } - return res; - } - - // Pointer <-> uintptr - if (is_type_pointer(src) && is_type_uintptr(dst)) { - lbValue res = {}; - res.type = t; - res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); - return res; - } - if (is_type_uintptr(src) && is_type_pointer(dst)) { - lbValue res = {}; - res.type = t; - res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); - return res; - } - -#if 1 - if (is_type_union(dst)) { - for_array(i, dst->Union.variants) { - Type *vt = dst->Union.variants[i]; - if (are_types_identical(vt, src_type)) { - lbAddr parent = lb_add_local_generated(p, t, true); - lb_emit_store_union_variant(p, parent.addr, value, vt); - return lb_addr_load(p, parent); - } - } - } -#endif - - // NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's - // subtype polymorphism casting - if (check_is_assignable_to_using_subtype(src_type, t)) { - Type *st = type_deref(src_type); - Type *pst = st; - st = type_deref(st); - - bool st_is_ptr = is_type_pointer(src_type); - st = base_type(st); - - Type *dt = t; - bool dt_is_ptr = type_deref(dt) != dt; - - GB_ASSERT(is_type_struct(st) || is_type_raw_union(st)); - String field_name = lookup_subtype_polymorphic_field(p->module->info, t, src_type); - if (field_name.len > 0) { - // NOTE(bill): It can be casted - Selection sel = lookup_field(st, field_name, false, true); - if (sel.entity != nullptr) { - if (st_is_ptr) { - lbValue res = lb_emit_deep_field_gep(p, value, sel); - Type *rt = res.type; - if (!are_types_identical(rt, dt) && are_types_identical(type_deref(rt), dt)) { - res = lb_emit_load(p, res); - } - return res; - } else { - if (is_type_pointer(value.type)) { - Type *rt = value.type; - if (!are_types_identical(rt, dt) && are_types_identical(type_deref(rt), dt)) { - value = lb_emit_load(p, value); - } else { - value = lb_emit_deep_field_gep(p, value, sel); - return lb_emit_load(p, value); - } - } - - return lb_emit_deep_field_ev(p, value, sel); - - } - } else { - GB_PANIC("invalid subtype cast %s.%.*s", type_to_string(src_type), LIT(field_name)); - } - } - } - - - - // Pointer <-> Pointer - if (is_type_pointer(src) && is_type_pointer(dst)) { - lbValue res = {}; - res.type = t; - res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); - return res; - } - - - - // proc <-> proc - if (is_type_proc(src) && is_type_proc(dst)) { - lbValue res = {}; - res.type = t; - res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); - return res; - } - - // pointer -> proc - if (is_type_pointer(src) && is_type_proc(dst)) { - lbValue res = {}; - res.type = t; - res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); - return res; - } - // proc -> pointer - if (is_type_proc(src) && is_type_pointer(dst)) { - lbValue res = {}; - res.type = t; - res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); - return res; - } - - // []byte/[]u8 <-> string - if (is_type_u8_slice(src) && is_type_string(dst)) { - return lb_emit_transmute(p, value, t); - } - if (is_type_string(src) && is_type_u8_slice(dst)) { - return lb_emit_transmute(p, value, t); - } - - if (is_type_array_like(dst)) { - Type *elem = base_array_type(dst); - lbValue e = lb_emit_conv(p, value, elem); - // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops - lbAddr v = lb_add_local_generated(p, t, false); - isize index_count = cast(isize)get_array_type_count(dst); - - for (isize i = 0; i < index_count; i++) { - lbValue elem = lb_emit_array_epi(p, v.addr, i); - lb_emit_store(p, elem, e); - } - return lb_addr_load(p, v); - } - - if (is_type_any(dst)) { - if (is_type_untyped_nil(src)) { - return lb_const_nil(p->module, t); - } - if (is_type_untyped_undef(src)) { - return lb_const_undef(p->module, t); - } - - lbAddr result = lb_add_local_generated(p, t, true); - - Type *st = default_type(src_type); - - lbValue data = lb_address_from_load_or_generate_local(p, value); - GB_ASSERT_MSG(is_type_pointer(data.type), "%s", type_to_string(data.type)); - GB_ASSERT_MSG(is_type_typed(st), "%s", type_to_string(st)); - data = lb_emit_conv(p, data, t_rawptr); - - lbValue id = lb_typeid(p->module, st); - lbValue any_data = lb_emit_struct_ep(p, result.addr, 0); - lbValue any_id = lb_emit_struct_ep(p, result.addr, 1); - - lb_emit_store(p, any_data, data); - lb_emit_store(p, any_id, id); - - return lb_addr_load(p, result); - } - - - i64 src_sz = type_size_of(src); - i64 dst_sz = type_size_of(dst); - - if (src_sz == dst_sz) { - // bit_set <-> integer - if (is_type_integer(src) && is_type_bit_set(dst)) { - lbValue res = lb_emit_conv(p, value, bit_set_to_int(dst)); - res.type = dst; - return res; - } - if (is_type_bit_set(src) && is_type_integer(dst)) { - lbValue bs = value; - bs.type = bit_set_to_int(src); - return lb_emit_conv(p, bs, dst); - } - - // typeid <-> integer - if (is_type_integer(src) && is_type_typeid(dst)) { - return lb_emit_transmute(p, value, dst); - } - if (is_type_typeid(src) && is_type_integer(dst)) { - return lb_emit_transmute(p, value, dst); - } - } - - - - if (is_type_untyped(src)) { - if (is_type_string(src) && is_type_string(dst)) { - lbAddr result = lb_add_local_generated(p, t, false); - lb_addr_store(p, result, value); - return lb_addr_load(p, result); - } - } - - gb_printf_err("%.*s\n", LIT(p->name)); - gb_printf_err("lb_emit_conv: src -> dst\n"); - gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t)); - gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst)); - gb_printf_err("Not Identical %p != %p\n", src_type, t); - gb_printf_err("Not Identical %p != %p\n", src, dst); - - - GB_PANIC("Invalid type conversion: '%s' to '%s' for procedure '%.*s'", - type_to_string(src_type), type_to_string(t), - LIT(p->name)); - - return {}; -} - -bool lb_is_type_aggregate(Type *t) { - t = base_type(t); - switch (t->kind) { - case Type_Basic: - switch (t->Basic.kind) { - case Basic_string: - case Basic_any: - return true; - - case Basic_complex32: - case Basic_complex64: - case Basic_complex128: - case Basic_quaternion64: - case Basic_quaternion128: - case Basic_quaternion256: - return true; - } - break; - - case Type_Pointer: - return false; - - case Type_Array: - case Type_Slice: - case Type_Struct: - case Type_Union: - case Type_Tuple: - case Type_DynamicArray: - case Type_Map: - case Type_SimdVector: - return true; - - case Type_Named: - return lb_is_type_aggregate(t->Named.base); - } - - return false; -} - -lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { - Type *src_type = value.type; - if (are_types_identical(t, src_type)) { - return value; - } - - lbValue res = {}; - res.type = t; - - - Type *src = base_type(src_type); - Type *dst = base_type(t); - - lbModule *m = p->module; - - i64 sz = type_size_of(src); - i64 dz = type_size_of(dst); - - if (sz != dz) { - LLVMTypeRef s = lb_type(m, src); - LLVMTypeRef d = lb_type(m, dst); - i64 llvm_sz = lb_sizeof(s); - i64 llvm_dz = lb_sizeof(d); - GB_ASSERT_MSG(llvm_sz == llvm_dz, "%s %s", LLVMPrintTypeToString(s), LLVMPrintTypeToString(d)); - } - - GB_ASSERT_MSG(sz == dz, "Invalid transmute conversion: '%s' to '%s'", type_to_string(src_type), type_to_string(t)); - - // NOTE(bill): Casting between an integer and a pointer cannot be done through a bitcast - if (is_type_uintptr(src) && is_type_pointer(dst)) { - res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); - return res; - } - if (is_type_pointer(src) && is_type_uintptr(dst)) { - res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); - return res; - } - if (is_type_uintptr(src) && is_type_proc(dst)) { - res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); - return res; - } - if (is_type_proc(src) && is_type_uintptr(dst)) { - res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); - return res; - } - - if (is_type_integer(src) && (is_type_pointer(dst) || is_type_cstring(dst))) { - res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); - return res; - } else if ((is_type_pointer(src) || is_type_cstring(src)) && is_type_integer(dst)) { - res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); - return res; - } - - if (is_type_pointer(src) && is_type_pointer(dst)) { - res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(p->module, t), ""); - return res; - } - - if (lb_is_type_aggregate(src) || lb_is_type_aggregate(dst)) { - lbValue s = lb_address_from_load_or_generate_local(p, value); - lbValue d = lb_emit_transmute(p, s, alloc_type_pointer(t)); - return lb_emit_load(p, d); - } - - res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), ""); - return res; -} - - void lb_emit_init_context(lbProcedure *p, lbAddr addr) { GB_ASSERT(addr.kind == lbAddr_Context); GB_ASSERT(addr.ctx.sel.index.count == 0); @@ -8653,2874 +117,6 @@ lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx) { } -lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) { - if (p->context_stack.count > 0) { - return p->context_stack[p->context_stack.count-1].ctx; - } - - Type *pt = base_type(p->type); - GB_ASSERT(pt->kind == Type_Proc); - GB_ASSERT(pt->Proc.calling_convention != ProcCC_Odin); - - lbAddr c = lb_add_local_generated(p, t_context, true); - c.kind = lbAddr_Context; - lb_emit_init_context(p, c); - lb_push_context_onto_stack(p, c); - lb_add_debug_context_variable(p, c); - - return c; -} - -lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value) { - if (LLVMIsALoadInst(value.value)) { - lbValue res = {}; - res.value = LLVMGetOperand(value.value, 0); - res.type = alloc_type_pointer(value.type); - return res; - } - - GB_ASSERT(is_type_typed(value.type)); - - lbAddr res = lb_add_local_generated(p, value.type, false); - lb_addr_store(p, res, value); - return res.addr; -} -lbValue lb_address_from_load(lbProcedure *p, lbValue value) { - if (LLVMIsALoadInst(value.value)) { - lbValue res = {}; - res.value = LLVMGetOperand(value.value, 0); - res.type = alloc_type_pointer(value.type); - return res; - } - - GB_PANIC("lb_address_from_load"); - return {}; -} - -lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 alignment) { - i64 type_alignment = type_align_of(new_type); - if (alignment < type_alignment) { - alignment = type_alignment; - } - GB_ASSERT_MSG(are_types_identical(new_type, val.type), "%s %s", type_to_string(new_type), type_to_string(val.type)); - - lbAddr ptr = lb_add_local_generated(p, new_type, false); - LLVMSetAlignment(ptr.addr.value, cast(unsigned)alignment); - lb_addr_store(p, ptr, val); - // ptr.kind = lbAddr_Context; - return ptr.addr; -} - -lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { - GB_ASSERT(is_type_pointer(s.type)); - Type *t = base_type(type_deref(s.type)); - Type *result_type = nullptr; - - if (is_type_relative_pointer(t)) { - s = lb_addr_get_ptr(p, lb_addr(s)); - } - - if (is_type_struct(t)) { - result_type = get_struct_field_type(t, index); - } else if (is_type_union(t)) { - GB_ASSERT(index == -1); - return lb_emit_union_tag_ptr(p, s); - } else if (is_type_tuple(t)) { - GB_ASSERT(t->Tuple.variables.count > 0); - result_type = t->Tuple.variables[index]->type; - } else if (is_type_complex(t)) { - Type *ft = base_complex_elem_type(t); - switch (index) { - case 0: result_type = ft; break; - case 1: result_type = ft; break; - } - } else if (is_type_quaternion(t)) { - Type *ft = base_complex_elem_type(t); - switch (index) { - case 0: result_type = ft; break; - case 1: result_type = ft; break; - case 2: result_type = ft; break; - case 3: result_type = ft; break; - } - } else if (is_type_slice(t)) { - switch (index) { - case 0: result_type = alloc_type_pointer(t->Slice.elem); break; - case 1: result_type = t_int; break; - } - } else if (is_type_string(t)) { - switch (index) { - case 0: result_type = t_u8_ptr; break; - case 1: result_type = t_int; break; - } - } else if (is_type_any(t)) { - switch (index) { - case 0: result_type = t_rawptr; break; - case 1: result_type = t_typeid; break; - } - } else if (is_type_dynamic_array(t)) { - switch (index) { - case 0: result_type = alloc_type_pointer(t->DynamicArray.elem); break; - case 1: result_type = t_int; break; - case 2: result_type = t_int; break; - case 3: result_type = t_allocator; break; - } - } else if (is_type_map(t)) { - init_map_internal_types(t); - Type *itp = alloc_type_pointer(t->Map.internal_type); - s = lb_emit_transmute(p, s, itp); - - Type *gst = t->Map.internal_type; - GB_ASSERT(gst->kind == Type_Struct); - switch (index) { - case 0: result_type = get_struct_field_type(gst, 0); break; - case 1: result_type = get_struct_field_type(gst, 1); break; - } - } else if (is_type_array(t)) { - return lb_emit_array_epi(p, s, index); - } else if (is_type_relative_slice(t)) { - switch (index) { - case 0: result_type = t->RelativeSlice.base_integer; break; - case 1: result_type = t->RelativeSlice.base_integer; break; - } - } else { - GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index); - } - - GB_ASSERT_MSG(result_type != nullptr, "%s %d", type_to_string(t), index); - - if (t->kind == Type_Struct && t->Struct.custom_align != 0) { - index += 1; - } - if (lb_is_const(s)) { - lbModule *m = p->module; - lbValue res = {}; - LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)}; - res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); - res.type = alloc_type_pointer(result_type); - return res; - } else { - lbValue res = {}; - res.value = LLVMBuildStructGEP(p->builder, s.value, cast(unsigned)index, ""); - res.type = alloc_type_pointer(result_type); - return res; - } -} - -lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { - if (LLVMIsALoadInst(s.value)) { - lbValue res = {}; - res.value = LLVMGetOperand(s.value, 0); - res.type = alloc_type_pointer(s.type); - lbValue ptr = lb_emit_struct_ep(p, res, index); - return lb_emit_load(p, ptr); - } - - Type *t = base_type(s.type); - Type *result_type = nullptr; - - switch (t->kind) { - case Type_Basic: - switch (t->Basic.kind) { - case Basic_string: - switch (index) { - case 0: result_type = t_u8_ptr; break; - case 1: result_type = t_int; break; - } - break; - case Basic_any: - switch (index) { - case 0: result_type = t_rawptr; break; - case 1: result_type = t_typeid; break; - } - break; - case Basic_complex32: - case Basic_complex64: - case Basic_complex128: - { - Type *ft = base_complex_elem_type(t); - switch (index) { - case 0: result_type = ft; break; - case 1: result_type = ft; break; - } - break; - } - case Basic_quaternion64: - case Basic_quaternion128: - case Basic_quaternion256: - { - Type *ft = base_complex_elem_type(t); - switch (index) { - case 0: result_type = ft; break; - case 1: result_type = ft; break; - case 2: result_type = ft; break; - case 3: result_type = ft; break; - } - break; - } - } - break; - case Type_Struct: - result_type = get_struct_field_type(t, index); - break; - case Type_Union: - GB_ASSERT(index == -1); - // return lb_emit_union_tag_value(p, s); - GB_PANIC("lb_emit_union_tag_value"); - - case Type_Tuple: - GB_ASSERT(t->Tuple.variables.count > 0); - result_type = t->Tuple.variables[index]->type; - if (t->Tuple.variables.count == 1) { - return s; - } - break; - case Type_Slice: - switch (index) { - case 0: result_type = alloc_type_pointer(t->Slice.elem); break; - case 1: result_type = t_int; break; - } - break; - case Type_DynamicArray: - switch (index) { - case 0: result_type = alloc_type_pointer(t->DynamicArray.elem); break; - case 1: result_type = t_int; break; - case 2: result_type = t_int; break; - case 3: result_type = t_allocator; break; - } - break; - - case Type_Map: - { - init_map_internal_types(t); - Type *gst = t->Map.generated_struct_type; - switch (index) { - case 0: result_type = get_struct_field_type(gst, 0); break; - case 1: result_type = get_struct_field_type(gst, 1); break; - } - } - break; - - case Type_Array: - result_type = t->Array.elem; - break; - - default: - GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s.type), index); - break; - } - - GB_ASSERT_MSG(result_type != nullptr, "%s, %d", type_to_string(s.type), index); - - if (t->kind == Type_Struct && t->Struct.custom_align != 0) { - index += 1; - } - - lbValue res = {}; - res.value = LLVMBuildExtractValue(p->builder, s.value, cast(unsigned)index, ""); - res.type = result_type; - return res; -} - -lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) { - GB_ASSERT(sel.index.count > 0); - Type *type = type_deref(e.type); - - for_array(i, sel.index) { - i32 index = cast(i32)sel.index[i]; - if (is_type_pointer(type)) { - type = type_deref(type); - e = lb_emit_load(p, e); - } - type = core_type(type); - - if (is_type_quaternion(type)) { - e = lb_emit_struct_ep(p, e, index); - } else if (is_type_raw_union(type)) { - type = get_struct_field_type(type, index); - GB_ASSERT(is_type_pointer(e.type)); - e = lb_emit_transmute(p, e, alloc_type_pointer(type)); - } else if (is_type_struct(type)) { - type = get_struct_field_type(type, index); - e = lb_emit_struct_ep(p, e, index); - } else if (type->kind == Type_Union) { - GB_ASSERT(index == -1); - type = t_type_info_ptr; - e = lb_emit_struct_ep(p, e, index); - } else if (type->kind == Type_Tuple) { - type = type->Tuple.variables[index]->type; - e = lb_emit_struct_ep(p, e, index); - } else if (type->kind == Type_Basic) { - switch (type->Basic.kind) { - case Basic_any: { - if (index == 0) { - type = t_rawptr; - } else if (index == 1) { - type = t_type_info_ptr; - } - e = lb_emit_struct_ep(p, e, index); - break; - } - - case Basic_string: - e = lb_emit_struct_ep(p, e, index); - break; - - default: - GB_PANIC("un-gep-able type %s", type_to_string(type)); - break; - } - } else if (type->kind == Type_Slice) { - e = lb_emit_struct_ep(p, e, index); - } else if (type->kind == Type_DynamicArray) { - e = lb_emit_struct_ep(p, e, index); - } else if (type->kind == Type_Array) { - e = lb_emit_array_epi(p, e, index); - } else if (type->kind == Type_Map) { - e = lb_emit_struct_ep(p, e, index); - } else if (type->kind == Type_RelativePointer) { - e = lb_emit_struct_ep(p, e, index); - } else { - GB_PANIC("un-gep-able type %s", type_to_string(type)); - } - } - - return e; -} - - -lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel) { - lbValue ptr = lb_address_from_load_or_generate_local(p, e); - lbValue res = lb_emit_deep_field_gep(p, ptr, sel); - return lb_emit_load(p, res); -} - - - -void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) { - if (p->curr_block == nullptr) { - return; - } - // NOTE(bill): The prev block may defer injection before it's terminator - LLVMValueRef last_instr = LLVMGetLastInstruction(p->curr_block->block); - if (last_instr != nullptr && LLVMIsAReturnInst(last_instr)) { - // NOTE(bill): ReturnStmt defer stuff will be handled previously - return; - } - - isize prev_context_stack_count = p->context_stack.count; - GB_ASSERT(prev_context_stack_count <= p->context_stack.capacity); - defer (p->context_stack.count = prev_context_stack_count); - p->context_stack.count = d.context_stack_count; - - lbBlock *b = lb_create_block(p, "defer"); - if (last_instr == nullptr || !LLVMIsATerminatorInst(last_instr)) { - lb_emit_jump(p, b); - } - - lb_start_block(p, b); - if (d.kind == lbDefer_Node) { - lb_build_stmt(p, d.stmt); - } else if (d.kind == lbDefer_Instr) { - // NOTE(bill): Need to make a new copy - LLVMValueRef instr = LLVMInstructionClone(d.instr.value); - LLVMInsertIntoBuilder(p->builder, instr); - } else if (d.kind == lbDefer_Proc) { - lb_emit_call(p, d.proc.deferred, d.proc.result_as_args); - } -} - -void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) { - isize count = p->defer_stmts.count; - isize i = count; - while (i --> 0) { - lbDefer const &d = p->defer_stmts[i]; - - if (kind == lbDeferExit_Default) { - if (p->scope_index == d.scope_index && - d.scope_index > 0) { // TODO(bill): Which is correct: > 0 or > 1? - lb_build_defer_stmt(p, d); - array_pop(&p->defer_stmts); - continue; - } else { - break; - } - } else if (kind == lbDeferExit_Return) { - lb_build_defer_stmt(p, d); - } else if (kind == lbDeferExit_Branch) { - GB_ASSERT(block != nullptr); - isize lower_limit = block->scope_index; - if (lower_limit < d.scope_index) { - lb_build_defer_stmt(p, d); - } - } - } -} - -void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) { - Type *pt = base_type(p->type); - GB_ASSERT(pt->kind == Type_Proc); - if (pt->Proc.calling_convention == ProcCC_Odin) { - GB_ASSERT(p->context_stack.count != 0); - } - - lbDefer *d = array_add_and_get(&p->defer_stmts); - d->kind = lbDefer_Node; - d->scope_index = scope_index; - d->context_stack_count = p->context_stack.count; - d->block = p->curr_block; - d->stmt = stmt; -} - -void lb_add_defer_proc(lbProcedure *p, isize scope_index, lbValue deferred, Array<lbValue> const &result_as_args) { - Type *pt = base_type(p->type); - GB_ASSERT(pt->kind == Type_Proc); - if (pt->Proc.calling_convention == ProcCC_Odin) { - GB_ASSERT(p->context_stack.count != 0); - } - - lbDefer *d = array_add_and_get(&p->defer_stmts); - d->kind = lbDefer_Proc; - d->scope_index = p->scope_index; - d->block = p->curr_block; - d->context_stack_count = p->context_stack.count; - d->proc.deferred = deferred; - d->proc.result_as_args = result_as_args; -} - - - -Array<lbValue> lb_value_to_array(lbProcedure *p, lbValue value) { - Array<lbValue> array = {}; - Type *t = base_type(value.type); - if (t == nullptr) { - // Do nothing - } else if (is_type_tuple(t)) { - GB_ASSERT(t->kind == Type_Tuple); - auto *rt = &t->Tuple; - if (rt->variables.count > 0) { - array = array_make<lbValue>(permanent_allocator(), rt->variables.count); - for_array(i, rt->variables) { - lbValue elem = lb_emit_struct_ev(p, value, cast(i32)i); - array[i] = elem; - } - } - } else { - array = array_make<lbValue>(permanent_allocator(), 1); - array[0] = value; - } - return array; -} - - - -lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array<lbValue> const &processed_args, Type *abi_rt, lbAddr context_ptr, ProcInlining inlining) { - GB_ASSERT(p->module->ctx == LLVMGetTypeContext(LLVMTypeOf(value.value))); - - unsigned arg_count = cast(unsigned)processed_args.count; - if (return_ptr.value != nullptr) { - arg_count += 1; - } - if (context_ptr.addr.value != nullptr) { - arg_count += 1; - } - - LLVMValueRef *args = gb_alloc_array(permanent_allocator(), LLVMValueRef, arg_count); - isize arg_index = 0; - if (return_ptr.value != nullptr) { - args[arg_index++] = return_ptr.value; - } - for_array(i, processed_args) { - lbValue arg = processed_args[i]; - args[arg_index++] = arg.value; - } - if (context_ptr.addr.value != nullptr) { - LLVMValueRef cp = context_ptr.addr.value; - cp = LLVMBuildPointerCast(p->builder, cp, lb_type(p->module, t_rawptr), ""); - args[arg_index++] = cp; - } - LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder); - GB_ASSERT(curr_block != p->decl_block->block); - - { - LLVMTypeRef ftp = lb_type(p->module, value.type); - LLVMTypeRef ft = LLVMGetElementType(ftp); - LLVMValueRef fn = value.value; - if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) { - fn = LLVMBuildPointerCast(p->builder, fn, ftp, ""); - } - LLVMTypeRef fnp = LLVMGetElementType(LLVMTypeOf(fn)); - GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp)); - - { - unsigned param_count = LLVMCountParamTypes(fnp); - GB_ASSERT(arg_count >= param_count); - - LLVMTypeRef *param_types = gb_alloc_array(temporary_allocator(), LLVMTypeRef, param_count); - LLVMGetParamTypes(fnp, param_types); - for (unsigned i = 0; i < param_count; i++) { - LLVMTypeRef param_type = param_types[i]; - LLVMTypeRef arg_type = LLVMTypeOf(args[i]); - GB_ASSERT_MSG( - arg_type == param_type, - "Parameter types do not match: %s != %s, argument: %s", - LLVMPrintTypeToString(arg_type), - LLVMPrintTypeToString(param_type), - LLVMPrintValueToString(args[i]) - ); - } - } - - LLVMValueRef ret = LLVMBuildCall2(p->builder, fnp, fn, args, arg_count, ""); - - switch (inlining) { - case ProcInlining_none: - break; - case ProcInlining_inline: - LLVMAddCallSiteAttribute(ret, LLVMAttributeIndex_FunctionIndex, lb_create_enum_attribute(p->module->ctx, "alwaysinline")); - break; - case ProcInlining_no_inline: - LLVMAddCallSiteAttribute(ret, LLVMAttributeIndex_FunctionIndex, lb_create_enum_attribute(p->module->ctx, "noinline")); - break; - } - - lbValue res = {}; - res.value = ret; - res.type = abi_rt; - return res; - } -} - - -lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name) { - AstPackage *pkg = m->info->runtime_package; - Entity *e = scope_lookup_current(pkg->scope, name); - return lb_find_procedure_value_from_entity(m, e); -} - - -lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args) { - String name = make_string_c(c_name); - lbValue proc = lb_lookup_runtime_procedure(p->module, name); - return lb_emit_call(p, proc, args); -} - -lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining, bool use_copy_elision_hint) { - lbModule *m = p->module; - - Type *pt = base_type(value.type); - GB_ASSERT(pt->kind == Type_Proc); - Type *results = pt->Proc.results; - - if (p->entity != nullptr) { - if (p->entity->flags & EntityFlag_Disabled) { - return {}; - } - } - - lbAddr context_ptr = {}; - if (pt->Proc.calling_convention == ProcCC_Odin) { - context_ptr = lb_find_or_generate_context_ptr(p); - } - - defer (if (pt->Proc.diverging) { - LLVMBuildUnreachable(p->builder); - }); - - bool is_c_vararg = pt->Proc.c_vararg; - isize param_count = pt->Proc.param_count; - if (is_c_vararg) { - GB_ASSERT(param_count-1 <= args.count); - param_count -= 1; - } else { - GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count); - } - - lbValue result = {}; - - auto processed_args = array_make<lbValue>(permanent_allocator(), 0, args.count); - - { - lbFunctionType *ft = lb_get_function_type(m, p, pt); - bool return_by_pointer = ft->ret.kind == lbArg_Indirect; - - unsigned param_index = 0; - for (isize i = 0; i < param_count; i++) { - Entity *e = pt->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - GB_ASSERT(e->flags & EntityFlag_Param); - - Type *original_type = e->type; - lbArgType *arg = &ft->args[param_index]; - if (arg->kind == lbArg_Ignore) { - continue; - } - - lbValue x = lb_emit_conv(p, args[i], original_type); - LLVMTypeRef xt = lb_type(p->module, x.type); - - if (arg->kind == lbArg_Direct) { - LLVMTypeRef abi_type = arg->cast_type; - if (!abi_type) { - abi_type = arg->type; - } - if (xt == abi_type) { - array_add(&processed_args, x); - } else { - x.value = OdinLLVMBuildTransmute(p, x.value, abi_type); - array_add(&processed_args, x); - } - - } else if (arg->kind == lbArg_Indirect) { - lbValue ptr = {}; - if (arg->is_byval) { - ptr = lb_copy_value_to_ptr(p, x, original_type, arg->byval_alignment); - } else if (is_calling_convention_odin(pt->Proc.calling_convention)) { - // NOTE(bill): Odin parameters are immutable so the original value can be passed if possible - // i.e. `T const &` in C++ - ptr = lb_address_from_load_or_generate_local(p, x); - } else { - ptr = lb_copy_value_to_ptr(p, x, original_type, 16); - } - array_add(&processed_args, ptr); - } - - param_index += 1; - } - - if (is_c_vararg) { - for (isize i = processed_args.count; i < args.count; i++) { - array_add(&processed_args, args[i]); - } - } - - if (inlining == ProcInlining_none) { - inlining = p->inlining; - } - - Type *rt = reduce_tuple_to_single_type(results); - if (return_by_pointer) { - lbValue return_ptr = {}; - if (use_copy_elision_hint && p->copy_elision_hint.ptr.value != nullptr) { - if (are_types_identical(type_deref(p->copy_elision_hint.ptr.type), rt)) { - return_ptr = lb_consume_copy_elision_hint(p); - } - } - if (return_ptr.value == nullptr) { - lbAddr r = lb_add_local_generated(p, rt, true); - return_ptr = r.addr; - } - GB_ASSERT(is_type_pointer(return_ptr.type)); - lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining); - result = lb_emit_load(p, return_ptr); - } else if (rt != nullptr) { - result = lb_emit_call_internal(p, value, {}, processed_args, rt, context_ptr, inlining); - if (ft->ret.cast_type) { - result.value = OdinLLVMBuildTransmute(p, result.value, ft->ret.cast_type); - } - result.value = OdinLLVMBuildTransmute(p, result.value, ft->ret.type); - result.type = rt; - if (LLVMTypeOf(result.value) == LLVMInt1TypeInContext(p->module->ctx)) { - result.type = t_llvm_bool; - } - if (!is_type_tuple(rt)) { - result = lb_emit_conv(p, result, rt); - } - } else { - lb_emit_call_internal(p, value, {}, processed_args, nullptr, context_ptr, inlining); - } - - } - - Entity **found = map_get(&p->module->procedure_values, hash_pointer(value.value)); - if (found != nullptr) { - Entity *e = *found; - if (e != nullptr && entity_has_deferred_procedure(e)) { - DeferredProcedureKind kind = e->Procedure.deferred_procedure.kind; - Entity *deferred_entity = e->Procedure.deferred_procedure.entity; - lbValue deferred = lb_find_procedure_value_from_entity(p->module, deferred_entity); - - - auto in_args = args; - Array<lbValue> result_as_args = {}; - switch (kind) { - case DeferredProcedure_none: - break; - case DeferredProcedure_in: - result_as_args = in_args; - break; - case DeferredProcedure_out: - result_as_args = lb_value_to_array(p, result); - break; - case DeferredProcedure_in_out: - { - auto out_args = lb_value_to_array(p, result); - array_init(&result_as_args, permanent_allocator(), in_args.count + out_args.count); - array_copy(&result_as_args, in_args, 0); - array_copy(&result_as_args, out_args, in_args.count); - } - break; - } - - lb_add_defer_proc(p, p->scope_index, deferred, result_as_args); - } - } - - return result; -} - -lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) { - Type *t = s.type; - GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t)); - Type *st = base_type(type_deref(t)); - GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st), "%s", type_to_string(st)); - GB_ASSERT_MSG(is_type_integer(core_type(index.type)), "%s", type_to_string(index.type)); - - LLVMValueRef indices[2] = {}; - indices[0] = llvm_zero(p->module); - indices[1] = lb_emit_conv(p, index, t_int).value; - - Type *ptr = base_array_type(st); - lbValue res = {}; - res.value = LLVMBuildGEP(p->builder, s.value, indices, 2, ""); - res.type = alloc_type_pointer(ptr); - return res; -} - -lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) { - Type *t = s.type; - GB_ASSERT(is_type_pointer(t)); - Type *st = base_type(type_deref(t)); - GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st), "%s", type_to_string(st)); - - GB_ASSERT(0 <= index); - Type *ptr = base_array_type(st); - - - LLVMValueRef indices[2] = { - LLVMConstInt(lb_type(p->module, t_int), 0, false), - LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)index, false), - }; - - lbValue res = {}; - if (lb_is_const(s)) { - res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); - } else { - res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), ""); - } - res.type = alloc_type_pointer(ptr); - return res; -} - -lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) { - LLVMValueRef indices[1] = {index.value}; - lbValue res = {}; - res.type = ptr.type; - - if (lb_is_const(ptr) && lb_is_const(index)) { - res.value = LLVMConstGEP(ptr.value, indices, 1); - } else { - res.value = LLVMBuildGEP(p->builder, ptr.value, indices, 1, ""); - } - return res; -} - -LLVMValueRef llvm_const_slice(lbModule *m, lbValue data, lbValue len) { - GB_ASSERT(is_type_pointer(data.type)); - GB_ASSERT(are_types_identical(len.type, t_int)); - LLVMValueRef vals[2] = { - data.value, - len.value, - }; - return LLVMConstStructInContext(m->ctx, vals, gb_count_of(vals), false); -} - - -void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len) { - Type *t = lb_addr_type(slice); - GB_ASSERT(is_type_slice(t)); - lbValue ptr = lb_addr_get_ptr(p, slice); - lb_emit_store(p, lb_emit_struct_ep(p, ptr, 0), base_elem); - lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len); -} -void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue base_elem, lbValue len) { - Type *t = lb_addr_type(string); - GB_ASSERT(is_type_string(t)); - lbValue ptr = lb_addr_get_ptr(p, string); - lb_emit_store(p, lb_emit_struct_ep(p, ptr, 0), base_elem); - lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len); -} - -lbValue lb_string_elem(lbProcedure *p, lbValue string) { - Type *t = base_type(string.type); - GB_ASSERT(t->kind == Type_Basic && t->Basic.kind == Basic_string); - return lb_emit_struct_ev(p, string, 0); -} -lbValue lb_string_len(lbProcedure *p, lbValue string) { - Type *t = base_type(string.type); - GB_ASSERT_MSG(t->kind == Type_Basic && t->Basic.kind == Basic_string, "%s", type_to_string(t)); - return lb_emit_struct_ev(p, string, 1); -} - -lbValue lb_cstring_len(lbProcedure *p, lbValue value) { - GB_ASSERT(is_type_cstring(value.type)); - auto args = array_make<lbValue>(permanent_allocator(), 1); - args[0] = lb_emit_conv(p, value, t_cstring); - return lb_emit_runtime_call(p, "cstring_len", args); -} - - -lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr) { - Type *t = type_deref(array_ptr.type); - GB_ASSERT(is_type_array(t)); - return lb_emit_struct_ep(p, array_ptr, 0); -} - -lbValue lb_slice_elem(lbProcedure *p, lbValue slice) { - GB_ASSERT(is_type_slice(slice.type)); - return lb_emit_struct_ev(p, slice, 0); -} -lbValue lb_slice_len(lbProcedure *p, lbValue slice) { - GB_ASSERT(is_type_slice(slice.type)); - return lb_emit_struct_ev(p, slice, 1); -} -lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da) { - GB_ASSERT(is_type_dynamic_array(da.type)); - return lb_emit_struct_ev(p, da, 0); -} -lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da) { - GB_ASSERT(is_type_dynamic_array(da.type)); - return lb_emit_struct_ev(p, da, 1); -} -lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da) { - GB_ASSERT(is_type_dynamic_array(da.type)); - return lb_emit_struct_ev(p, da, 2); -} -lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da) { - GB_ASSERT(is_type_dynamic_array(da.type)); - return lb_emit_struct_ev(p, da, 3); -} - -lbValue lb_map_entries(lbProcedure *p, lbValue value) { - Type *t = base_type(value.type); - GB_ASSERT_MSG(t->kind == Type_Map, "%s", type_to_string(t)); - init_map_internal_types(t); - Type *gst = t->Map.generated_struct_type; - i32 index = 1; - lbValue entries = lb_emit_struct_ev(p, value, index); - return entries; -} - -lbValue lb_map_entries_ptr(lbProcedure *p, lbValue value) { - Type *t = base_type(type_deref(value.type)); - GB_ASSERT_MSG(t->kind == Type_Map, "%s", type_to_string(t)); - init_map_internal_types(t); - Type *gst = t->Map.generated_struct_type; - i32 index = 1; - lbValue entries = lb_emit_struct_ep(p, value, index); - return entries; -} - -lbValue lb_map_len(lbProcedure *p, lbValue value) { - lbValue entries = lb_map_entries(p, value); - return lb_dynamic_array_len(p, entries); -} - -lbValue lb_map_cap(lbProcedure *p, lbValue value) { - lbValue entries = lb_map_entries(p, value); - return lb_dynamic_array_cap(p, entries); -} - -lbValue lb_soa_struct_len(lbProcedure *p, lbValue value) { - Type *t = base_type(value.type); - bool is_ptr = false; - if (is_type_pointer(t)) { - is_ptr = true; - t = base_type(type_deref(t)); - } - - - if (t->Struct.soa_kind == StructSoa_Fixed) { - return lb_const_int(p->module, t_int, t->Struct.soa_count); - } - - GB_ASSERT(t->Struct.soa_kind == StructSoa_Slice || - t->Struct.soa_kind == StructSoa_Dynamic); - - isize n = 0; - Type *elem = base_type(t->Struct.soa_elem); - if (elem->kind == Type_Struct) { - n = cast(isize)elem->Struct.fields.count; - } else if (elem->kind == Type_Array) { - n = cast(isize)elem->Array.count; - } else { - GB_PANIC("Unreachable"); - } - - if (is_ptr) { - lbValue v = lb_emit_struct_ep(p, value, cast(i32)n); - return lb_emit_load(p, v); - } - return lb_emit_struct_ev(p, value, cast(i32)n); -} - -lbValue lb_soa_struct_cap(lbProcedure *p, lbValue value) { - Type *t = base_type(value.type); - - bool is_ptr = false; - if (is_type_pointer(t)) { - is_ptr = true; - t = base_type(type_deref(t)); - } - - if (t->Struct.soa_kind == StructSoa_Fixed) { - return lb_const_int(p->module, t_int, t->Struct.soa_count); - } - - GB_ASSERT(t->Struct.soa_kind == StructSoa_Dynamic); - - isize n = 0; - Type *elem = base_type(t->Struct.soa_elem); - if (elem->kind == Type_Struct) { - n = cast(isize)elem->Struct.fields.count+1; - } else if (elem->kind == Type_Array) { - n = cast(isize)elem->Array.count+1; - } else { - GB_PANIC("Unreachable"); - } - - if (is_ptr) { - lbValue v = lb_emit_struct_ep(p, value, cast(i32)n); - return lb_emit_load(p, v); - } - return lb_emit_struct_ev(p, value, cast(i32)n); -} - -lbValue lb_soa_zip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) { - GB_ASSERT(ce->args.count > 0); - - auto slices = slice_make<lbValue>(temporary_allocator(), ce->args.count); - for_array(i, slices) { - Ast *arg = ce->args[i]; - if (arg->kind == Ast_FieldValue) { - arg = arg->FieldValue.value; - } - slices[i] = lb_build_expr(p, arg); - } - - lbValue len = lb_slice_len(p, slices[0]); - for (isize i = 1; i < slices.count; i++) { - lbValue other_len = lb_slice_len(p, slices[i]); - len = lb_emit_min(p, t_int, len, other_len); - } - - GB_ASSERT(is_type_soa_struct(tv.type)); - lbAddr res = lb_add_local_generated(p, tv.type, true); - for_array(i, slices) { - lbValue src = lb_slice_elem(p, slices[i]); - lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i); - lb_emit_store(p, dst, src); - } - lbValue len_dst = lb_emit_struct_ep(p, res.addr, cast(i32)slices.count); - lb_emit_store(p, len_dst, len); - - return lb_addr_load(p, res); -} - -lbValue lb_soa_unzip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) { - GB_ASSERT(ce->args.count == 1); - - lbValue arg = lb_build_expr(p, ce->args[0]); - Type *t = base_type(arg.type); - GB_ASSERT(is_type_soa_struct(t) && t->Struct.soa_kind == StructSoa_Slice); - - lbValue len = lb_soa_struct_len(p, arg); - - lbAddr res = lb_add_local_generated(p, tv.type, true); - if (is_type_tuple(tv.type)) { - lbValue rp = lb_addr_get_ptr(p, res); - for (i32 i = 0; i < cast(i32)(t->Struct.fields.count-1); i++) { - lbValue ptr = lb_emit_struct_ev(p, arg, i); - lbAddr dst = lb_addr(lb_emit_struct_ep(p, rp, i)); - lb_fill_slice(p, dst, ptr, len); - } - } else { - GB_ASSERT(is_type_slice(tv.type)); - lbValue ptr = lb_emit_struct_ev(p, arg, 0); - lb_fill_slice(p, res, ptr, len); - } - - return lb_addr_load(p, res); -} - -void lb_emit_try_lhs_rhs(lbProcedure *p, Ast *arg, TypeAndValue const &tv, lbValue *lhs_, lbValue *rhs_) { - lbValue lhs = {}; - lbValue rhs = {}; - - lbValue value = lb_build_expr(p, arg); - if (is_type_tuple(value.type)) { - i32 n = cast(i32)(value.type->Tuple.variables.count-1); - if (value.type->Tuple.variables.count == 2) { - lhs = lb_emit_struct_ev(p, value, 0); - } else { - lbAddr lhs_addr = lb_add_local_generated(p, tv.type, false); - lbValue lhs_ptr = lb_addr_get_ptr(p, lhs_addr); - for (i32 i = 0; i < n; i++) { - lb_emit_store(p, lb_emit_struct_ep(p, lhs_ptr, i), lb_emit_struct_ev(p, value, i)); - } - lhs = lb_addr_load(p, lhs_addr); - } - rhs = lb_emit_struct_ev(p, value, n); - } else { - rhs = value; - } - - GB_ASSERT(rhs.value != nullptr); - - if (lhs_) *lhs_ = lhs; - if (rhs_) *rhs_ = rhs; -} - - -lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) { - lbValue has_value = {}; - if (is_type_boolean(rhs.type)) { - has_value = rhs; - } else { - GB_ASSERT_MSG(type_has_nil(rhs.type), "%s", type_to_string(rhs.type)); - has_value = lb_emit_comp_against_nil(p, Token_CmpEq, rhs); - } - GB_ASSERT(has_value.value != nullptr); - return has_value; -} -// lbValue lb_emit_try(lbProcedure *p, Ast *arg, TypeAndValue const &tv) { -// lbValue lhs = {}; -// lbValue rhs = {}; -// lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs); - -// lbBlock *return_block = lb_create_block(p, "try.return", false); -// lbBlock *continue_block = lb_create_block(p, "try.continue", false); -// lb_emit_if(p, lb_emit_try_has_value(p, rhs), continue_block, return_block); -// lb_start_block(p, return_block); - -// { -// Type *proc_type = base_type(p->type); -// Type *results = proc_type->Proc.results; -// GB_ASSERT(results != nullptr && results->kind == Type_Tuple); -// TypeTuple *tuple = &results->Tuple; - -// GB_ASSERT(tuple->variables.count != 0); - -// Entity *end_entity = tuple->variables[tuple->variables.count-1]; -// rhs = lb_emit_conv(p, rhs, end_entity->type); -// if (p->type->Proc.has_named_results) { -// GB_ASSERT(end_entity->token.string.len != 0); - -// // NOTE(bill): store the named values before returning -// lbValue found = map_must_get(&p->module->values, hash_entity(end_entity)); -// lb_emit_store(p, found, rhs); - -// lb_build_return_stmt(p, {}); -// } else { -// GB_ASSERT(tuple->variables.count == 1); -// lb_build_return_stmt_internal(p, rhs); -// } -// } - -// lb_start_block(p, continue_block); - -// if (tv.type != nullptr) { -// return lb_emit_conv(p, lhs, tv.type); -// } -// return {}; -// } - - -lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) { - lbValue lhs = {}; - lbValue rhs = {}; - lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs); - - LLVMValueRef incoming_values[2] = {}; - LLVMBasicBlockRef incoming_blocks[2] = {}; - - GB_ASSERT(else_expr != nullptr); - lbBlock *then = lb_create_block(p, "or_else.then"); - lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later - lbBlock *else_ = lb_create_block(p, "or_else.else"); - - lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); - lb_start_block(p, then); - - Type *type = default_type(tv.type); - - incoming_values[0] = lb_emit_conv(p, lhs, type).value; - - lb_emit_jump(p, done); - lb_start_block(p, else_); - - incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value; - - lb_emit_jump(p, done); - lb_start_block(p, done); - - lbValue res = {}; - res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), ""); - res.type = type; - - GB_ASSERT(p->curr_block->preds.count >= 2); - incoming_blocks[0] = p->curr_block->preds[0]->block; - incoming_blocks[1] = p->curr_block->preds[1]->block; - - LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2); - - return res; -} - - - -lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId id) { - ast_node(ce, CallExpr, expr); - - switch (id) { - case BuiltinProc_DIRECTIVE: { - ast_node(bd, BasicDirective, ce->proc); - String name = bd->name.string; - GB_ASSERT(name == "location"); - String procedure = p->entity->token.string; - TokenPos pos = ast_token(ce->proc).pos; - if (ce->args.count > 0) { - Ast *ident = unselector_expr(ce->args[0]); - GB_ASSERT(ident->kind == Ast_Ident); - Entity *e = entity_of_node(ident); - GB_ASSERT(e != nullptr); - - if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) { - procedure = e->parent_proc_decl->entity->token.string; - } else { - procedure = str_lit(""); - } - pos = e->token.pos; - - } - return lb_emit_source_code_location(p, procedure, pos); - } - - case BuiltinProc_type_info_of: { - Ast *arg = ce->args[0]; - TypeAndValue tav = type_and_value_of_expr(arg); - if (tav.mode == Addressing_Type) { - Type *t = default_type(type_of_expr(arg)); - return lb_type_info(p->module, t); - } - GB_ASSERT(is_type_typeid(tav.type)); - - auto args = array_make<lbValue>(permanent_allocator(), 1); - args[0] = lb_build_expr(p, arg); - return lb_emit_runtime_call(p, "__type_info_of", args); - } - - case BuiltinProc_typeid_of: { - Ast *arg = ce->args[0]; - TypeAndValue tav = type_and_value_of_expr(arg); - GB_ASSERT(tav.mode == Addressing_Type); - Type *t = default_type(type_of_expr(arg)); - return lb_typeid(p->module, t); - } - - case BuiltinProc_len: { - lbValue v = lb_build_expr(p, ce->args[0]); - Type *t = base_type(v.type); - if (is_type_pointer(t)) { - // IMPORTANT TODO(bill): Should there be a nil pointer check? - v = lb_emit_load(p, v); - t = type_deref(t); - } - if (is_type_cstring(t)) { - return lb_cstring_len(p, v); - } else if (is_type_string(t)) { - return lb_string_len(p, v); - } else if (is_type_array(t)) { - GB_PANIC("Array lengths are constant"); - } else if (is_type_slice(t)) { - return lb_slice_len(p, v); - } else if (is_type_dynamic_array(t)) { - return lb_dynamic_array_len(p, v); - } else if (is_type_map(t)) { - return lb_map_len(p, v); - } else if (is_type_soa_struct(t)) { - return lb_soa_struct_len(p, v); - } - - GB_PANIC("Unreachable"); - break; - } - - case BuiltinProc_cap: { - lbValue v = lb_build_expr(p, ce->args[0]); - Type *t = base_type(v.type); - if (is_type_pointer(t)) { - // IMPORTANT TODO(bill): Should there be a nil pointer check? - v = lb_emit_load(p, v); - t = type_deref(t); - } - if (is_type_string(t)) { - GB_PANIC("Unreachable"); - } else if (is_type_array(t)) { - GB_PANIC("Array lengths are constant"); - } else if (is_type_slice(t)) { - return lb_slice_len(p, v); - } else if (is_type_dynamic_array(t)) { - return lb_dynamic_array_cap(p, v); - } else if (is_type_map(t)) { - return lb_map_cap(p, v); - } else if (is_type_soa_struct(t)) { - return lb_soa_struct_cap(p, v); - } - - GB_PANIC("Unreachable"); - - break; - } - - case BuiltinProc_swizzle: { - isize index_count = ce->args.count-1; - if (is_type_simd_vector(tv.type)) { - lbValue vec = lb_build_expr(p, ce->args[0]); - if (index_count == 0) { - return vec; - } - - unsigned mask_len = cast(unsigned)index_count; - LLVMValueRef *mask_elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, index_count); - for (isize i = 1; i < ce->args.count; i++) { - TypeAndValue tv = type_and_value_of_expr(ce->args[i]); - GB_ASSERT(is_type_integer(tv.type)); - GB_ASSERT(tv.value.kind == ExactValue_Integer); - - u32 index = cast(u32)big_int_to_i64(&tv.value.value_integer); - mask_elems[i-1] = LLVMConstInt(lb_type(p->module, t_u32), index, false); - } - - LLVMValueRef mask = LLVMConstVector(mask_elems, mask_len); - - LLVMValueRef v1 = vec.value; - LLVMValueRef v2 = vec.value; - - lbValue res = {}; - res.type = tv.type; - res.value = LLVMBuildShuffleVector(p->builder, v1, v2, mask, ""); - return res; - - } - - lbAddr addr = lb_build_addr(p, ce->args[0]); - if (index_count == 0) { - return lb_addr_load(p, addr); - } - lbValue src = lb_addr_get_ptr(p, addr); - // TODO(bill): Should this be zeroed or not? - lbAddr dst = lb_add_local_generated(p, tv.type, true); - lbValue dst_ptr = lb_addr_get_ptr(p, dst); - - for (i32 i = 1; i < ce->args.count; i++) { - TypeAndValue tv = type_and_value_of_expr(ce->args[i]); - GB_ASSERT(is_type_integer(tv.type)); - GB_ASSERT(tv.value.kind == ExactValue_Integer); - - i32 src_index = cast(i32)big_int_to_i64(&tv.value.value_integer); - i32 dst_index = i-1; - - lbValue src_elem = lb_emit_array_epi(p, src, src_index); - lbValue dst_elem = lb_emit_array_epi(p, dst_ptr, dst_index); - - lb_emit_store(p, dst_elem, lb_emit_load(p, src_elem)); - } - return lb_addr_load(p, dst); - } - - case BuiltinProc_complex: { - lbValue real = lb_build_expr(p, ce->args[0]); - lbValue imag = lb_build_expr(p, ce->args[1]); - lbAddr dst_addr = lb_add_local_generated(p, tv.type, false); - lbValue dst = lb_addr_get_ptr(p, dst_addr); - - Type *ft = base_complex_elem_type(tv.type); - real = lb_emit_conv(p, real, ft); - imag = lb_emit_conv(p, imag, ft); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), real); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), imag); - - return lb_emit_load(p, dst); - } - - case BuiltinProc_quaternion: { - lbValue real = lb_build_expr(p, ce->args[0]); - lbValue imag = lb_build_expr(p, ce->args[1]); - lbValue jmag = lb_build_expr(p, ce->args[2]); - lbValue kmag = lb_build_expr(p, ce->args[3]); - - // @QuaternionLayout - lbAddr dst_addr = lb_add_local_generated(p, tv.type, false); - lbValue dst = lb_addr_get_ptr(p, dst_addr); - - Type *ft = base_complex_elem_type(tv.type); - real = lb_emit_conv(p, real, ft); - imag = lb_emit_conv(p, imag, ft); - jmag = lb_emit_conv(p, jmag, ft); - kmag = lb_emit_conv(p, kmag, ft); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), real); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), imag); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), jmag); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), kmag); - - return lb_emit_load(p, dst); - } - - case BuiltinProc_real: { - lbValue val = lb_build_expr(p, ce->args[0]); - if (is_type_complex(val.type)) { - lbValue real = lb_emit_struct_ev(p, val, 0); - return lb_emit_conv(p, real, tv.type); - } else if (is_type_quaternion(val.type)) { - // @QuaternionLayout - lbValue real = lb_emit_struct_ev(p, val, 3); - return lb_emit_conv(p, real, tv.type); - } - GB_PANIC("invalid type for real"); - return {}; - } - case BuiltinProc_imag: { - lbValue val = lb_build_expr(p, ce->args[0]); - if (is_type_complex(val.type)) { - lbValue imag = lb_emit_struct_ev(p, val, 1); - return lb_emit_conv(p, imag, tv.type); - } else if (is_type_quaternion(val.type)) { - // @QuaternionLayout - lbValue imag = lb_emit_struct_ev(p, val, 0); - return lb_emit_conv(p, imag, tv.type); - } - GB_PANIC("invalid type for imag"); - return {}; - } - case BuiltinProc_jmag: { - lbValue val = lb_build_expr(p, ce->args[0]); - if (is_type_quaternion(val.type)) { - // @QuaternionLayout - lbValue imag = lb_emit_struct_ev(p, val, 1); - return lb_emit_conv(p, imag, tv.type); - } - GB_PANIC("invalid type for jmag"); - return {}; - } - case BuiltinProc_kmag: { - lbValue val = lb_build_expr(p, ce->args[0]); - if (is_type_quaternion(val.type)) { - // @QuaternionLayout - lbValue imag = lb_emit_struct_ev(p, val, 2); - return lb_emit_conv(p, imag, tv.type); - } - GB_PANIC("invalid type for kmag"); - return {}; - } - - case BuiltinProc_conj: { - lbValue val = lb_build_expr(p, ce->args[0]); - lbValue res = {}; - Type *t = val.type; - if (is_type_complex(t)) { - res = lb_addr_get_ptr(p, lb_add_local_generated(p, tv.type, false)); - lbValue real = lb_emit_struct_ev(p, val, 0); - lbValue imag = lb_emit_struct_ev(p, val, 1); - imag = lb_emit_unary_arith(p, Token_Sub, imag, imag.type); - lb_emit_store(p, lb_emit_struct_ep(p, res, 0), real); - lb_emit_store(p, lb_emit_struct_ep(p, res, 1), imag); - } else if (is_type_quaternion(t)) { - // @QuaternionLayout - res = lb_addr_get_ptr(p, lb_add_local_generated(p, tv.type, false)); - lbValue real = lb_emit_struct_ev(p, val, 3); - lbValue imag = lb_emit_struct_ev(p, val, 0); - lbValue jmag = lb_emit_struct_ev(p, val, 1); - lbValue kmag = lb_emit_struct_ev(p, val, 2); - imag = lb_emit_unary_arith(p, Token_Sub, imag, imag.type); - jmag = lb_emit_unary_arith(p, Token_Sub, jmag, jmag.type); - kmag = lb_emit_unary_arith(p, Token_Sub, kmag, kmag.type); - lb_emit_store(p, lb_emit_struct_ep(p, res, 3), real); - lb_emit_store(p, lb_emit_struct_ep(p, res, 0), imag); - lb_emit_store(p, lb_emit_struct_ep(p, res, 1), jmag); - lb_emit_store(p, lb_emit_struct_ep(p, res, 2), kmag); - } - return lb_emit_load(p, res); - } - - case BuiltinProc_expand_to_tuple: { - lbValue val = lb_build_expr(p, ce->args[0]); - Type *t = base_type(val.type); - - if (!is_type_tuple(tv.type)) { - if (t->kind == Type_Struct) { - GB_ASSERT(t->Struct.fields.count == 1); - return lb_emit_struct_ev(p, val, 0); - } else if (t->kind == Type_Array) { - GB_ASSERT(t->Array.count == 1); - return lb_emit_array_epi(p, val, 0); - } else { - GB_PANIC("Unknown type of expand_to_tuple"); - } - - } - - GB_ASSERT(is_type_tuple(tv.type)); - // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops - lbValue tuple = lb_addr_get_ptr(p, lb_add_local_generated(p, tv.type, false)); - if (t->kind == Type_Struct) { - for_array(src_index, t->Struct.fields) { - Entity *field = t->Struct.fields[src_index]; - i32 field_index = field->Variable.field_index; - lbValue f = lb_emit_struct_ev(p, val, field_index); - lbValue ep = lb_emit_struct_ep(p, tuple, cast(i32)src_index); - lb_emit_store(p, ep, f); - } - } else if (is_type_array_like(t)) { - // TODO(bill): Clean-up this code - lbValue ap = lb_address_from_load_or_generate_local(p, val); - i32 n = cast(i32)get_array_type_count(t); - for (i32 i = 0; i < n; i++) { - lbValue f = lb_emit_load(p, lb_emit_array_epi(p, ap, i)); - lbValue ep = lb_emit_struct_ep(p, tuple, i); - lb_emit_store(p, ep, f); - } - } else { - GB_PANIC("Unknown type of expand_to_tuple"); - } - return lb_emit_load(p, tuple); - } - - case BuiltinProc_min: { - Type *t = type_of_expr(expr); - if (ce->args.count == 2) { - return lb_emit_min(p, t, lb_build_expr(p, ce->args[0]), lb_build_expr(p, ce->args[1])); - } else { - lbValue x = lb_build_expr(p, ce->args[0]); - for (isize i = 1; i < ce->args.count; i++) { - x = lb_emit_min(p, t, x, lb_build_expr(p, ce->args[i])); - } - return x; - } - } - - case BuiltinProc_max: { - Type *t = type_of_expr(expr); - if (ce->args.count == 2) { - return lb_emit_max(p, t, lb_build_expr(p, ce->args[0]), lb_build_expr(p, ce->args[1])); - } else { - lbValue x = lb_build_expr(p, ce->args[0]); - for (isize i = 1; i < ce->args.count; i++) { - x = lb_emit_max(p, t, x, lb_build_expr(p, ce->args[i])); - } - return x; - } - } - - case BuiltinProc_abs: { - lbValue x = lb_build_expr(p, ce->args[0]); - Type *t = x.type; - if (is_type_unsigned(t)) { - return x; - } - if (is_type_quaternion(t)) { - i64 sz = 8*type_size_of(t); - auto args = array_make<lbValue>(permanent_allocator(), 1); - args[0] = x; - switch (sz) { - case 64: return lb_emit_runtime_call(p, "abs_quaternion64", args); - case 128: return lb_emit_runtime_call(p, "abs_quaternion128", args); - case 256: return lb_emit_runtime_call(p, "abs_quaternion256", args); - } - GB_PANIC("Unknown complex type"); - } else if (is_type_complex(t)) { - i64 sz = 8*type_size_of(t); - auto args = array_make<lbValue>(permanent_allocator(), 1); - args[0] = x; - switch (sz) { - case 32: return lb_emit_runtime_call(p, "abs_complex32", args); - case 64: return lb_emit_runtime_call(p, "abs_complex64", args); - case 128: return lb_emit_runtime_call(p, "abs_complex128", args); - } - GB_PANIC("Unknown complex type"); - } - lbValue zero = lb_const_nil(p->module, t); - lbValue cond = lb_emit_comp(p, Token_Lt, x, zero); - lbValue neg = lb_emit_unary_arith(p, Token_Sub, x, t); - return lb_emit_select(p, cond, neg, x); - } - - case BuiltinProc_clamp: - return lb_emit_clamp(p, type_of_expr(expr), - lb_build_expr(p, ce->args[0]), - lb_build_expr(p, ce->args[1]), - lb_build_expr(p, ce->args[2])); - - - case BuiltinProc_soa_zip: - return lb_soa_zip(p, ce, tv); - case BuiltinProc_soa_unzip: - return lb_soa_unzip(p, ce, tv); - - case BuiltinProc_or_else: - return lb_emit_or_else(p, ce->args[0], ce->args[1], tv); - - // "Intrinsics" - - case BuiltinProc_alloca: - { - lbValue sz = lb_build_expr(p, ce->args[0]); - i64 al = exact_value_to_i64(type_and_value_of_expr(ce->args[1]).value); - - lbValue res = {}; - res.type = t_u8_ptr; - res.value = LLVMBuildArrayAlloca(p->builder, lb_type(p->module, t_u8), sz.value, ""); - LLVMSetAlignment(res.value, cast(unsigned)al); - return res; - } - - case BuiltinProc_cpu_relax: - if (build_context.metrics.arch == TargetArch_386 || - build_context.metrics.arch == TargetArch_amd64) { - LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false); - LLVMValueRef the_asm = LLVMGetInlineAsm(func_type, - cast(char *)"pause", 5, - cast(char *)"", 0, - /*HasSideEffects*/true, /*IsAlignStack*/false, - LLVMInlineAsmDialectATT - ); - GB_ASSERT(the_asm != nullptr); - LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, ""); - } else if (build_context.metrics.arch == TargetArch_arm64) { - LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false); - LLVMValueRef the_asm = LLVMGetInlineAsm(func_type, - cast(char *)"yield", 5, - cast(char *)"", 0, - /*HasSideEffects*/true, /*IsAlignStack*/false, - LLVMInlineAsmDialectATT - ); - GB_ASSERT(the_asm != nullptr); - LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, ""); - } - return {}; - - - case BuiltinProc_debug_trap: - case BuiltinProc_trap: - { - char const *name = nullptr; - switch (id) { - case BuiltinProc_debug_trap: name = "llvm.debugtrap"; break; - case BuiltinProc_trap: name = "llvm.trap"; break; - } - - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); - - LLVMBuildCall(p->builder, ip, nullptr, 0, ""); - if (id == BuiltinProc_trap) { - LLVMBuildUnreachable(p->builder); - } - return {}; - } - - case BuiltinProc_read_cycle_counter: - { - char const *name = "llvm.readcyclecounter"; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); - - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, ""); - res.type = tv.type; - return res; - } - - case BuiltinProc_count_trailing_zeros: - return lb_emit_count_trailing_zeros(p, lb_build_expr(p, ce->args[0]), tv.type); - case BuiltinProc_count_leading_zeros: - return lb_emit_count_leading_zeros(p, lb_build_expr(p, ce->args[0]), tv.type); - - case BuiltinProc_count_ones: - return lb_emit_count_ones(p, lb_build_expr(p, ce->args[0]), tv.type); - case BuiltinProc_count_zeros: - return lb_emit_count_zeros(p, lb_build_expr(p, ce->args[0]), tv.type); - - case BuiltinProc_reverse_bits: - return lb_emit_reverse_bits(p, lb_build_expr(p, ce->args[0]), tv.type); - - case BuiltinProc_byte_swap: - { - lbValue x = lb_build_expr(p, ce->args[0]); - x = lb_emit_conv(p, x, tv.type); - return lb_emit_byte_swap(p, x, tv.type); - } - - case BuiltinProc_overflow_add: - case BuiltinProc_overflow_sub: - case BuiltinProc_overflow_mul: - { - Type *main_type = tv.type; - Type *type = main_type; - if (is_type_tuple(main_type)) { - type = main_type->Tuple.variables[0]->type; - } - - lbValue x = lb_build_expr(p, ce->args[0]); - lbValue y = lb_build_expr(p, ce->args[1]); - x = lb_emit_conv(p, x, type); - y = lb_emit_conv(p, y, type); - - char const *name = nullptr; - if (is_type_unsigned(type)) { - switch (id) { - case BuiltinProc_overflow_add: name = "llvm.uadd.with.overflow"; break; - case BuiltinProc_overflow_sub: name = "llvm.usub.with.overflow"; break; - case BuiltinProc_overflow_mul: name = "llvm.umul.with.overflow"; break; - } - } else { - switch (id) { - case BuiltinProc_overflow_add: name = "llvm.sadd.with.overflow"; break; - case BuiltinProc_overflow_sub: name = "llvm.ssub.with.overflow"; break; - case BuiltinProc_overflow_mul: name = "llvm.smul.with.overflow"; break; - } - } - LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[2] = {}; - args[0] = x.value; - args[1] = y.value; - - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - - if (is_type_tuple(main_type)) { - Type *res_type = nullptr; - gbAllocator a = permanent_allocator(); - res_type = alloc_type_tuple(); - array_init(&res_type->Tuple.variables, a, 2); - res_type->Tuple.variables[0] = alloc_entity_field(nullptr, blank_token, type, false, 0); - res_type->Tuple.variables[1] = alloc_entity_field(nullptr, blank_token, t_llvm_bool, false, 1); - - res.type = res_type; - } else { - res.value = LLVMBuildExtractValue(p->builder, res.value, 0, ""); - res.type = type; - } - return res; - } - - case BuiltinProc_sqrt: - { - Type *type = tv.type; - - lbValue x = lb_build_expr(p, ce->args[0]); - x = lb_emit_conv(p, x, type); - - char const *name = "llvm.sqrt"; - LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[1] = {}; - args[0] = x.value; - - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - res.type = type; - return res; - } - - case BuiltinProc_mem_copy: - case BuiltinProc_mem_copy_non_overlapping: - { - lbValue dst = lb_build_expr(p, ce->args[0]); - lbValue src = lb_build_expr(p, ce->args[1]); - lbValue len = lb_build_expr(p, ce->args[2]); - dst = lb_emit_conv(p, dst, t_rawptr); - src = lb_emit_conv(p, src, t_rawptr); - len = lb_emit_conv(p, len, t_int); - - bool is_inlinable = false; - - if (ce->args[2]->tav.mode == Addressing_Constant) { - ExactValue ev = exact_value_to_integer(ce->args[2]->tav.value); - i64 const_len = exact_value_to_i64(ev); - // TODO(bill): Determine when it is better to do the `*.inline` versions - if (const_len <= 4*build_context.word_size) { - is_inlinable = true; - } - } - - char const *name = nullptr; - switch (id) { - case BuiltinProc_mem_copy: - if (is_inlinable) { - name = "llvm.memmove.inline"; - } else { - name = "llvm.memmove"; - } - break; - case BuiltinProc_mem_copy_non_overlapping: - if (is_inlinable) { - name = "llvm.memcpy.line"; - } else { - name = "llvm.memcpy"; - } - break; - } - - LLVMTypeRef types[3] = { - lb_type(p->module, t_rawptr), - lb_type(p->module, t_rawptr), - lb_type(p->module, t_int) - }; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[4] = {}; - args[0] = dst.value; - args[1] = src.value; - args[2] = len.value; - args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, false); // is_volatile parameter - - LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - - return {}; - } - - case BuiltinProc_mem_zero: - { - lbValue ptr = lb_build_expr(p, ce->args[0]); - lbValue len = lb_build_expr(p, ce->args[1]); - ptr = lb_emit_conv(p, ptr, t_rawptr); - len = lb_emit_conv(p, len, t_int); - - unsigned alignment = 1; - lb_mem_zero_ptr_internal(p, ptr.value, len.value, alignment); - return {}; - } - - case BuiltinProc_ptr_offset: - { - lbValue ptr = lb_build_expr(p, ce->args[0]); - lbValue len = lb_build_expr(p, ce->args[1]); - len = lb_emit_conv(p, len, t_int); - - LLVMValueRef indices[1] = { - len.value, - }; - - lbValue res = {}; - res.type = tv.type; - res.value = LLVMBuildGEP(p->builder, ptr.value, indices, gb_count_of(indices), ""); - return res; - } - case BuiltinProc_ptr_sub: - { - lbValue ptr0 = lb_build_expr(p, ce->args[0]); - lbValue ptr1 = lb_build_expr(p, ce->args[1]); - - LLVMTypeRef type_int = lb_type(p->module, t_int); - LLVMValueRef diff = LLVMBuildPtrDiff(p->builder, ptr0.value, ptr1.value, ""); - diff = LLVMBuildIntCast2(p->builder, diff, type_int, /*signed*/true, ""); - - lbValue res = {}; - res.type = t_int; - res.value = diff; - return res; - } - - - - case BuiltinProc_atomic_fence: - LLVMBuildFence(p->builder, LLVMAtomicOrderingSequentiallyConsistent, false, ""); - return {}; - case BuiltinProc_atomic_fence_acq: - LLVMBuildFence(p->builder, LLVMAtomicOrderingAcquire, false, ""); - return {}; - case BuiltinProc_atomic_fence_rel: - LLVMBuildFence(p->builder, LLVMAtomicOrderingRelease, false, ""); - return {}; - case BuiltinProc_atomic_fence_acqrel: - LLVMBuildFence(p->builder, LLVMAtomicOrderingAcquireRelease, false, ""); - return {}; - - case BuiltinProc_volatile_store: - case BuiltinProc_atomic_store: - case BuiltinProc_atomic_store_rel: - case BuiltinProc_atomic_store_relaxed: - case BuiltinProc_atomic_store_unordered: { - lbValue dst = lb_build_expr(p, ce->args[0]); - lbValue val = lb_build_expr(p, ce->args[1]); - val = lb_emit_conv(p, val, type_deref(dst.type)); - - LLVMValueRef instr = LLVMBuildStore(p->builder, val.value, dst.value); - switch (id) { - case BuiltinProc_volatile_store: LLVMSetVolatile(instr, true); break; - case BuiltinProc_atomic_store: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; - case BuiltinProc_atomic_store_rel: LLVMSetOrdering(instr, LLVMAtomicOrderingRelease); break; - case BuiltinProc_atomic_store_relaxed: LLVMSetOrdering(instr, LLVMAtomicOrderingMonotonic); break; - case BuiltinProc_atomic_store_unordered: LLVMSetOrdering(instr, LLVMAtomicOrderingUnordered); break; - } - - LLVMSetAlignment(instr, cast(unsigned)type_align_of(type_deref(dst.type))); - - return {}; - } - - case BuiltinProc_volatile_load: - case BuiltinProc_atomic_load: - case BuiltinProc_atomic_load_acq: - case BuiltinProc_atomic_load_relaxed: - case BuiltinProc_atomic_load_unordered: { - lbValue dst = lb_build_expr(p, ce->args[0]); - - LLVMValueRef instr = LLVMBuildLoad(p->builder, dst.value, ""); - switch (id) { - case BuiltinProc_volatile_load: LLVMSetVolatile(instr, true); break; - case BuiltinProc_atomic_load: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; - case BuiltinProc_atomic_load_acq: LLVMSetOrdering(instr, LLVMAtomicOrderingAcquire); break; - case BuiltinProc_atomic_load_relaxed: LLVMSetOrdering(instr, LLVMAtomicOrderingMonotonic); break; - case BuiltinProc_atomic_load_unordered: LLVMSetOrdering(instr, LLVMAtomicOrderingUnordered); break; - } - LLVMSetAlignment(instr, cast(unsigned)type_align_of(type_deref(dst.type))); - - lbValue res = {}; - res.value = instr; - res.type = type_deref(dst.type); - return res; - } - - case BuiltinProc_atomic_add: - case BuiltinProc_atomic_add_acq: - case BuiltinProc_atomic_add_rel: - case BuiltinProc_atomic_add_acqrel: - case BuiltinProc_atomic_add_relaxed: - case BuiltinProc_atomic_sub: - case BuiltinProc_atomic_sub_acq: - case BuiltinProc_atomic_sub_rel: - case BuiltinProc_atomic_sub_acqrel: - case BuiltinProc_atomic_sub_relaxed: - case BuiltinProc_atomic_and: - case BuiltinProc_atomic_and_acq: - case BuiltinProc_atomic_and_rel: - case BuiltinProc_atomic_and_acqrel: - case BuiltinProc_atomic_and_relaxed: - case BuiltinProc_atomic_nand: - case BuiltinProc_atomic_nand_acq: - case BuiltinProc_atomic_nand_rel: - case BuiltinProc_atomic_nand_acqrel: - case BuiltinProc_atomic_nand_relaxed: - case BuiltinProc_atomic_or: - case BuiltinProc_atomic_or_acq: - case BuiltinProc_atomic_or_rel: - case BuiltinProc_atomic_or_acqrel: - case BuiltinProc_atomic_or_relaxed: - case BuiltinProc_atomic_xor: - case BuiltinProc_atomic_xor_acq: - case BuiltinProc_atomic_xor_rel: - case BuiltinProc_atomic_xor_acqrel: - case BuiltinProc_atomic_xor_relaxed: - case BuiltinProc_atomic_xchg: - case BuiltinProc_atomic_xchg_acq: - case BuiltinProc_atomic_xchg_rel: - case BuiltinProc_atomic_xchg_acqrel: - case BuiltinProc_atomic_xchg_relaxed: { - lbValue dst = lb_build_expr(p, ce->args[0]); - lbValue val = lb_build_expr(p, ce->args[1]); - val = lb_emit_conv(p, val, type_deref(dst.type)); - - LLVMAtomicRMWBinOp op = {}; - LLVMAtomicOrdering ordering = {}; - - switch (id) { - case BuiltinProc_atomic_add: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_add_acq: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_add_rel: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_add_acqrel: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_add_relaxed: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_sub: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_sub_acq: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_sub_rel: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_sub_acqrel: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_sub_relaxed: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_and: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_and_acq: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_and_rel: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_and_acqrel: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_and_relaxed: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_nand: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_nand_acq: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_nand_rel: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_nand_acqrel: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_nand_relaxed: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_or: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_or_acq: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_or_rel: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_or_acqrel: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_or_relaxed: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_xor: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_xor_acq: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_xor_rel: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_xor_acqrel: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_xor_relaxed: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingMonotonic; break; - case BuiltinProc_atomic_xchg: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; - case BuiltinProc_atomic_xchg_acq: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingAcquire; break; - case BuiltinProc_atomic_xchg_rel: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingRelease; break; - case BuiltinProc_atomic_xchg_acqrel: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingAcquireRelease; break; - case BuiltinProc_atomic_xchg_relaxed: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingMonotonic; break; - } - - lbValue res = {}; - res.value = LLVMBuildAtomicRMW(p->builder, op, dst.value, val.value, ordering, false); - res.type = tv.type; - return res; - } - - case BuiltinProc_atomic_cxchg: - case BuiltinProc_atomic_cxchg_acq: - case BuiltinProc_atomic_cxchg_rel: - case BuiltinProc_atomic_cxchg_acqrel: - case BuiltinProc_atomic_cxchg_relaxed: - case BuiltinProc_atomic_cxchg_failrelaxed: - case BuiltinProc_atomic_cxchg_failacq: - case BuiltinProc_atomic_cxchg_acq_failrelaxed: - case BuiltinProc_atomic_cxchg_acqrel_failrelaxed: - case BuiltinProc_atomic_cxchgweak: - case BuiltinProc_atomic_cxchgweak_acq: - case BuiltinProc_atomic_cxchgweak_rel: - case BuiltinProc_atomic_cxchgweak_acqrel: - case BuiltinProc_atomic_cxchgweak_relaxed: - case BuiltinProc_atomic_cxchgweak_failrelaxed: - case BuiltinProc_atomic_cxchgweak_failacq: - case BuiltinProc_atomic_cxchgweak_acq_failrelaxed: - case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed: { - Type *type = expr->tav.type; - - lbValue address = lb_build_expr(p, ce->args[0]); - Type *elem = type_deref(address.type); - lbValue old_value = lb_build_expr(p, ce->args[1]); - lbValue new_value = lb_build_expr(p, ce->args[2]); - old_value = lb_emit_conv(p, old_value, elem); - new_value = lb_emit_conv(p, new_value, elem); - - LLVMAtomicOrdering success_ordering = {}; - LLVMAtomicOrdering failure_ordering = {}; - LLVMBool weak = false; - - switch (id) { - case BuiltinProc_atomic_cxchg: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchg_acq: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchg_rel: success_ordering = LLVMAtomicOrderingRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchg_acqrel: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchg_relaxed: success_ordering = LLVMAtomicOrderingMonotonic; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchg_failrelaxed: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchg_failacq: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingAcquire; weak = false; break; - case BuiltinProc_atomic_cxchg_acq_failrelaxed: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchg_acqrel_failrelaxed: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; - case BuiltinProc_atomic_cxchgweak: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; - case BuiltinProc_atomic_cxchgweak_acq: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true; break; - case BuiltinProc_atomic_cxchgweak_rel: success_ordering = LLVMAtomicOrderingRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true; break; - case BuiltinProc_atomic_cxchgweak_acqrel: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true; break; - case BuiltinProc_atomic_cxchgweak_relaxed: success_ordering = LLVMAtomicOrderingMonotonic; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; - case BuiltinProc_atomic_cxchgweak_failrelaxed: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; - case BuiltinProc_atomic_cxchgweak_failacq: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingAcquire; weak = true; break; - case BuiltinProc_atomic_cxchgweak_acq_failrelaxed: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; - case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; - } - - // TODO(bill): Figure out how to make it weak - LLVMBool single_threaded = weak; - - LLVMValueRef value = LLVMBuildAtomicCmpXchg( - p->builder, address.value, - old_value.value, new_value.value, - success_ordering, - failure_ordering, - single_threaded - ); - - if (tv.type->kind == Type_Tuple) { - Type *fix_typed = alloc_type_tuple(); - array_init(&fix_typed->Tuple.variables, permanent_allocator(), 2); - fix_typed->Tuple.variables[0] = tv.type->Tuple.variables[0]; - fix_typed->Tuple.variables[1] = alloc_entity_field(nullptr, blank_token, t_llvm_bool, false, 1); - - lbValue res = {}; - res.value = value; - res.type = fix_typed; - return res; - } else { - lbValue res = {}; - res.value = LLVMBuildExtractValue(p->builder, value, 0, ""); - res.type = tv.type; - return res; - } - } - - - case BuiltinProc_type_equal_proc: - return lb_get_equal_proc_for_type(p->module, ce->args[0]->tav.type); - - case BuiltinProc_type_hasher_proc: - return lb_get_hasher_proc_for_type(p->module, ce->args[0]->tav.type); - - case BuiltinProc_fixed_point_mul: - case BuiltinProc_fixed_point_div: - case BuiltinProc_fixed_point_mul_sat: - case BuiltinProc_fixed_point_div_sat: - { - bool do_bswap = is_type_different_to_arch_endianness(tv.type); - Type *platform_type = integer_endian_type_to_platform_type(tv.type); - - lbValue x = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), platform_type); - lbValue y = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), platform_type); - lbValue scale = lb_emit_conv(p, lb_build_expr(p, ce->args[2]), t_i32); - - char const *name = nullptr; - if (is_type_unsigned(tv.type)) { - switch (id) { - case BuiltinProc_fixed_point_mul: name = "llvm.umul.fix"; break; - case BuiltinProc_fixed_point_div: name = "llvm.udiv.fix"; break; - case BuiltinProc_fixed_point_mul_sat: name = "llvm.umul.fix.sat"; break; - case BuiltinProc_fixed_point_div_sat: name = "llvm.udiv.fix.sat"; break; - } - } else { - switch (id) { - case BuiltinProc_fixed_point_mul: name = "llvm.smul.fix"; break; - case BuiltinProc_fixed_point_div: name = "llvm.sdiv.fix"; break; - case BuiltinProc_fixed_point_mul_sat: name = "llvm.smul.fix.sat"; break; - case BuiltinProc_fixed_point_div_sat: name = "llvm.sdiv.fix.sat"; break; - } - } - GB_ASSERT(name != nullptr); - - LLVMTypeRef types[1] = {lb_type(p->module, platform_type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - lbValue res = {}; - - LLVMValueRef args[3] = {}; - args[0] = x.value; - args[1] = y.value; - args[2] = scale.value; - - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - res.type = platform_type; - return lb_emit_conv(p, res, tv.type); - } - - case BuiltinProc_expect: - { - Type *t = default_type(tv.type); - lbValue x = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t); - lbValue y = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t); - - char const *name = "llvm.expect"; - - LLVMTypeRef types[1] = {lb_type(p->module, t)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - lbValue res = {}; - - LLVMValueRef args[2] = {}; - args[0] = x.value; - args[1] = y.value; - - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - res.type = t; - return lb_emit_conv(p, res, t); - } - } - - GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); - return {}; -} - - -lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos) { - switch (param_value.kind) { - case ParameterValue_Constant: - if (is_type_constant_type(parameter_type)) { - auto res = lb_const_value(p->module, parameter_type, param_value.value); - return res; - } else { - ExactValue ev = param_value.value; - lbValue arg = {}; - Type *type = type_of_expr(param_value.original_ast_expr); - if (type != nullptr) { - arg = lb_const_value(p->module, type, ev); - } else { - arg = lb_const_value(p->module, parameter_type, param_value.value); - } - return lb_emit_conv(p, arg, parameter_type); - } - - case ParameterValue_Nil: - return lb_const_nil(p->module, parameter_type); - case ParameterValue_Location: - { - String proc_name = {}; - if (p->entity != nullptr) { - proc_name = p->entity->token.string; - } - return lb_emit_source_code_location(p, proc_name, pos); - } - case ParameterValue_Value: - return lb_build_expr(p, param_value.ast_value); - } - return lb_const_nil(p->module, parameter_type); -} - - -lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr); - -lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { - expr = unparen_expr(expr); - ast_node(ce, CallExpr, expr); - - if (ce->sce_temp_data) { - return *(lbValue *)ce->sce_temp_data; - } - - lbValue res = lb_build_call_expr_internal(p, expr); - - if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures - GB_ASSERT(is_type_tuple(res.type)); - GB_ASSERT(res.type->Tuple.variables.count == 2); - return lb_emit_struct_ev(p, res, 0); - } - return res; -} -lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { - lbModule *m = p->module; - - 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; - } - 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(m, 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(m, 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; - } - } - } - - Entity *proc_entity = entity_of_node(proc_expr); - if (proc_entity != nullptr) { - if (proc_entity->flags & EntityFlag_Disabled) { - return {}; - } - } - - 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; - - if (is_call_expr_field_value(ce)) { - auto args = array_make<lbValue>(permanent_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(m, 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(m, e->type); - } else if (e->kind == Entity_Constant) { - continue; - } else { - GB_ASSERT(e->kind == Entity_Variable); - if (args[i].value == nullptr) { - args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos); - } else { - args[i] = lb_emit_conv(p, args[i], e->type); - } - } - } - - for (isize i = 0; i < args.count; i++) { - Entity *e = params->variables[i]; - if (args[i].type == nullptr) { - continue; - } else if (is_type_untyped_nil(args[i].type)) { - args[i] = lb_const_nil(m, e->type); - } else if (is_type_untyped_undef(args[i].type)) { - args[i] = lb_const_undef(m, e->type); - } - } - - return lb_emit_call(p, value, args, ce->inlining, p->copy_elision_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<lbValue>(permanent_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(m, 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_struct_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); - args[arg_index++] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos); - } - } - - 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) { - if (args[i].value == nullptr) { - continue; - } - GB_ASSERT_MSG(args[i].value != nullptr, "%.*s", LIT(e->token.string)); - args[i] = lb_emit_conv(p, args[i], e->type); - } - } - } - - if (variadic && !vari_expand && !is_c_vararg) { - // variadic call argument generation - 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(m, 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]; - args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos); - } - } - - isize final_count = param_count; - if (is_c_vararg) { - final_count = arg_count; - } - - if (param_tuple != nullptr) { - for (isize i = 0; i < gb_min(args.count, param_tuple->variables.count); i++) { - Entity *e = param_tuple->variables[i]; - if (args[i].type == nullptr) { - continue; - } else if (is_type_untyped_nil(args[i].type)) { - args[i] = lb_const_nil(m, e->type); - } else if (is_type_untyped_undef(args[i].type)) { - args[i] = lb_const_undef(m, e->type); - } - } - } - - auto call_args = array_slice(args, 0, final_count); - return lb_emit_call(p, value, call_args, ce->inlining, p->copy_elision_hint.ast == expr); -} - -bool lb_is_const(lbValue value) { - LLVMValueRef v = value.value; - if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) { - // TODO(bill): Is this correct behaviour? - return true; - } - if (LLVMIsConstant(v)) { - return true; - } - return false; -} - - -bool lb_is_const_or_global(lbValue value) { - if (lb_is_const(value)) { - return true; - } - if (LLVMGetValueKind(value.value) == LLVMGlobalVariableValueKind) { - LLVMTypeRef t = LLVMGetElementType(LLVMTypeOf(value.value)); - if (!lb_is_type_kind(t, LLVMPointerTypeKind)) { - return false; - } - LLVMTypeRef elem = LLVMGetElementType(t); - return lb_is_type_kind(elem, LLVMFunctionTypeKind); - } - return false; -} - - -bool lb_is_const_nil(lbValue value) { - LLVMValueRef v = value.value; - if (LLVMIsConstant(v)) { - if (LLVMIsAConstantAggregateZero(v)) { - return true; - } else if (LLVMIsAConstantPointerNull(v)) { - return true; - } - } - return false; -} - -String lb_get_const_string(lbModule *m, lbValue value) { - GB_ASSERT(lb_is_const(value)); - GB_ASSERT(LLVMIsConstant(value.value)); - - Type *t = base_type(value.type); - GB_ASSERT(are_types_identical(t, t_string)); - - - - unsigned ptr_indices[1] = {0}; - unsigned len_indices[1] = {1}; - LLVMValueRef underlying_ptr = LLVMConstExtractValue(value.value, ptr_indices, gb_count_of(ptr_indices)); - LLVMValueRef underlying_len = LLVMConstExtractValue(value.value, len_indices, gb_count_of(len_indices)); - - GB_ASSERT(LLVMGetConstOpcode(underlying_ptr) == LLVMGetElementPtr); - underlying_ptr = LLVMGetOperand(underlying_ptr, 0); - GB_ASSERT(LLVMIsAGlobalVariable(underlying_ptr)); - underlying_ptr = LLVMGetInitializer(underlying_ptr); - - size_t length = 0; - char const *text = LLVMGetAsString(underlying_ptr, &length); - - isize real_length = cast(isize)LLVMConstIntGetSExtValue(underlying_len); - - return make_string(cast(u8 const *)text, real_length); -} - - -void lb_emit_increment(lbProcedure *p, lbValue addr) { - GB_ASSERT(is_type_pointer(addr.type)); - Type *type = type_deref(addr.type); - lbValue v_one = lb_const_value(p->module, type, exact_value_i64(1)); - lb_emit_store(p, addr, lb_emit_arith(p, Token_Add, lb_emit_load(p, addr), v_one, type)); - -} - -lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) { - GB_ASSERT(type_size_of(value.type) == type_size_of(end_type)); - - if (type_size_of(value.type) < 2) { - return value; - } - - Type *original_type = value.type; - if (is_type_float(original_type)) { - i64 sz = type_size_of(original_type); - Type *integer_type = nullptr; - switch (sz) { - case 2: integer_type = t_u16; break; - case 4: integer_type = t_u32; break; - case 8: integer_type = t_u64; break; - } - GB_ASSERT(integer_type != nullptr); - value = lb_emit_transmute(p, value, integer_type); - } - - char const *name = "llvm.bswap"; - LLVMTypeRef types[1] = {lb_type(p->module, value.type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[1] = {}; - args[0] = value.value; - - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - res.type = value.type; - - if (is_type_float(original_type)) { - res = lb_emit_transmute(p, res, original_type); - } - res.type = end_type; - return res; -} - - -lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) { - x = lb_emit_conv(p, x, type); - - char const *name = "llvm.ctpop"; - LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[1] = {}; - args[0] = x.value; - - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - res.type = type; - return res; -} - -lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type) { - i64 sz = 8*type_size_of(type); - lbValue size = lb_const_int(p->module, type, cast(u64)sz); - lbValue count = lb_emit_count_ones(p, x, type); - return lb_emit_arith(p, Token_Sub, size, count, type); -} - - - -lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) { - x = lb_emit_conv(p, x, type); - - char const *name = "llvm.cttz"; - LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[2] = {}; - args[0] = x.value; - args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)); - - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - res.type = type; - return res; -} - -lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) { - x = lb_emit_conv(p, x, type); - - char const *name = "llvm.ctlz"; - LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[2] = {}; - args[0] = x.value; - args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)); - - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - res.type = type; - return res; -} - - - -lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) { - x = lb_emit_conv(p, x, type); - - char const *name = "llvm.bitreverse"; - LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[1] = {}; - args[0] = x.value; - - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - res.type = type; - return res; -} - - -lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x) { - GB_ASSERT(is_type_bit_set(x.type)); - Type *underlying = bit_set_to_int(x.type); - lbValue card = lb_emit_count_ones(p, x, underlying); - return lb_emit_conv(p, card, t_int); -} - - -lbLoopData lb_loop_start(lbProcedure *p, isize count, Type *index_type) { - lbLoopData data = {}; - - lbValue max = lb_const_int(p->module, t_int, count); - - data.idx_addr = lb_add_local_generated(p, index_type, true); - - data.body = lb_create_block(p, "loop.body"); - data.done = lb_create_block(p, "loop.done"); - data.loop = lb_create_block(p, "loop.loop"); - - lb_emit_jump(p, data.loop); - lb_start_block(p, data.loop); - - data.idx = lb_addr_load(p, data.idx_addr); - - lbValue cond = lb_emit_comp(p, Token_Lt, data.idx, max); - lb_emit_if(p, cond, data.body, data.done); - lb_start_block(p, data.body); - - return data; -} - -void lb_loop_end(lbProcedure *p, lbLoopData const &data) { - if (data.idx_addr.addr.value != nullptr) { - lb_emit_increment(p, data.idx_addr.addr); - lb_emit_jump(p, data.loop); - lb_start_block(p, data.done); - } -} - -lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { - lbValue res = {}; - res.type = t_llvm_bool; - Type *t = x.type; - Type *bt = base_type(t); - TypeKind type_kind = bt->kind; - - switch (type_kind) { - case Type_Basic: - switch (bt->Basic.kind) { - case Basic_rawptr: - case Basic_cstring: - if (op_kind == Token_CmpEq) { - res.value = LLVMBuildIsNull(p->builder, x.value, ""); - } else if (op_kind == Token_NotEq) { - res.value = LLVMBuildIsNotNull(p->builder, x.value, ""); - } - return res; - case Basic_any: - { - // TODO(bill): is this correct behaviour for nil comparison for any? - lbValue data = lb_emit_struct_ev(p, x, 0); - lbValue ti = lb_emit_struct_ev(p, x, 1); - if (op_kind == Token_CmpEq) { - LLVMValueRef a = LLVMBuildIsNull(p->builder, data.value, ""); - LLVMValueRef b = LLVMBuildIsNull(p->builder, ti.value, ""); - res.value = LLVMBuildOr(p->builder, a, b, ""); - return res; - } else if (op_kind == Token_NotEq) { - LLVMValueRef a = LLVMBuildIsNotNull(p->builder, data.value, ""); - LLVMValueRef b = LLVMBuildIsNotNull(p->builder, ti.value, ""); - res.value = LLVMBuildAnd(p->builder, a, b, ""); - return res; - } - } - break; - case Basic_typeid: - lbValue invalid_typeid = lb_const_value(p->module, t_typeid, exact_value_i64(0)); - return lb_emit_comp(p, op_kind, x, invalid_typeid); - } - break; - - case Type_Enum: - case Type_Pointer: - case Type_Proc: - case Type_BitSet: - if (op_kind == Token_CmpEq) { - res.value = LLVMBuildIsNull(p->builder, x.value, ""); - } else if (op_kind == Token_NotEq) { - res.value = LLVMBuildIsNotNull(p->builder, x.value, ""); - } - return res; - - case Type_Slice: - { - lbValue data = lb_emit_struct_ev(p, x, 0); - if (op_kind == Token_CmpEq) { - res.value = LLVMBuildIsNull(p->builder, data.value, ""); - return res; - } else if (op_kind == Token_NotEq) { - res.value = LLVMBuildIsNotNull(p->builder, data.value, ""); - return res; - } - } - break; - - case Type_DynamicArray: - { - lbValue data = lb_emit_struct_ev(p, x, 0); - if (op_kind == Token_CmpEq) { - res.value = LLVMBuildIsNull(p->builder, data.value, ""); - return res; - } else if (op_kind == Token_NotEq) { - res.value = LLVMBuildIsNotNull(p->builder, data.value, ""); - return res; - } - } - break; - - case Type_Map: - { - lbValue map_ptr = lb_address_from_load_or_generate_local(p, x); - - unsigned indices[2] = {0, 0}; - LLVMValueRef hashes_data = LLVMBuildStructGEP(p->builder, map_ptr.value, 0, ""); - LLVMValueRef hashes_data_ptr_ptr = LLVMBuildStructGEP(p->builder, hashes_data, 0, ""); - LLVMValueRef hashes_data_ptr = LLVMBuildLoad(p->builder, hashes_data_ptr_ptr, ""); - - if (op_kind == Token_CmpEq) { - res.value = LLVMBuildIsNull(p->builder, hashes_data_ptr, ""); - return res; - } else { - res.value = LLVMBuildIsNotNull(p->builder, hashes_data_ptr, ""); - return res; - } - } - break; - - case Type_Union: - { - if (type_size_of(t) == 0) { - if (op_kind == Token_CmpEq) { - return lb_const_bool(p->module, t_llvm_bool, true); - } else if (op_kind == Token_NotEq) { - return lb_const_bool(p->module, t_llvm_bool, false); - } - } else if (is_type_union_maybe_pointer(t)) { - lbValue tag = lb_emit_transmute(p, x, t_rawptr); - return lb_emit_comp_against_nil(p, op_kind, tag); - } else { - lbValue tag = lb_emit_union_tag_value(p, x); - return lb_emit_comp(p, op_kind, tag, lb_zero(p->module, tag.type)); - } - } - case Type_Struct: - if (is_type_soa_struct(t)) { - Type *bt = base_type(t); - if (bt->Struct.soa_kind == StructSoa_Slice) { - LLVMValueRef the_value = {}; - if (bt->Struct.fields.count == 0) { - lbValue len = lb_soa_struct_len(p, x); - the_value = len.value; - } else { - lbValue first_field = lb_emit_struct_ev(p, x, 0); - the_value = first_field.value; - } - if (op_kind == Token_CmpEq) { - res.value = LLVMBuildIsNull(p->builder, the_value, ""); - return res; - } else if (op_kind == Token_NotEq) { - res.value = LLVMBuildIsNotNull(p->builder, the_value, ""); - return res; - } - } else if (bt->Struct.soa_kind == StructSoa_Dynamic) { - LLVMValueRef the_value = {}; - if (bt->Struct.fields.count == 0) { - lbValue cap = lb_soa_struct_cap(p, x); - the_value = cap.value; - } else { - lbValue first_field = lb_emit_struct_ev(p, x, 0); - the_value = first_field.value; - } - if (op_kind == Token_CmpEq) { - res.value = LLVMBuildIsNull(p->builder, the_value, ""); - return res; - } else if (op_kind == Token_NotEq) { - res.value = LLVMBuildIsNotNull(p->builder, the_value, ""); - return res; - } - } - } else if (is_type_struct(t) && type_has_nil(t)) { - auto args = array_make<lbValue>(permanent_allocator(), 2); - lbValue lhs = lb_address_from_load_or_generate_local(p, x); - args[0] = lb_emit_conv(p, lhs, t_rawptr); - args[1] = lb_const_int(p->module, t_int, type_size_of(t)); - lbValue val = lb_emit_runtime_call(p, "memory_compare_zero", args); - lbValue res = lb_emit_comp(p, op_kind, val, lb_const_int(p->module, t_int, 0)); - return res; - } - break; - } - GB_PANIC("Unknown handled type: %s -> %s", type_to_string(t), type_to_string(bt)); - return {}; -} - lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) { Type *original_type = type; type = base_type(type); @@ -11839,372 +435,6 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { return {p->value, p->type}; } -lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right, Type *type) { - GB_ASSERT((is_type_struct(type) || is_type_union(type)) && is_type_comparable(type)); - lbValue left_ptr = lb_address_from_load_or_generate_local(p, left); - lbValue right_ptr = lb_address_from_load_or_generate_local(p, right); - lbValue res = {}; - if (is_type_simple_compare(type)) { - // TODO(bill): Test to see if this is actually faster!!!! - auto args = array_make<lbValue>(permanent_allocator(), 3); - args[0] = lb_emit_conv(p, left_ptr, t_rawptr); - args[1] = lb_emit_conv(p, right_ptr, t_rawptr); - args[2] = lb_const_int(p->module, t_int, type_size_of(type)); - res = lb_emit_runtime_call(p, "memory_equal", args); - } else { - lbValue value = lb_get_equal_proc_for_type(p->module, type); - auto args = array_make<lbValue>(permanent_allocator(), 2); - args[0] = lb_emit_conv(p, left_ptr, t_rawptr); - args[1] = lb_emit_conv(p, right_ptr, t_rawptr); - res = lb_emit_call(p, value, args); - } - if (op_kind == Token_NotEq) { - res = lb_emit_unary_arith(p, Token_Not, res, res.type); - } - return res; -} - - -lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) { - Type *a = core_type(left.type); - Type *b = core_type(right.type); - - GB_ASSERT(gb_is_between(op_kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)); - - lbValue nil_check = {}; - if (is_type_untyped_nil(left.type)) { - nil_check = lb_emit_comp_against_nil(p, op_kind, right); - } else if (is_type_untyped_nil(right.type)) { - nil_check = lb_emit_comp_against_nil(p, op_kind, left); - } - if (nil_check.value != nullptr) { - return nil_check; - } - - if (are_types_identical(a, b)) { - // NOTE(bill): No need for a conversion - } else if (lb_is_const(left) || lb_is_const_nil(left)) { - left = lb_emit_conv(p, left, right.type); - } else if (lb_is_const(right) || lb_is_const_nil(right)) { - right = lb_emit_conv(p, right, left.type); - } else { - Type *lt = left.type; - Type *rt = right.type; - - lt = left.type; - rt = right.type; - i64 ls = type_size_of(lt); - i64 rs = type_size_of(rt); - - // NOTE(bill): Quick heuristic, larger types are usually the target type - if (ls < rs) { - left = lb_emit_conv(p, left, rt); - } else if (ls > rs) { - right = lb_emit_conv(p, right, lt); - } else { - if (is_type_union(rt)) { - left = lb_emit_conv(p, left, rt); - } else { - right = lb_emit_conv(p, right, lt); - } - } - } - - if (is_type_array(a) || is_type_enumerated_array(a)) { - Type *tl = base_type(a); - lbValue lhs = lb_address_from_load_or_generate_local(p, left); - lbValue rhs = lb_address_from_load_or_generate_local(p, right); - - - TokenKind cmp_op = Token_And; - lbValue res = lb_const_bool(p->module, t_llvm_bool, true); - if (op_kind == Token_NotEq) { - res = lb_const_bool(p->module, t_llvm_bool, false); - cmp_op = Token_Or; - } else if (op_kind == Token_CmpEq) { - res = lb_const_bool(p->module, t_llvm_bool, true); - cmp_op = Token_And; - } - - bool inline_array_arith = type_size_of(tl) <= build_context.max_align; - i32 count = 0; - switch (tl->kind) { - case Type_Array: count = cast(i32)tl->Array.count; break; - case Type_EnumeratedArray: count = cast(i32)tl->EnumeratedArray.count; break; - } - - if (inline_array_arith) { - // inline - lbAddr val = lb_add_local_generated(p, t_bool, false); - lb_addr_store(p, val, res); - for (i32 i = 0; i < count; i++) { - lbValue x = lb_emit_load(p, lb_emit_array_epi(p, lhs, i)); - lbValue y = lb_emit_load(p, lb_emit_array_epi(p, rhs, i)); - lbValue cmp = lb_emit_comp(p, op_kind, x, y); - lbValue new_res = lb_emit_arith(p, cmp_op, lb_addr_load(p, val), cmp, t_bool); - lb_addr_store(p, val, lb_emit_conv(p, new_res, t_bool)); - } - - return lb_addr_load(p, val); - } else { - if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { - // TODO(bill): Test to see if this is actually faster!!!! - auto args = array_make<lbValue>(permanent_allocator(), 3); - args[0] = lb_emit_conv(p, lhs, t_rawptr); - args[1] = lb_emit_conv(p, rhs, t_rawptr); - args[2] = lb_const_int(p->module, t_int, type_size_of(tl)); - lbValue val = lb_emit_runtime_call(p, "memory_compare", args); - lbValue res = lb_emit_comp(p, op_kind, val, lb_const_nil(p->module, val.type)); - return lb_emit_conv(p, res, t_bool); - } else { - lbAddr val = lb_add_local_generated(p, t_bool, false); - lb_addr_store(p, val, res); - auto loop_data = lb_loop_start(p, count, t_i32); - { - lbValue i = loop_data.idx; - lbValue x = lb_emit_load(p, lb_emit_array_ep(p, lhs, i)); - lbValue y = lb_emit_load(p, lb_emit_array_ep(p, rhs, i)); - lbValue cmp = lb_emit_comp(p, op_kind, x, y); - lbValue new_res = lb_emit_arith(p, cmp_op, lb_addr_load(p, val), cmp, t_bool); - lb_addr_store(p, val, lb_emit_conv(p, new_res, t_bool)); - } - lb_loop_end(p, loop_data); - - return lb_addr_load(p, val); - } - } - } - - - if ((is_type_struct(a) || is_type_union(a)) && is_type_comparable(a)) { - return lb_compare_records(p, op_kind, left, right, a); - } - - if ((is_type_struct(b) || is_type_union(b)) && is_type_comparable(b)) { - return lb_compare_records(p, op_kind, left, right, b); - } - - if (is_type_string(a)) { - if (is_type_cstring(a)) { - left = lb_emit_conv(p, left, t_string); - right = lb_emit_conv(p, right, t_string); - } - - char const *runtime_procedure = nullptr; - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "string_eq"; break; - case Token_NotEq: runtime_procedure = "string_ne"; break; - case Token_Lt: runtime_procedure = "string_lt"; break; - case Token_Gt: runtime_procedure = "string_gt"; break; - case Token_LtEq: runtime_procedure = "string_le"; break; - case Token_GtEq: runtime_procedure = "string_gt"; break; - } - GB_ASSERT(runtime_procedure != nullptr); - - auto args = array_make<lbValue>(permanent_allocator(), 2); - args[0] = left; - args[1] = right; - return lb_emit_runtime_call(p, runtime_procedure, args); - } - - if (is_type_complex(a)) { - char const *runtime_procedure = ""; - i64 sz = 8*type_size_of(a); - switch (sz) { - case 32: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "complex32_eq"; break; - case Token_NotEq: runtime_procedure = "complex32_ne"; break; - } - break; - case 64: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "complex64_eq"; break; - case Token_NotEq: runtime_procedure = "complex64_ne"; break; - } - break; - case 128: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "complex128_eq"; break; - case Token_NotEq: runtime_procedure = "complex128_ne"; break; - } - break; - } - GB_ASSERT(runtime_procedure != nullptr); - - auto args = array_make<lbValue>(permanent_allocator(), 2); - args[0] = left; - args[1] = right; - return lb_emit_runtime_call(p, runtime_procedure, args); - } - - if (is_type_quaternion(a)) { - char const *runtime_procedure = ""; - i64 sz = 8*type_size_of(a); - switch (sz) { - case 64: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "quaternion64_eq"; break; - case Token_NotEq: runtime_procedure = "quaternion64_ne"; break; - } - break; - case 128: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "quaternion128_eq"; break; - case Token_NotEq: runtime_procedure = "quaternion128_ne"; break; - } - break; - case 256: - switch (op_kind) { - case Token_CmpEq: runtime_procedure = "quaternion256_eq"; break; - case Token_NotEq: runtime_procedure = "quaternion256_ne"; break; - } - break; - } - GB_ASSERT(runtime_procedure != nullptr); - - auto args = array_make<lbValue>(permanent_allocator(), 2); - args[0] = left; - args[1] = right; - return lb_emit_runtime_call(p, runtime_procedure, args); - } - - if (is_type_bit_set(a)) { - switch (op_kind) { - case Token_Lt: - case Token_LtEq: - case Token_Gt: - case Token_GtEq: - { - Type *it = bit_set_to_int(a); - lbValue lhs = lb_emit_transmute(p, left, it); - lbValue rhs = lb_emit_transmute(p, right, it); - lbValue res = lb_emit_arith(p, Token_And, lhs, rhs, it); - - if (op_kind == Token_Lt || op_kind == Token_LtEq) { - // (lhs & rhs) == lhs - res.value = LLVMBuildICmp(p->builder, LLVMIntEQ, res.value, lhs.value, ""); - res.type = t_llvm_bool; - } else if (op_kind == Token_Gt || op_kind == Token_GtEq) { - // (lhs & rhs) == rhs - res.value = LLVMBuildICmp(p->builder, LLVMIntEQ, res.value, rhs.value, ""); - res.type = t_llvm_bool; - } - - // NOTE(bill): Strict subsets - if (op_kind == Token_Lt || op_kind == Token_Gt) { - // res &~ (lhs == rhs) - lbValue eq = {}; - eq.value = LLVMBuildICmp(p->builder, LLVMIntEQ, lhs.value, rhs.value, ""); - eq.type = t_llvm_bool; - res = lb_emit_arith(p, Token_AndNot, res, eq, t_llvm_bool); - } - - return res; - } - - case Token_CmpEq: - case Token_NotEq: - { - LLVMIntPredicate pred = {}; - switch (op_kind) { - case Token_CmpEq: pred = LLVMIntEQ; break; - case Token_NotEq: pred = LLVMIntNE; break; - } - lbValue res = {}; - res.type = t_llvm_bool; - res.value = LLVMBuildICmp(p->builder, pred, left.value, right.value, ""); - return res; - } - } - } - - if (op_kind != Token_CmpEq && op_kind != Token_NotEq) { - Type *t = left.type; - if (is_type_integer(t) && is_type_different_to_arch_endianness(t)) { - Type *platform_type = integer_endian_type_to_platform_type(t); - lbValue x = lb_emit_byte_swap(p, left, platform_type); - lbValue y = lb_emit_byte_swap(p, right, platform_type); - left = x; - right = y; - } else if (is_type_float(t) && is_type_different_to_arch_endianness(t)) { - Type *platform_type = integer_endian_type_to_platform_type(t); - lbValue x = lb_emit_conv(p, left, platform_type); - lbValue y = lb_emit_conv(p, right, platform_type); - left = x; - right = y; - } - } - - a = core_type(left.type); - b = core_type(right.type); - - - lbValue res = {}; - res.type = t_llvm_bool; - if (is_type_integer(a) || - is_type_boolean(a) || - is_type_pointer(a) || - is_type_proc(a) || - is_type_enum(a)) { - LLVMIntPredicate pred = {}; - if (is_type_unsigned(left.type)) { - switch (op_kind) { - case Token_Gt: pred = LLVMIntUGT; break; - case Token_GtEq: pred = LLVMIntUGE; break; - case Token_Lt: pred = LLVMIntULT; break; - case Token_LtEq: pred = LLVMIntULE; break; - } - } else { - switch (op_kind) { - case Token_Gt: pred = LLVMIntSGT; break; - case Token_GtEq: pred = LLVMIntSGE; break; - case Token_Lt: pred = LLVMIntSLT; break; - case Token_LtEq: pred = LLVMIntSLE; break; - } - } - switch (op_kind) { - case Token_CmpEq: pred = LLVMIntEQ; break; - case Token_NotEq: pred = LLVMIntNE; break; - } - LLVMValueRef lhs = left.value; - LLVMValueRef rhs = right.value; - if (LLVMTypeOf(lhs) != LLVMTypeOf(rhs)) { - if (lb_is_type_kind(LLVMTypeOf(lhs), LLVMPointerTypeKind)) { - rhs = LLVMBuildPointerCast(p->builder, rhs, LLVMTypeOf(lhs), ""); - } - } - - res.value = LLVMBuildICmp(p->builder, pred, lhs, rhs, ""); - } else if (is_type_float(a)) { - LLVMRealPredicate pred = {}; - switch (op_kind) { - case Token_CmpEq: pred = LLVMRealOEQ; break; - case Token_Gt: pred = LLVMRealOGT; break; - case Token_GtEq: pred = LLVMRealOGE; break; - case Token_Lt: pred = LLVMRealOLT; break; - case Token_LtEq: pred = LLVMRealOLE; break; - case Token_NotEq: pred = LLVMRealONE; break; - } - res.value = LLVMBuildFCmp(p->builder, pred, left.value, right.value, ""); - } else if (is_type_typeid(a)) { - LLVMIntPredicate pred = {}; - switch (op_kind) { - case Token_Gt: pred = LLVMIntUGT; break; - case Token_GtEq: pred = LLVMIntUGE; break; - case Token_Lt: pred = LLVMIntULT; break; - case Token_LtEq: pred = LLVMIntULE; break; - case Token_CmpEq: pred = LLVMIntEQ; break; - case Token_NotEq: pred = LLVMIntNE; break; - } - res.value = LLVMBuildICmp(p->builder, pred, left.value, right.value, ""); - } else { - GB_PANIC("Unhandled comparison kind %s (%s) %.*s %s (%s)", type_to_string(left.type), type_to_string(base_type(left.type)), LIT(token_strings[op_kind]), type_to_string(right.type), type_to_string(base_type(right.type))); - } - - return res; -} - lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent) { lbProcedure **found = map_get(&m->gen->anonymous_proc_lits, hash_pointer(expr)); @@ -12252,816 +482,6 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A return value; } -lbValue lb_emit_union_cast_only_ok_check(lbProcedure *p, lbValue value, Type *type, TokenPos pos) { - GB_ASSERT(is_type_tuple(type)); - lbModule *m = p->module; - - Type *src_type = value.type; - bool is_ptr = is_type_pointer(src_type); - - - // IMPORTANT NOTE(bill): This assumes that the value is completely ignored - // so when it does an assignment, it complete ignores the value. - // Just make it two booleans and ignore the first one - // - // _, ok := x.(T); - // - Type *ok_type = type->Tuple.variables[1]->type; - Type *gen_tuple_types[2] = {}; - gen_tuple_types[0] = ok_type; - gen_tuple_types[1] = ok_type; - - Type *gen_tuple = alloc_type_tuple_from_field_types(gen_tuple_types, gb_count_of(gen_tuple_types), false, true); - - lbAddr v = lb_add_local_generated(p, gen_tuple, false); - - if (is_ptr) { - value = lb_emit_load(p, value); - } - Type *src = base_type(type_deref(src_type)); - GB_ASSERT_MSG(is_type_union(src), "%s", type_to_string(src_type)); - Type *dst = type->Tuple.variables[0]->type; - - lbValue cond = {}; - - if (is_type_union_maybe_pointer(src)) { - lbValue data = lb_emit_transmute(p, value, dst); - cond = lb_emit_comp_against_nil(p, Token_NotEq, data); - } else { - lbValue tag = lb_emit_union_tag_value(p, value); - lbValue dst_tag = lb_const_union_tag(m, src, dst); - cond = lb_emit_comp(p, Token_CmpEq, tag, dst_tag); - } - - lbValue gep1 = lb_emit_struct_ep(p, v.addr, 1); - lb_emit_store(p, gep1, cond); - - return lb_addr_load(p, v); -} - -lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) { - lbModule *m = p->module; - - Type *src_type = value.type; - bool is_ptr = is_type_pointer(src_type); - - bool is_tuple = true; - Type *tuple = type; - if (type->kind != Type_Tuple) { - is_tuple = false; - tuple = make_optional_ok_type(type); - } - - lbAddr v = lb_add_local_generated(p, tuple, true); - - if (is_ptr) { - value = lb_emit_load(p, value); - } - Type *src = base_type(type_deref(src_type)); - GB_ASSERT_MSG(is_type_union(src), "%s", type_to_string(src_type)); - Type *dst = tuple->Tuple.variables[0]->type; - - lbValue value_ = lb_address_from_load_or_generate_local(p, value); - - lbValue tag = {}; - lbValue dst_tag = {}; - lbValue cond = {}; - lbValue data = {}; - - lbValue gep0 = lb_emit_struct_ep(p, v.addr, 0); - lbValue gep1 = lb_emit_struct_ep(p, v.addr, 1); - - if (is_type_union_maybe_pointer(src)) { - data = lb_emit_load(p, lb_emit_conv(p, value_, gep0.type)); - } else { - tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, value_)); - dst_tag = lb_const_union_tag(m, src, dst); - } - - lbBlock *ok_block = lb_create_block(p, "union_cast.ok"); - lbBlock *end_block = lb_create_block(p, "union_cast.end"); - - if (data.value != nullptr) { - GB_ASSERT(is_type_union_maybe_pointer(src)); - cond = lb_emit_comp_against_nil(p, Token_NotEq, data); - } else { - cond = lb_emit_comp(p, Token_CmpEq, tag, dst_tag); - } - - lb_emit_if(p, cond, ok_block, end_block); - lb_start_block(p, ok_block); - - - - if (data.value == nullptr) { - data = lb_emit_load(p, lb_emit_conv(p, value_, gep0.type)); - } - lb_emit_store(p, gep0, data); - lb_emit_store(p, gep1, lb_const_bool(m, t_bool, true)); - - lb_emit_jump(p, end_block); - lb_start_block(p, end_block); - - if (!is_tuple) { - { - // NOTE(bill): Panic on invalid conversion - Type *dst_type = tuple->Tuple.variables[0]->type; - - lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make<lbValue>(permanent_allocator(), 7); - args[0] = ok; - - args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); - args[2] = lb_const_int(m, t_i32, pos.line); - args[3] = lb_const_int(m, t_i32, pos.column); - - args[4] = lb_typeid(m, src_type); - args[5] = lb_typeid(m, dst_type); - args[6] = lb_emit_conv(p, value_, t_rawptr); - lb_emit_runtime_call(p, "type_assertion_check2", args); - } - - return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0)); - } - return lb_addr_load(p, v); -} - -lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos pos) { - lbModule *m = p->module; - - Type *src_type = value.type; - - if (is_type_pointer(src_type)) { - value = lb_emit_load(p, value); - } - - bool is_tuple = true; - Type *tuple = type; - if (type->kind != Type_Tuple) { - is_tuple = false; - tuple = make_optional_ok_type(type); - } - Type *dst_type = tuple->Tuple.variables[0]->type; - - lbAddr v = lb_add_local_generated(p, tuple, true); - - lbValue dst_typeid = lb_typeid(m, dst_type); - lbValue any_typeid = lb_emit_struct_ev(p, value, 1); - - - lbBlock *ok_block = lb_create_block(p, "any_cast.ok"); - lbBlock *end_block = lb_create_block(p, "any_cast.end"); - lbValue cond = lb_emit_comp(p, Token_CmpEq, any_typeid, dst_typeid); - lb_emit_if(p, cond, ok_block, end_block); - lb_start_block(p, ok_block); - - lbValue gep0 = lb_emit_struct_ep(p, v.addr, 0); - lbValue gep1 = lb_emit_struct_ep(p, v.addr, 1); - - lbValue any_data = lb_emit_struct_ev(p, value, 0); - lbValue ptr = lb_emit_conv(p, any_data, alloc_type_pointer(dst_type)); - lb_emit_store(p, gep0, lb_emit_load(p, ptr)); - lb_emit_store(p, gep1, lb_const_bool(m, t_bool, true)); - - lb_emit_jump(p, end_block); - lb_start_block(p, end_block); - - if (!is_tuple) { - // NOTE(bill): Panic on invalid conversion - - lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make<lbValue>(permanent_allocator(), 7); - args[0] = ok; - - args[1] = lb_const_string(m, get_file_path_string(pos.file_id)); - args[2] = lb_const_int(m, t_i32, pos.line); - args[3] = lb_const_int(m, t_i32, pos.column); - - args[4] = any_typeid; - args[5] = dst_typeid; - args[6] = lb_emit_struct_ev(p, value, 0);; - lb_emit_runtime_call(p, "type_assertion_check2", args); - - return lb_addr(lb_emit_struct_ep(p, v.addr, 0)); - } - return v; -} -lbValue lb_emit_any_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) { - return lb_addr_load(p, lb_emit_any_cast_addr(p, value, type, pos)); -} - - -lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *expr) { - auto *found = map_get(&m->values, hash_entity(e)); - if (found) { - auto v = *found; - // 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 lb_addr_load(p, lb_build_addr(p, expr)); - } - - if (e->kind == Entity_Procedure) { - return lb_find_procedure_value_from_entity(m, e); - } - if (USE_SEPARATE_MODULES) { - lbModule *other_module = lb_pkg_module(m->gen, e->pkg); - if (other_module != m) { - - String name = lb_get_entity_name(other_module, e); - - lb_set_entity_from_other_modules_linkage_correctly(other_module, e, name); - - lbValue g = {}; - g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); - g.type = alloc_type_pointer(e->type); - LLVMSetLinkage(g.value, LLVMExternalLinkage); - - lb_add_entity(m, e, g); - lb_add_member(m, name, g); - return lb_emit_load(p, g); - } - } - - String pkg = {}; - if (e->pkg) { - pkg = e->pkg->name; - } - gb_printf_err("Error in: %s\n", token_pos_to_string(ast_token(expr).pos)); - GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(pkg), LIT(e->token.string), e, type_to_string(e->type), expr); - return {}; -} - -bool lb_is_expr_constant_zero(Ast *expr) { - GB_ASSERT(expr != nullptr); - auto v = exact_value_to_integer(expr->tav.value); - if (v.kind == ExactValue_Integer) { - return big_int_cmp_zero(&v.value_integer) == 0; - } - return false; -} - -lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { - ast_node(ue, UnaryExpr, expr); - auto tv = type_and_value_of_expr(expr); - - - Ast *ue_expr = unparen_expr(ue->expr); - if (ue_expr->kind == Ast_IndexExpr && tv.mode == Addressing_OptionalOkPtr && is_type_tuple(tv.type)) { - Type *tuple = tv.type; - - Type *map_type = type_of_expr(ue_expr->IndexExpr.expr); - Type *ot = base_type(map_type); - Type *t = base_type(type_deref(ot)); - bool deref = t != ot; - GB_ASSERT(t->kind == Type_Map); - ast_node(ie, IndexExpr, ue_expr); - - lbValue map_val = lb_build_addr_ptr(p, ie->expr); - if (deref) { - map_val = lb_emit_load(p, map_val); - } - - lbValue key = lb_build_expr(p, ie->index); - key = lb_emit_conv(p, key, t->Map.key); - - Type *result_type = type_of_expr(expr); - lbAddr addr = lb_addr_map(map_val, key, t, alloc_type_pointer(t->Map.value)); - lbValue ptr = lb_addr_get_ptr(p, addr); - - lbValue ok = lb_emit_comp_against_nil(p, Token_NotEq, ptr); - ok = lb_emit_conv(p, ok, tuple->Tuple.variables[1]->type); - - lbAddr res = lb_add_local_generated(p, tuple, false); - lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0); - lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1); - lb_emit_store(p, gep0, ptr); - lb_emit_store(p, gep1, ok); - return lb_addr_load(p, res); - - } if (ue_expr->kind == Ast_CompoundLit) { - lbValue v = lb_build_expr(p, ue->expr); - - Type *type = v.type; - lbAddr addr = {}; - if (p->is_startup) { - addr = lb_add_global_generated(p->module, type, v); - } else { - addr = lb_add_local_generated(p, type, false); - } - lb_addr_store(p, addr, v); - return addr.addr; - - } else if (ue_expr->kind == Ast_TypeAssertion) { - if (is_type_tuple(tv.type)) { - Type *tuple = tv.type; - Type *ptr_type = tuple->Tuple.variables[0]->type; - Type *ok_type = tuple->Tuple.variables[1]->type; - - ast_node(ta, TypeAssertion, ue_expr); - TokenPos pos = ast_token(expr).pos; - Type *type = type_of_expr(ue_expr); - GB_ASSERT(!is_type_tuple(type)); - - lbValue e = lb_build_expr(p, ta->expr); - Type *t = type_deref(e.type); - if (is_type_union(t)) { - lbValue v = e; - if (!is_type_pointer(v.type)) { - v = lb_address_from_load_or_generate_local(p, v); - } - Type *src_type = type_deref(v.type); - Type *dst_type = type; - - lbValue src_tag = {}; - lbValue dst_tag = {}; - if (is_type_union_maybe_pointer(src_type)) { - src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v); - dst_tag = lb_const_bool(p->module, t_bool, true); - } else { - src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); - dst_tag = lb_const_union_tag(p->module, src_type, dst_type); - } - - lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - - lbValue data_ptr = lb_emit_conv(p, v, ptr_type); - lbAddr res = lb_add_local_generated(p, tuple, true); - lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0); - lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1); - lb_emit_store(p, gep0, lb_emit_select(p, ok, data_ptr, lb_const_nil(p->module, ptr_type))); - lb_emit_store(p, gep1, lb_emit_conv(p, ok, ok_type)); - return lb_addr_load(p, res); - } else if (is_type_any(t)) { - lbValue v = e; - if (is_type_pointer(v.type)) { - v = lb_emit_load(p, v); - } - - lbValue data_ptr = lb_emit_conv(p, lb_emit_struct_ev(p, v, 0), ptr_type); - lbValue any_id = lb_emit_struct_ev(p, v, 1); - lbValue id = lb_typeid(p->module, type); - - lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); - - lbAddr res = lb_add_local_generated(p, tuple, false); - lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0); - lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1); - lb_emit_store(p, gep0, lb_emit_select(p, ok, data_ptr, lb_const_nil(p->module, ptr_type))); - lb_emit_store(p, gep1, lb_emit_conv(p, ok, ok_type)); - return lb_addr_load(p, res); - } else { - GB_PANIC("TODO(bill): type assertion %s", type_to_string(type)); - } - - } else { - GB_ASSERT(is_type_pointer(tv.type)); - - ast_node(ta, TypeAssertion, ue_expr); - TokenPos pos = ast_token(expr).pos; - Type *type = type_of_expr(ue_expr); - GB_ASSERT(!is_type_tuple(type)); - - lbValue e = lb_build_expr(p, ta->expr); - Type *t = type_deref(e.type); - if (is_type_union(t)) { - lbValue v = e; - if (!is_type_pointer(v.type)) { - v = lb_address_from_load_or_generate_local(p, v); - } - Type *src_type = type_deref(v.type); - Type *dst_type = type; - - lbValue src_tag = {}; - lbValue dst_tag = {}; - if (is_type_union_maybe_pointer(src_type)) { - src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v); - dst_tag = lb_const_bool(p->module, t_bool, true); - } else { - src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); - dst_tag = lb_const_union_tag(p->module, src_type, dst_type); - } - - lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - auto args = array_make<lbValue>(permanent_allocator(), 6); - args[0] = ok; - - args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); - args[2] = lb_const_int(p->module, t_i32, pos.line); - args[3] = lb_const_int(p->module, t_i32, pos.column); - - args[4] = lb_typeid(p->module, src_type); - args[5] = lb_typeid(p->module, dst_type); - lb_emit_runtime_call(p, "type_assertion_check", args); - - lbValue data_ptr = v; - return lb_emit_conv(p, data_ptr, tv.type); - } else if (is_type_any(t)) { - lbValue v = e; - if (is_type_pointer(v.type)) { - v = lb_emit_load(p, v); - } - - lbValue data_ptr = lb_emit_struct_ev(p, v, 0); - lbValue any_id = lb_emit_struct_ev(p, v, 1); - lbValue id = lb_typeid(p->module, type); - - - lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); - auto args = array_make<lbValue>(permanent_allocator(), 6); - args[0] = ok; - - args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); - args[2] = lb_const_int(p->module, t_i32, pos.line); - args[3] = lb_const_int(p->module, t_i32, pos.column); - - args[4] = any_id; - args[5] = id; - lb_emit_runtime_call(p, "type_assertion_check", args); - - return lb_emit_conv(p, data_ptr, tv.type); - } else { - GB_PANIC("TODO(bill): type assertion %s", type_to_string(type)); - } - } - } - - return lb_build_addr_ptr(p, ue->expr); -} - -lbValue lb_build_expr(lbProcedure *p, Ast *expr) { - lbModule *m = p->module; - - u16 prev_state_flags = p->state_flags; - defer (p->state_flags = prev_state_flags); - - if (expr->state_flags != 0) { - u16 in = expr->state_flags; - u16 out = p->state_flags; - - if (in & StateFlag_bounds_check) { - out |= StateFlag_bounds_check; - out &= ~StateFlag_no_bounds_check; - } else if (in & StateFlag_no_bounds_check) { - out |= StateFlag_no_bounds_check; - out &= ~StateFlag_bounds_check; - } - - p->state_flags = out; - } - - expr = unparen_expr(expr); - - TokenPos expr_pos = ast_token(expr).pos; - TypeAndValue tv = type_and_value_of_expr(expr); - GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type)); - - if (tv.value.kind != ExactValue_Invalid) { - // NOTE(bill): The commented out code below is just for debug purposes only - // GB_ASSERT_MSG(!is_type_untyped(tv.type), "%s @ %s\n%s", type_to_string(tv.type), token_pos_to_string(expr_pos), expr_to_string(expr)); - // if (is_type_untyped(tv.type)) { - // gb_printf_err("%s %s\n", token_pos_to_string(expr_pos), expr_to_string(expr)); - // } - - // NOTE(bill): Short on constant values - return lb_const_value(p->module, tv.type, tv.value); - } - - #if 0 - LLVMMetadataRef prev_debug_location = nullptr; - if (p->debug_info != nullptr) { - prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder); - LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, expr)); - } - defer (if (prev_debug_location != nullptr) { - LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location); - }); - #endif - - switch (expr->kind) { - case_ast_node(bl, BasicLit, expr); - TokenPos pos = bl->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(token_strings[bl->token.kind])); - case_end; - - case_ast_node(bd, BasicDirective, expr); - TokenPos pos = bd->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string)); - case_end; - - case_ast_node(i, Implicit, expr); - return lb_addr_load(p, lb_build_addr(p, expr)); - case_end; - - case_ast_node(u, Undef, expr) - lbValue res = {}; - if (is_type_untyped(tv.type)) { - res.value = nullptr; - res.type = t_untyped_undef; - } else { - res.value = LLVMGetUndef(lb_type(m, tv.type)); - res.type = tv.type; - } - return res; - case_end; - - case_ast_node(i, Ident, expr); - Entity *e = entity_from_expr(expr); - e = strip_entity_wrapping(e); - - GB_ASSERT_MSG(e != nullptr, "%s", expr_to_string(expr)); - if (e->kind == Entity_Builtin) { - Token token = ast_token(expr); - GB_PANIC("TODO(bill): lb_build_expr Entity_Builtin '%.*s'\n" - "\t at %s", LIT(builtin_procs[e->Builtin.id].name), - token_pos_to_string(token.pos)); - return {}; - } else if (e->kind == Entity_Nil) { - lbValue res = {}; - res.value = nullptr; - res.type = e->type; - return res; - } - GB_ASSERT(e->kind != Entity_ProcGroup); - - return lb_find_ident(p, m, e, expr); - case_end; - - case_ast_node(de, DerefExpr, expr); - return lb_addr_load(p, lb_build_addr(p, expr)); - case_end; - - case_ast_node(se, SelectorExpr, expr); - TypeAndValue tav = type_and_value_of_expr(expr); - GB_ASSERT(tav.mode != Addressing_Invalid); - return lb_addr_load(p, lb_build_addr(p, expr)); - case_end; - - case_ast_node(ise, ImplicitSelectorExpr, expr); - TypeAndValue tav = type_and_value_of_expr(expr); - GB_ASSERT(tav.mode == Addressing_Constant); - - return lb_const_value(p->module, tv.type, tv.value); - case_end; - - case_ast_node(se, SelectorCallExpr, expr); - GB_ASSERT(se->modified_call); - TypeAndValue tav = type_and_value_of_expr(expr); - GB_ASSERT(tav.mode != Addressing_Invalid); - lbValue res = lb_build_call_expr(p, se->call); - - ast_node(ce, CallExpr, se->call); - ce->sce_temp_data = gb_alloc_copy(permanent_allocator(), &res, gb_size_of(res)); - - return res; - case_end; - - case_ast_node(te, TernaryIfExpr, expr); - LLVMValueRef incoming_values[2] = {}; - LLVMBasicBlockRef incoming_blocks[2] = {}; - - GB_ASSERT(te->y != nullptr); - lbBlock *then = lb_create_block(p, "if.then"); - lbBlock *done = lb_create_block(p, "if.done"); // NOTE(bill): Append later - lbBlock *else_ = lb_create_block(p, "if.else"); - - lbValue cond = lb_build_cond(p, te->cond, then, else_); - lb_start_block(p, then); - - Type *type = default_type(type_of_expr(expr)); - - lb_open_scope(p, nullptr); - incoming_values[0] = lb_emit_conv(p, lb_build_expr(p, te->x), type).value; - lb_close_scope(p, lbDeferExit_Default, nullptr); - - lb_emit_jump(p, done); - lb_start_block(p, else_); - - lb_open_scope(p, nullptr); - incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, te->y), type).value; - lb_close_scope(p, lbDeferExit_Default, nullptr); - - lb_emit_jump(p, done); - lb_start_block(p, done); - - lbValue res = {}; - res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), ""); - res.type = type; - - GB_ASSERT(p->curr_block->preds.count >= 2); - incoming_blocks[0] = p->curr_block->preds[0]->block; - incoming_blocks[1] = p->curr_block->preds[1]->block; - - LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2); - - return res; - case_end; - - case_ast_node(te, TernaryWhenExpr, expr); - TypeAndValue tav = type_and_value_of_expr(te->cond); - GB_ASSERT(tav.mode == Addressing_Constant); - GB_ASSERT(tav.value.kind == ExactValue_Bool); - if (tav.value.value_bool) { - return lb_build_expr(p, te->x); - } else { - return lb_build_expr(p, te->y); - } - case_end; - - case_ast_node(ta, TypeAssertion, expr); - TokenPos pos = ast_token(expr).pos; - Type *type = tv.type; - lbValue e = lb_build_expr(p, ta->expr); - Type *t = type_deref(e.type); - if (is_type_union(t)) { - if (ta->ignores[0]) { - // NOTE(bill): This is not needed for optimization levels other than 0 - return lb_emit_union_cast_only_ok_check(p, e, type, pos); - } - return lb_emit_union_cast(p, e, type, pos); - } else if (is_type_any(t)) { - return lb_emit_any_cast(p, e, type, pos); - } else { - GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type)); - } - case_end; - - case_ast_node(tc, TypeCast, expr); - lbValue e = lb_build_expr(p, tc->expr); - switch (tc->token.kind) { - case Token_cast: - return lb_emit_conv(p, e, tv.type); - case Token_transmute: - return lb_emit_transmute(p, e, tv.type); - } - GB_PANIC("Invalid AST TypeCast"); - case_end; - - case_ast_node(ac, AutoCast, expr); - lbValue value = lb_build_expr(p, ac->expr); - return lb_emit_conv(p, value, tv.type); - case_end; - - case_ast_node(ue, UnaryExpr, expr); - switch (ue->op.kind) { - case Token_And: - return lb_build_unary_and(p, expr); - default: - { - lbValue v = lb_build_expr(p, ue->expr); - return lb_emit_unary_arith(p, ue->op.kind, v, tv.type); - } - } - case_end; - - case_ast_node(be, BinaryExpr, expr); - return lb_build_binary_expr(p, expr); - case_end; - - case_ast_node(pl, ProcLit, expr); - return lb_generate_anonymous_proc_lit(p->module, p->name, expr, p); - case_end; - - case_ast_node(cl, CompoundLit, expr); - return lb_addr_load(p, lb_build_addr(p, expr)); - case_end; - - case_ast_node(ce, CallExpr, expr); - return lb_build_call_expr(p, expr); - case_end; - - case_ast_node(se, SliceExpr, expr); - if (is_type_slice(type_of_expr(se->expr))) { - // NOTE(bill): Quick optimization - if (se->high == nullptr && - (se->low == nullptr || lb_is_expr_constant_zero(se->low))) { - return lb_build_expr(p, se->expr); - } - } - return lb_addr_load(p, lb_build_addr(p, expr)); - case_end; - - case_ast_node(ie, IndexExpr, expr); - return lb_addr_load(p, lb_build_addr(p, expr)); - case_end; - - case_ast_node(ia, InlineAsmExpr, expr); - Type *t = type_of_expr(expr); - GB_ASSERT(is_type_asm_proc(t)); - - String asm_string = {}; - String constraints_string = {}; - - TypeAndValue tav; - tav = type_and_value_of_expr(ia->asm_string); - GB_ASSERT(is_type_string(tav.type)); - GB_ASSERT(tav.value.kind == ExactValue_String); - asm_string = tav.value.value_string; - - tav = type_and_value_of_expr(ia->constraints_string); - GB_ASSERT(is_type_string(tav.type)); - GB_ASSERT(tav.value.kind == ExactValue_String); - constraints_string = tav.value.value_string; - - - LLVMInlineAsmDialect dialect = LLVMInlineAsmDialectATT; - switch (ia->dialect) { - case InlineAsmDialect_Default: dialect = LLVMInlineAsmDialectATT; break; - case InlineAsmDialect_ATT: dialect = LLVMInlineAsmDialectATT; break; - case InlineAsmDialect_Intel: dialect = LLVMInlineAsmDialectIntel; break; - default: GB_PANIC("Unhandled inline asm dialect"); break; - } - - LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, t)); - LLVMValueRef the_asm = LLVMGetInlineAsm(func_type, - cast(char *)asm_string.text, cast(size_t)asm_string.len, - cast(char *)constraints_string.text, cast(size_t)constraints_string.len, - ia->has_side_effects, ia->is_align_stack, dialect - ); - GB_ASSERT(the_asm != nullptr); - return {the_asm, t}; - case_end; - } - - GB_PANIC("lb_build_expr: %.*s", LIT(ast_strings[expr->kind])); - - return {}; -} - -lbAddr lb_get_soa_variable_addr(lbProcedure *p, Entity *e) { - return map_must_get(&p->module->soa_values, hash_entity(e)); -} -lbValue lb_get_using_variable(lbProcedure *p, Entity *e) { - GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using); - String name = e->token.string; - Entity *parent = e->using_parent; - Selection sel = lookup_field(parent->type, name, false); - GB_ASSERT(sel.entity != nullptr); - lbValue *pv = map_get(&p->module->values, hash_entity(parent)); - - lbValue v = {}; - - if (pv == nullptr && parent->flags & EntityFlag_SoaPtrField) { - // NOTE(bill): using SOA value (probably from for-in statement) - lbAddr parent_addr = lb_get_soa_variable_addr(p, parent); - v = lb_addr_get_ptr(p, parent_addr); - } else if (pv != nullptr) { - v = *pv; - } else { - GB_ASSERT_MSG(e->using_expr != nullptr, "%.*s", LIT(name)); - v = lb_build_addr_ptr(p, e->using_expr); - } - GB_ASSERT(v.value != nullptr); - GB_ASSERT_MSG(parent->type == type_deref(v.type), "%s %s", type_to_string(parent->type), type_to_string(v.type)); - lbValue ptr = lb_emit_deep_field_gep(p, v, sel); - if (parent->scope) { - if ((parent->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) { - lb_add_debug_local_variable(p, ptr.value, e->type, e->token); - } - } else { - lb_add_debug_local_variable(p, ptr.value, e->type, e->token); - } - return ptr; -} - - -lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) { - GB_ASSERT(e != nullptr); - if (e->kind == Entity_Constant) { - Type *t = default_type(type_of_expr(expr)); - lbValue v = lb_const_value(p->module, t, e->Constant.value); - lbAddr g = lb_add_global_generated(p->module, t, v); - return g; - } - - - lbValue v = {}; - lbValue *found = map_get(&p->module->values, hash_entity(e)); - if (found) { - v = *found; - } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { - // NOTE(bill): Calculate the using variable every time - v = lb_get_using_variable(p, e); - } else if (e->flags & EntityFlag_SoaPtrField) { - return lb_get_soa_variable_addr(p, e); - } - - - if (v.value == nullptr) { - return lb_addr(lb_find_value_from_entity(p->module, e)); - - // error(expr, "%.*s Unknown value: %.*s, entity: %p %.*s", - // LIT(p->name), - // LIT(e->token.string), e, LIT(entity_strings[e->kind])); - // GB_PANIC("Unknown value"); - } - - return lb_addr(v); -} - lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { GB_ASSERT_MSG(is_type_pointer(map_val_ptr.type), "%s", type_to_string(map_val_ptr.type)); lbAddr h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later @@ -13190,2091 +610,6 @@ void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_ } -lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { - expr = unparen_expr(expr); - - switch (expr->kind) { - case_ast_node(i, Implicit, expr); - lbAddr v = {}; - switch (i->kind) { - case Token_context: - v = lb_find_or_generate_context_ptr(p); - break; - } - - GB_ASSERT(v.addr.value != nullptr); - return v; - case_end; - - case_ast_node(i, Ident, expr); - if (is_blank_ident(expr)) { - lbAddr val = {}; - return val; - } - String name = i->token.string; - Entity *e = entity_of_node(expr); - return lb_build_addr_from_entity(p, e, expr); - case_end; - - case_ast_node(se, SelectorExpr, expr); - Ast *sel = unparen_expr(se->selector); - if (sel->kind == Ast_Ident) { - String selector = sel->Ident.token.string; - TypeAndValue tav = type_and_value_of_expr(se->expr); - - if (tav.mode == Addressing_Invalid) { - // NOTE(bill): Imports - Entity *imp = entity_of_node(se->expr); - if (imp != nullptr) { - GB_ASSERT(imp->kind == Entity_ImportName); - } - return lb_build_addr(p, unparen_expr(se->selector)); - } - - - Type *type = base_type(tav.type); - if (tav.mode == Addressing_Type) { // Addressing_Type - GB_PANIC("Unreachable"); - } - - if (se->swizzle_count > 0) { - Type *array_type = base_type(type_deref(tav.type)); - GB_ASSERT(array_type->kind == Type_Array); - u8 swizzle_count = se->swizzle_count; - u8 swizzle_indices_raw = se->swizzle_indices; - u8 swizzle_indices[4] = {}; - for (u8 i = 0; i < swizzle_count; i++) { - u8 index = swizzle_indices_raw>>(i*2) & 3; - swizzle_indices[i] = index; - } - lbValue a = {}; - if (is_type_pointer(tav.type)) { - a = lb_build_expr(p, se->expr); - } else { - lbAddr addr = lb_build_addr(p, se->expr); - a = lb_addr_get_ptr(p, addr); - } - - GB_ASSERT(is_type_array(expr->tav.type)); - return lb_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices); - } - - Selection sel = lookup_field(type, selector, false); - GB_ASSERT(sel.entity != nullptr); - - { - lbAddr addr = lb_build_addr(p, se->expr); - if (addr.kind == lbAddr_Map) { - lbValue v = lb_addr_load(p, addr); - lbValue a = lb_address_from_load_or_generate_local(p, v); - a = lb_emit_deep_field_gep(p, a, sel); - return lb_addr(a); - } else if (addr.kind == lbAddr_Context) { - GB_ASSERT(sel.index.count > 0); - if (addr.ctx.sel.index.count >= 0) { - sel = selection_combine(addr.ctx.sel, sel); - } - addr.ctx.sel = sel; - addr.kind = lbAddr_Context; - return addr; - } else if (addr.kind == lbAddr_SoaVariable) { - lbValue index = addr.soa.index; - i32 first_index = sel.index[0]; - Selection sub_sel = sel; - sub_sel.index.data += 1; - sub_sel.index.count -= 1; - - lbValue arr = lb_emit_struct_ep(p, addr.addr, first_index); - - Type *t = base_type(type_deref(addr.addr.type)); - GB_ASSERT(is_type_soa_struct(t)); - - if (addr.soa.index_expr != nullptr && (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) { - lbValue len = lb_soa_struct_len(p, addr.addr); - lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); - } - - lbValue item = {}; - - if (t->Struct.soa_kind == StructSoa_Fixed) { - item = lb_emit_array_ep(p, arr, index); - } else { - item = lb_emit_ptr_offset(p, lb_emit_load(p, arr), index); - } - if (sub_sel.index.count > 0) { - item = lb_emit_deep_field_gep(p, item, sub_sel); - } - return lb_addr(item); - } else if (addr.kind == lbAddr_Swizzle) { - GB_ASSERT(sel.index.count > 0); - // NOTE(bill): just patch the index in place - sel.index[0] = addr.swizzle.indices[sel.index[0]]; - } - lbValue a = lb_addr_get_ptr(p, addr); - a = lb_emit_deep_field_gep(p, a, sel); - return lb_addr(a); - } - } else { - GB_PANIC("Unsupported selector expression"); - } - case_end; - - case_ast_node(se, SelectorCallExpr, expr); - GB_ASSERT(se->modified_call); - TypeAndValue tav = type_and_value_of_expr(expr); - GB_ASSERT(tav.mode != Addressing_Invalid); - lbValue e = lb_build_expr(p, expr); - return lb_addr(lb_address_from_load_or_generate_local(p, e)); - case_end; - - case_ast_node(ta, TypeAssertion, expr); - TokenPos pos = ast_token(expr).pos; - lbValue e = lb_build_expr(p, ta->expr); - Type *t = type_deref(e.type); - if (is_type_union(t)) { - Type *type = type_of_expr(expr); - lbAddr v = lb_add_local_generated(p, type, false); - lb_addr_store(p, v, lb_emit_union_cast(p, lb_build_expr(p, ta->expr), type, pos)); - return v; - } else if (is_type_any(t)) { - Type *type = type_of_expr(expr); - return lb_emit_any_cast_addr(p, lb_build_expr(p, ta->expr), type, pos); - } else { - GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type)); - } - case_end; - - case_ast_node(ue, UnaryExpr, expr); - switch (ue->op.kind) { - case Token_And: { - lbValue ptr = lb_build_expr(p, expr); - return lb_addr(lb_address_from_load_or_generate_local(p, ptr)); - } - default: - GB_PANIC("Invalid unary expression for lb_build_addr"); - } - case_end; - case_ast_node(be, BinaryExpr, expr); - lbValue v = lb_build_expr(p, expr); - Type *t = v.type; - if (is_type_pointer(t)) { - return lb_addr(v); - } - return lb_addr(lb_address_from_load_or_generate_local(p, v)); - case_end; - - case_ast_node(ie, IndexExpr, expr); - Type *t = base_type(type_of_expr(ie->expr)); - - bool deref = is_type_pointer(t); - t = base_type(type_deref(t)); - if (is_type_soa_struct(t)) { - // SOA STRUCTURES!!!! - lbValue val = lb_build_addr_ptr(p, ie->expr); - if (deref) { - val = lb_emit_load(p, val); - } - - lbValue index = lb_build_expr(p, ie->index); - return lb_addr_soa_variable(val, index, ie->index); - } - - if (ie->expr->tav.mode == Addressing_SoaVariable) { - // SOA Structures for slices/dynamic arrays - GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); - - lbValue field = lb_build_expr(p, ie->expr); - lbValue index = lb_build_expr(p, ie->index); - - - if (!build_context.no_bounds_check) { - // TODO HACK(bill): Clean up this hack to get the length for bounds checking - // GB_ASSERT(LLVMIsALoadInst(field.value)); - - // lbValue a = {}; - // a.value = LLVMGetOperand(field.value, 0); - // a.type = alloc_type_pointer(field.type); - - // irInstr *b = &a->Instr; - // GB_ASSERT(b->kind == irInstr_StructElementPtr); - // lbValue base_struct = b->StructElementPtr.address; - - // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); - // lbValue len = ir_soa_struct_len(p, base_struct); - // lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - - lbValue val = lb_emit_ptr_offset(p, field, index); - return lb_addr(val); - } - - GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); - - if (is_type_map(t)) { - lbValue map_val = lb_build_addr_ptr(p, ie->expr); - if (deref) { - map_val = lb_emit_load(p, map_val); - } - - lbValue key = lb_build_expr(p, ie->index); - key = lb_emit_conv(p, key, t->Map.key); - - Type *result_type = type_of_expr(expr); - return lb_addr_map(map_val, key, t, result_type); - } - - switch (t->kind) { - case Type_Array: { - lbValue array = {}; - array = lb_build_addr_ptr(p, ie->expr); - if (deref) { - array = lb_emit_load(p, array); - } - lbValue index = lb_build_expr(p, ie->index); - index = lb_emit_conv(p, index, t_int); - lbValue elem = lb_emit_array_ep(p, array, index); - - auto index_tv = type_and_value_of_expr(ie->index); - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->Array.count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return lb_addr(elem); - } - - case Type_EnumeratedArray: { - lbValue array = {}; - array = lb_build_addr_ptr(p, ie->expr); - if (deref) { - array = lb_emit_load(p, array); - } - - Type *index_type = t->EnumeratedArray.index; - - auto index_tv = type_and_value_of_expr(ie->index); - - lbValue index = {}; - if (compare_exact_values(Token_NotEq, t->EnumeratedArray.min_value, exact_value_i64(0))) { - if (index_tv.mode == Addressing_Constant) { - ExactValue idx = exact_value_sub(index_tv.value, t->EnumeratedArray.min_value); - index = lb_const_value(p->module, index_type, idx); - } else { - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, t->EnumeratedArray.min_value), index_type); - } - } else { - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - } - - lbValue elem = lb_emit_array_ep(p, array, index); - - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->EnumeratedArray.count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return lb_addr(elem); - } - - case Type_Slice: { - lbValue slice = {}; - slice = lb_build_expr(p, ie->expr); - if (deref) { - slice = lb_emit_load(p, slice); - } - lbValue elem = lb_slice_elem(p, slice); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lbValue len = lb_slice_len(p, slice); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } - - case Type_RelativeSlice: { - lbAddr slice_addr = {}; - if (deref) { - slice_addr = lb_addr(lb_build_expr(p, ie->expr)); - } else { - slice_addr = lb_build_addr(p, ie->expr); - } - lbValue slice = lb_addr_load(p, slice_addr); - - lbValue elem = lb_slice_elem(p, slice); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lbValue len = lb_slice_len(p, slice); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } - - case Type_DynamicArray: { - lbValue dynamic_array = {}; - dynamic_array = lb_build_expr(p, ie->expr); - if (deref) { - dynamic_array = lb_emit_load(p, dynamic_array); - } - lbValue elem = lb_dynamic_array_elem(p, dynamic_array); - lbValue len = lb_dynamic_array_len(p, dynamic_array); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } - - - case Type_Basic: { // Basic_string - lbValue str; - lbValue elem; - lbValue len; - lbValue index; - - str = lb_build_expr(p, ie->expr); - if (deref) { - str = lb_emit_load(p, str); - } - elem = lb_string_elem(p, str); - len = lb_string_len(p, str); - - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - - return lb_addr(lb_emit_ptr_offset(p, elem, index)); - } - } - case_end; - - case_ast_node(se, SliceExpr, expr); - - lbValue low = lb_const_int(p->module, t_int, 0); - lbValue high = {}; - - if (se->low != nullptr) low = lb_build_expr(p, se->low); - if (se->high != nullptr) high = lb_build_expr(p, se->high); - - bool no_indices = se->low == nullptr && se->high == nullptr; - - lbAddr addr = lb_build_addr(p, se->expr); - lbValue base = lb_addr_load(p, addr); - Type *type = base_type(base.type); - - if (is_type_pointer(type)) { - type = base_type(type_deref(type)); - addr = lb_addr(base); - base = lb_addr_load(p, addr); - } - - switch (type->kind) { - case Type_Slice: { - Type *slice_type = type; - lbValue len = lb_slice_len(p, base); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - - lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } - - case Type_RelativeSlice: - GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load"); - break; - - case Type_DynamicArray: { - Type *elem_type = type->DynamicArray.elem; - Type *slice_type = alloc_type_slice(elem_type); - - lbValue len = lb_dynamic_array_len(p, base); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - - lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } - - - case Type_Array: { - Type *slice_type = alloc_type_slice(type->Array.elem); - lbValue len = lb_const_int(p->module, t_int, type->Array.count); - - if (high.value == nullptr) high = len; - - bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; - bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; - - if (!low_const || !high_const) { - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - } - lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } - - case Type_Basic: { - GB_ASSERT(type == t_string); - lbValue len = lb_string_len(p, base); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - - lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr str = lb_add_local_generated(p, t_string, false); - lb_fill_string(p, str, elem, new_len); - return str; - } - - - case Type_Struct: - if (is_type_soa_struct(type)) { - lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr)); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - #if 1 - - lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true); - if (type->Struct.soa_kind == StructSoa_Fixed) { - i32 field_count = cast(i32)type->Struct.fields.count; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); - field_src = lb_emit_array_ep(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } - - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); - } else if (type->Struct.soa_kind == StructSoa_Slice) { - if (no_indices) { - lb_addr_store(p, dst, base); - } else { - i32 field_count = cast(i32)type->Struct.fields.count - 1; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ev(p, base, i); - field_src = lb_emit_ptr_offset(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } - - - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); - } - } else if (type->Struct.soa_kind == StructSoa_Dynamic) { - i32 field_count = cast(i32)type->Struct.fields.count - 3; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ev(p, base, i); - field_src = lb_emit_ptr_offset(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } - - - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); - } - - return dst; - #endif - } - break; - - } - - GB_PANIC("Unknown slicable type"); - case_end; - - case_ast_node(de, DerefExpr, expr); - if (is_type_relative_pointer(type_of_expr(de->expr))) { - lbAddr addr = lb_build_addr(p, de->expr); - addr.relative.deref = true; - return addr;\ - } - lbValue addr = lb_build_expr(p, de->expr); - return lb_addr(addr); - case_end; - - case_ast_node(ce, CallExpr, expr); - // NOTE(bill): This is make sure you never need to have an 'array_ev' - lbValue e = lb_build_expr(p, expr); - #if 1 - return lb_addr(lb_address_from_load_or_generate_local(p, e)); - #else - lbAddr v = lb_add_local_generated(p, e.type, false); - lb_addr_store(p, v, e); - return v; - #endif - case_end; - - case_ast_node(cl, CompoundLit, expr); - Type *type = type_of_expr(expr); - Type *bt = base_type(type); - - lbAddr v = lb_add_local_generated(p, type, true); - - Type *et = nullptr; - switch (bt->kind) { - case Type_Array: et = bt->Array.elem; break; - case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; - case Type_Slice: et = bt->Slice.elem; break; - case Type_BitSet: et = bt->BitSet.elem; break; - case Type_SimdVector: et = bt->SimdVector.elem; break; - } - - String proc_name = {}; - if (p->entity) { - proc_name = p->entity->token.string; - } - TokenPos pos = ast_token(expr).pos; - - switch (bt->kind) { - default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; - - case Type_Struct: { - // TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment. - // NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR - bool is_raw_union = is_type_raw_union(bt); - GB_ASSERT(is_type_struct(bt) || is_raw_union); - TypeStruct *st = &bt->Struct; - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - lbValue comp_lit_ptr = lb_addr_get_ptr(p, v); - - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - - lbValue field_expr = {}; - Entity *field = nullptr; - isize index = field_index; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - String name = fv->field->Ident.token.string; - Selection sel = lookup_field(bt, name, false); - index = sel.index[0]; - elem = fv->value; - TypeAndValue tav = type_and_value_of_expr(elem); - } else { - TypeAndValue tav = type_and_value_of_expr(elem); - Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_src_index); - index = sel.index[0]; - } - - field = st->fields[index]; - Type *ft = field->type; - if (!is_raw_union && !is_type_typeid(ft) && lb_is_elem_const(elem, ft)) { - continue; - } - - field_expr = lb_build_expr(p, elem); - - lbValue gep = {}; - if (is_raw_union) { - gep = lb_emit_conv(p, comp_lit_ptr, alloc_type_pointer(ft)); - } else { - gep = lb_emit_struct_ep(p, comp_lit_ptr, cast(i32)index); - } - - Type *fet = field_expr.type; - GB_ASSERT(fet->kind != Type_Tuple); - - // HACK TODO(bill): THIS IS A MASSIVE HACK!!!! - if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) { - GB_ASSERT_MSG(union_variant_index(ft, fet) > 0, "%s", type_to_string(fet)); - - lb_emit_store_union_variant(p, gep, field_expr, fet); - } else { - lbValue fv = lb_emit_conv(p, field_expr, ft); - lb_emit_store(p, gep, fv); - } - } - } - break; - } - - case Type_Map: { - if (cl->elems.count == 0) { - break; - } - { - auto args = array_make<lbValue>(permanent_allocator(), 3); - args[0] = lb_gen_map_header(p, v.addr, type); - args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count); - args[2] = lb_emit_source_code_location(p, proc_name, pos); - lb_emit_runtime_call(p, "__dynamic_map_reserve", args); - } - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - ast_node(fv, FieldValue, elem); - - lbValue key = lb_build_expr(p, fv->field); - lbValue value = lb_build_expr(p, fv->value); - lb_insert_dynamic_map_key_and_value(p, v, type, key, value, elem); - } - break; - } - - case Type_Array: { - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count); - - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } - - for_array(i, temp_data) { - temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index); - } - - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - - lb_reset_copy_elision_hint(p, prev_hint); - } - - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - } - } - break; - } - case Type_EnumeratedArray: { - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count); - - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } - - - i32 index_offset = cast(i32)exact_value_to_i64(bt->EnumeratedArray.min_value); - - for_array(i, temp_data) { - i32 index = temp_data[i].elem_index - index_offset; - temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), index); - } - - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - - lb_reset_copy_elision_hint(p, prev_hint); - } - - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - } - } - break; - } - case Type_Slice: { - if (cl->elems.count > 0) { - Type *elem_type = bt->Slice.elem; - Type *elem_ptr_type = alloc_type_pointer(elem_type); - Type *elem_ptr_ptr_type = alloc_type_pointer(elem_ptr_type); - lbValue slice = lb_const_value(p->module, type, exact_value_compound(expr)); - - lbValue data = lb_slice_elem(p, slice); - - auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count); - - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - - if (lb_is_elem_const(fv->value, et)) { - continue; - } - - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } - - } else { - GB_ASSERT(fv->field->tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(fv->field->tav.value); - - lbValue field_expr = lb_build_expr(p, fv->value); - GB_ASSERT(!is_type_tuple(field_expr.type)); - - lbValue ev = lb_emit_conv(p, field_expr, et); - - lbCompoundLitElemTempData data = {}; - data.value = ev; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbValue field_expr = lb_build_expr(p, elem); - GB_ASSERT(!is_type_tuple(field_expr.type)); - - lbValue ev = lb_emit_conv(p, field_expr, et); - - lbCompoundLitElemTempData data = {}; - data.value = ev; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } - - for_array(i, temp_data) { - temp_data[i].gep = lb_emit_ptr_offset(p, data, lb_const_int(p->module, t_int, temp_data[i].elem_index)); - } - - for_array(i, temp_data) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - - { - lbValue count = {}; - count.type = t_int; - - if (lb_is_const(slice)) { - unsigned indices[1] = {1}; - count.value = LLVMConstExtractValue(slice.value, indices, gb_count_of(indices)); - } else { - count.value = LLVMBuildExtractValue(p->builder, slice.value, 1, ""); - } - lb_fill_slice(p, v, data, count); - } - } - break; - } - - case Type_DynamicArray: { - if (cl->elems.count == 0) { - break; - } - Type *et = bt->DynamicArray.elem; - lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); - lbValue align = lb_const_int(p->module, t_int, type_align_of(et)); - - i64 item_count = gb_max(cl->max_count, cl->elems.count); - { - - auto args = array_make<lbValue>(permanent_allocator(), 5); - args[0] = lb_emit_conv(p, lb_addr_get_ptr(p, v), t_rawptr); - args[1] = size; - args[2] = align; - args[3] = lb_const_int(p->module, t_int, 2*item_count); // TODO(bill): Is this too much waste? - args[4] = lb_emit_source_code_location(p, proc_name, pos); - lb_emit_runtime_call(p, "__dynamic_array_reserve", args); - } - - lbValue items = lb_generate_local_array(p, et, item_count); - // lbValue items = lb_generate_global_array(p->module, et, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr); - - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); - - for (i64 k = lo; k < hi; k++) { - lbValue ep = lb_emit_array_epi(p, items, cast(i32)k); - lb_emit_store(p, ep, value); - } - } else { - GB_ASSERT(fv->field->tav.mode == Addressing_Constant); - - i64 field_index = exact_value_to_i64(fv->field->tav.value); - - lbValue ev = lb_build_expr(p, fv->value); - lbValue value = lb_emit_conv(p, ev, et); - lbValue ep = lb_emit_array_epi(p, items, cast(i32)field_index); - lb_emit_store(p, ep, value); - } - } else { - lbValue value = lb_emit_conv(p, lb_build_expr(p, elem), et); - lbValue ep = lb_emit_array_epi(p, items, cast(i32)i); - lb_emit_store(p, ep, value); - } - } - - { - auto args = array_make<lbValue>(permanent_allocator(), 6); - args[0] = lb_emit_conv(p, v.addr, t_rawptr); - args[1] = size; - args[2] = align; - args[3] = lb_emit_conv(p, items, t_rawptr); - args[4] = lb_const_int(p->module, t_int, item_count); - args[5] = lb_emit_source_code_location(p, proc_name, pos); - lb_emit_runtime_call(p, "__dynamic_array_append", args); - } - break; - } - - case Type_Basic: { - GB_ASSERT(is_type_any(bt)); - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - String field_names[2] = { - str_lit("data"), - str_lit("id"), - }; - Type *field_types[2] = { - t_rawptr, - t_typeid, - }; - - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - - lbValue field_expr = {}; - isize index = field_index; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); - index = sel.index[0]; - elem = fv->value; - } else { - TypeAndValue tav = type_and_value_of_expr(elem); - Selection sel = lookup_field(bt, field_names[field_index], false); - index = sel.index[0]; - } - - field_expr = lb_build_expr(p, elem); - - GB_ASSERT(field_expr.type->kind != Type_Tuple); - - Type *ft = field_types[index]; - lbValue fv = lb_emit_conv(p, field_expr, ft); - lbValue gep = lb_emit_struct_ep(p, lb_addr_get_ptr(p, v), cast(i32)index); - lb_emit_store(p, gep, fv); - } - } - - break; - } - - case Type_BitSet: { - i64 sz = type_size_of(type); - if (cl->elems.count > 0 && sz > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower)); - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - GB_ASSERT(elem->kind != Ast_FieldValue); - - if (lb_is_elem_const(elem, et)) { - continue; - } - - lbValue expr = lb_build_expr(p, elem); - GB_ASSERT(expr.type->kind != Type_Tuple); - - Type *it = bit_set_to_int(bt); - lbValue one = lb_const_value(p->module, it, exact_value_i64(1)); - lbValue e = lb_emit_conv(p, expr, it); - e = lb_emit_arith(p, Token_Sub, e, lower, it); - e = lb_emit_arith(p, Token_Shl, one, e, it); - - lbValue old_value = lb_emit_transmute(p, lb_addr_load(p, v), it); - lbValue new_value = lb_emit_arith(p, Token_Or, old_value, e, it); - new_value = lb_emit_transmute(p, new_value, type); - lb_addr_store(p, v, new_value); - } - } - break; - } - - } - - return v; - case_end; - - case_ast_node(tc, TypeCast, expr); - Type *type = type_of_expr(expr); - lbValue x = lb_build_expr(p, tc->expr); - lbValue e = {}; - switch (tc->token.kind) { - case Token_cast: - e = lb_emit_conv(p, x, type); - break; - case Token_transmute: - e = lb_emit_transmute(p, x, type); - break; - default: - GB_PANIC("Invalid AST TypeCast"); - } - lbAddr v = lb_add_local_generated(p, type, false); - lb_addr_store(p, v, e); - return v; - case_end; - - case_ast_node(ac, AutoCast, expr); - return lb_build_addr(p, ac->expr); - case_end; - } - - TokenPos token_pos = ast_token(expr).pos; - GB_PANIC("Unexpected address expression\n" - "\tAst: %.*s @ " - "%s\n", - LIT(ast_strings[expr->kind]), - token_pos_to_string(token_pos)); - - - return {}; -} - -void lb_init_module(lbModule *m, Checker *c) { - m->info = &c->info; - - gbString module_name = gb_string_make(heap_allocator(), "odin_package"); - if (m->pkg) { - module_name = gb_string_appendc(module_name, "-"); - module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len); - } else if (USE_SEPARATE_MODULES) { - module_name = gb_string_appendc(module_name, "-builtin"); - } - - m->ctx = LLVMContextCreate(); - m->mod = LLVMModuleCreateWithNameInContext(module_name ? module_name : "odin_package", m->ctx); - // m->debug_builder = nullptr; - if (build_context.ODIN_DEBUG) { - enum {DEBUG_METADATA_VERSION = 3}; - - LLVMMetadataRef debug_ref = LLVMValueAsMetadata(LLVMConstInt(LLVMInt32TypeInContext(m->ctx), DEBUG_METADATA_VERSION, true)); - LLVMAddModuleFlag(m->mod, LLVMModuleFlagBehaviorWarning, "Debug Info Version", 18, debug_ref); - - switch (build_context.metrics.os) { - case TargetOs_windows: - LLVMAddModuleFlag(m->mod, - LLVMModuleFlagBehaviorWarning, - "CodeView", 8, - LLVMValueAsMetadata(LLVMConstInt(LLVMInt32TypeInContext(m->ctx), 1, true))); - break; - - case TargetOs_darwin: - // NOTE(bill): Darwin only supports DWARF2 (that I know of) - LLVMAddModuleFlag(m->mod, - LLVMModuleFlagBehaviorWarning, - "Dwarf Version", 13, - LLVMValueAsMetadata(LLVMConstInt(LLVMInt32TypeInContext(m->ctx), 2, true))); - break; - } - m->debug_builder = LLVMCreateDIBuilder(m->mod); - } - - gbAllocator a = heap_allocator(); - map_init(&m->types, a); - map_init(&m->llvm_types, a); - map_init(&m->values, a); - map_init(&m->soa_values, a); - string_map_init(&m->members, a); - map_init(&m->procedure_values, a); - string_map_init(&m->procedures, a); - string_map_init(&m->const_strings, a); - map_init(&m->anonymous_proc_lits, a); - map_init(&m->function_type_map, a); - map_init(&m->equal_procs, a); - map_init(&m->hasher_procs, a); - array_init(&m->procedures_to_generate, a, 0, 1024); - array_init(&m->foreign_library_paths, a, 0, 1024); - array_init(&m->missing_procedures_to_check, a, 0, 16); - - map_init(&m->debug_values, a); - array_init(&m->debug_incomplete_types, a, 0, 1024); - -} - - -bool lb_init_generator(lbGenerator *gen, Checker *c) { - if (global_error_collector.count != 0) { - return false; - } - - isize tc = c->parser->total_token_count; - if (tc < 2) { - return false; - } - - - String init_fullpath = c->parser->init_fullpath; - - if (build_context.out_filepath.len == 0) { - gen->output_name = remove_directory_from_path(init_fullpath); - gen->output_name = remove_extension_from_path(gen->output_name); - gen->output_name = string_trim_whitespace(gen->output_name); - if (gen->output_name.len == 0) { - gen->output_name = c->info.init_scope->pkg->name; - } - gen->output_base = gen->output_name; - } else { - gen->output_name = build_context.out_filepath; - gen->output_name = string_trim_whitespace(gen->output_name); - if (gen->output_name.len == 0) { - gen->output_name = c->info.init_scope->pkg->name; - } - isize pos = string_extension_position(gen->output_name); - if (pos < 0) { - gen->output_base = gen->output_name; - } else { - gen->output_base = substring(gen->output_name, 0, pos); - } - } - gbAllocator ha = heap_allocator(); - array_init(&gen->output_object_paths, ha); - array_init(&gen->output_temp_paths, ha); - - gen->output_base = path_to_full_path(ha, gen->output_base); - - gbString output_file_path = gb_string_make_length(ha, gen->output_base.text, gen->output_base.len); - output_file_path = gb_string_appendc(output_file_path, ".obj"); - defer (gb_string_free(output_file_path)); - - gen->info = &c->info; - - map_init(&gen->modules, permanent_allocator(), gen->info->packages.entries.count*2); - map_init(&gen->modules_through_ctx, permanent_allocator(), gen->info->packages.entries.count*2); - map_init(&gen->anonymous_proc_lits, heap_allocator(), 1024); - - gb_mutex_init(&gen->mutex); - - if (USE_SEPARATE_MODULES) { - for_array(i, gen->info->packages.entries) { - AstPackage *pkg = gen->info->packages.entries[i].value; - - auto m = gb_alloc_item(permanent_allocator(), lbModule); - m->pkg = pkg; - m->gen = gen; - map_set(&gen->modules, hash_pointer(pkg), m); - lb_init_module(m, c); - } - } - - gen->default_module.gen = gen; - map_set(&gen->modules, hash_pointer(nullptr), &gen->default_module); - lb_init_module(&gen->default_module, c); - - - for_array(i, gen->modules.entries) { - lbModule *m = gen->modules.entries[i].value; - LLVMContextRef ctx = LLVMGetModuleContext(m->mod); - map_set(&gen->modules_through_ctx, hash_pointer(ctx), m); - } - - return true; -} - -lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) { - GB_ASSERT(type != nullptr); - type = default_type(type); - - isize max_len = 7+8+1; - u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len); - - u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_generated_index, 1); - - isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", id); - String name = make_string(str, len-1); - - Scope *scope = nullptr; - Entity *e = alloc_entity_variable(scope, make_token_ident(name), type); - lbValue g = {}; - g.type = alloc_type_pointer(type); - g.value = LLVMAddGlobal(m->mod, lb_type(m, type), cast(char const *)str); - if (value.value != nullptr) { - GB_ASSERT_MSG(LLVMIsConstant(value.value), LLVMPrintValueToString(value.value)); - LLVMSetInitializer(g.value, value.value); - } else { - LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, type))); - } - - lb_add_entity(m, e, g); - lb_add_member(m, name, g); - return lb_addr(g); -} - -lbValue lb_find_runtime_value(lbModule *m, String const &name) { - AstPackage *p = m->info->runtime_package; - Entity *e = scope_lookup_current(p->scope, name); - return lb_find_value_from_entity(m, e); -} -lbValue lb_find_package_value(lbModule *m, String const &pkg, String const &name) { - Entity *e = find_entity_in_pkg(m->info, pkg, name); - return lb_find_value_from_entity(m, e); -} - -lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { - i32 index = cast(i32)lb_type_info_index(m->info, type); - GB_ASSERT(index >= 0); - // gb_printf_err("%d %s\n", index, type_to_string(type)); - - LLVMValueRef indices[2] = { - LLVMConstInt(lb_type(m, t_int), 0, false), - LLVMConstInt(lb_type(m, t_int), index, false), - }; - - lbValue res = {}; - res.type = t_type_info_ptr; - res.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, cast(unsigned)gb_count_of(indices)); - return res; -} - - -lbValue lb_type_info_member_types_offset(lbProcedure *p, isize count) { - GB_ASSERT(p->module == &p->module->gen->default_module); - lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_types.addr, lb_global_type_info_member_types_index); - lb_global_type_info_member_types_index += cast(i32)count; - return offset; -} -lbValue lb_type_info_member_names_offset(lbProcedure *p, isize count) { - GB_ASSERT(p->module == &p->module->gen->default_module); - lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_names.addr, lb_global_type_info_member_names_index); - lb_global_type_info_member_names_index += cast(i32)count; - return offset; -} -lbValue lb_type_info_member_offsets_offset(lbProcedure *p, isize count) { - GB_ASSERT(p->module == &p->module->gen->default_module); - lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_offsets.addr, lb_global_type_info_member_offsets_index); - lb_global_type_info_member_offsets_index += cast(i32)count; - return offset; -} -lbValue lb_type_info_member_usings_offset(lbProcedure *p, isize count) { - GB_ASSERT(p->module == &p->module->gen->default_module); - lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_usings.addr, lb_global_type_info_member_usings_index); - lb_global_type_info_member_usings_index += cast(i32)count; - return offset; -} -lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) { - GB_ASSERT(p->module == &p->module->gen->default_module); - lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_tags.addr, lb_global_type_info_member_tags_index); - lb_global_type_info_member_tags_index += cast(i32)count; - return offset; -} - -lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init) { - lbAddr addr = lb_add_local_generated(p, alloc_type_array(elem_type, count), zero_init); - return lb_addr_get_ptr(p, addr); -} - -lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id) { - Token token = {Token_Ident}; - isize name_len = prefix.len + 1 + 20; - - auto suffix_id = cast(unsigned long long)id; - char *text = gb_alloc_array(permanent_allocator(), char, name_len+1); - gb_snprintf(text, name_len, - "%.*s-%llu", LIT(prefix), suffix_id); - text[name_len] = 0; - - String s = make_string_c(text); - - Type *t = alloc_type_array(elem_type, count); - lbValue g = {}; - g.value = LLVMAddGlobal(m->mod, lb_type(m, t), text); - g.type = alloc_type_pointer(t); - LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t))); - LLVMSetLinkage(g.value, LLVMInternalLinkage); - string_map_set(&m->members, s, g); - return g; -} - - -void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data - lbModule *m = p->module; - LLVMContextRef ctx = m->ctx; - CheckerInfo *info = m->info; - - { - // NOTE(bill): Set the type_table slice with the global backing array - lbValue global_type_table = lb_find_runtime_value(m, str_lit("type_table")); - Type *type = base_type(lb_global_type_info_data_entity->type); - GB_ASSERT(is_type_array(type)); - - LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef values[2] = { - LLVMConstInBoundsGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)), - LLVMConstInt(lb_type(m, t_int), type->Array.count, true), - }; - LLVMValueRef slice = llvm_const_named_struct(llvm_addr_type(global_type_table), values, gb_count_of(values)); - - LLVMSetInitializer(global_type_table.value, slice); - } - - - // Useful types - Type *t_i64_slice_ptr = alloc_type_pointer(alloc_type_slice(t_i64)); - Type *t_string_slice_ptr = alloc_type_pointer(alloc_type_slice(t_string)); - Entity *type_info_flags_entity = find_core_entity(info->checker, str_lit("Type_Info_Flags")); - Type *t_type_info_flags = type_info_flags_entity->type; - - - i32 type_info_member_types_index = 0; - i32 type_info_member_names_index = 0; - i32 type_info_member_offsets_index = 0; - - for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; - if (t == nullptr || t == t_invalid) { - continue; - } - - isize entry_index = lb_type_info_index(info, t, false); - if (entry_index <= 0) { - continue; - } - - lbValue tag = {}; - lbValue ti_ptr = lb_emit_array_epi(p, lb_global_type_info_data_ptr(m), cast(i32)entry_index); - lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 4); - - lbValue type_info_flags = lb_const_int(p->module, t_type_info_flags, type_info_flags_of_type(t)); - - lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 0), lb_const_int(m, t_int, type_size_of(t))); - lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 1), lb_const_int(m, t_int, type_align_of(t))); - lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 2), type_info_flags); - lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 3), lb_typeid(m, t)); - - - switch (t->kind) { - case Type_Named: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_named_ptr); - - LLVMValueRef pkg_name = nullptr; - if (t->Named.type_name->pkg) { - pkg_name = lb_const_string(m, t->Named.type_name->pkg->name).value; - } else { - pkg_name = LLVMConstNull(lb_type(m, t_string)); - } - - String proc_name = {}; - if (t->Named.type_name->parent_proc_decl) { - DeclInfo *decl = t->Named.type_name->parent_proc_decl; - if (decl->entity && decl->entity->kind == Entity_Procedure) { - proc_name = decl->entity->token.string; - } - } - TokenPos pos = t->Named.type_name->token.pos; - - lbValue loc = lb_emit_source_code_location(p, proc_name, pos); - - LLVMValueRef vals[4] = { - lb_const_string(p->module, t->Named.type_name->token.string).value, - lb_get_type_info_ptr(m, t->Named.base).value, - pkg_name, - loc.value - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - - case Type_Basic: - switch (t->Basic.kind) { - case Basic_bool: - case Basic_b8: - case Basic_b16: - case Basic_b32: - case Basic_b64: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_boolean_ptr); - break; - - case Basic_i8: - case Basic_u8: - case Basic_i16: - case Basic_u16: - case Basic_i32: - case Basic_u32: - case Basic_i64: - case Basic_u64: - case Basic_i128: - case Basic_u128: - - case Basic_i16le: - case Basic_u16le: - case Basic_i32le: - case Basic_u32le: - case Basic_i64le: - case Basic_u64le: - case Basic_i128le: - case Basic_u128le: - case Basic_i16be: - case Basic_u16be: - case Basic_i32be: - case Basic_u32be: - case Basic_i64be: - case Basic_u64be: - case Basic_i128be: - case Basic_u128be: - - case Basic_int: - case Basic_uint: - case Basic_uintptr: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_integer_ptr); - - lbValue is_signed = lb_const_bool(m, t_bool, (t->Basic.flags & BasicFlag_Unsigned) == 0); - // NOTE(bill): This is matches the runtime layout - u8 endianness_value = 0; - if (t->Basic.flags & BasicFlag_EndianLittle) { - endianness_value = 1; - } else if (t->Basic.flags & BasicFlag_EndianBig) { - endianness_value = 2; - } - lbValue endianness = lb_const_int(m, t_u8, endianness_value); - - LLVMValueRef vals[2] = { - is_signed.value, - endianness.value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - - case Basic_rune: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_rune_ptr); - break; - - case Basic_f16: - case Basic_f32: - case Basic_f64: - case Basic_f16le: - case Basic_f32le: - case Basic_f64le: - case Basic_f16be: - case Basic_f32be: - case Basic_f64be: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_float_ptr); - - // NOTE(bill): This is matches the runtime layout - u8 endianness_value = 0; - if (t->Basic.flags & BasicFlag_EndianLittle) { - endianness_value = 1; - } else if (t->Basic.flags & BasicFlag_EndianBig) { - endianness_value = 2; - } - lbValue endianness = lb_const_int(m, t_u8, endianness_value); - - LLVMValueRef vals[1] = { - endianness.value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Basic_complex32: - case Basic_complex64: - case Basic_complex128: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_complex_ptr); - break; - - case Basic_quaternion64: - case Basic_quaternion128: - case Basic_quaternion256: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_quaternion_ptr); - break; - - case Basic_rawptr: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr); - break; - - case Basic_string: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_string_ptr); - break; - - case Basic_cstring: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_string_ptr); - LLVMValueRef vals[1] = { - lb_const_bool(m, t_bool, true).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Basic_any: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_any_ptr); - break; - - case Basic_typeid: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_typeid_ptr); - break; - } - break; - - case Type_Pointer: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr); - lbValue gep = lb_get_type_info_ptr(m, t->Pointer.elem); - - LLVMValueRef vals[1] = { - gep.value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_Array: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_array_ptr); - i64 ez = type_size_of(t->Array.elem); - - LLVMValueRef vals[3] = { - lb_get_type_info_ptr(m, t->Array.elem).value, - lb_const_int(m, t_int, ez).value, - lb_const_int(m, t_int, t->Array.count).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_EnumeratedArray: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr); - - LLVMValueRef vals[6] = { - lb_get_type_info_ptr(m, t->EnumeratedArray.elem).value, - lb_get_type_info_ptr(m, t->EnumeratedArray.index).value, - lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value, - lb_const_int(m, t_int, t->EnumeratedArray.count).value, - - // Unions - LLVMConstNull(lb_type(m, t_type_info_enum_value)), - LLVMConstNull(lb_type(m, t_type_info_enum_value)), - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - - // NOTE(bill): Union assignment - lbValue min_value = lb_emit_struct_ep(p, tag, 4); - lbValue max_value = lb_emit_struct_ep(p, tag, 5); - - lbValue min_v = lb_const_value(m, t_i64, t->EnumeratedArray.min_value); - lbValue max_v = lb_const_value(m, t_i64, t->EnumeratedArray.max_value); - - lb_emit_store(p, min_value, min_v); - lb_emit_store(p, max_value, max_v); - break; - } - case Type_DynamicArray: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_dynamic_array_ptr); - - LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->DynamicArray.elem).value, - lb_const_int(m, t_int, type_size_of(t->DynamicArray.elem)).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_Slice: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_slice_ptr); - - LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->Slice.elem).value, - lb_const_int(m, t_int, type_size_of(t->Slice.elem)).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_Proc: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_procedure_ptr); - - LLVMValueRef params = LLVMConstNull(lb_type(m, t_type_info_ptr)); - LLVMValueRef results = LLVMConstNull(lb_type(m, t_type_info_ptr)); - if (t->Proc.params != nullptr) { - params = lb_get_type_info_ptr(m, t->Proc.params).value; - } - if (t->Proc.results != nullptr) { - results = lb_get_type_info_ptr(m, t->Proc.results).value; - } - - LLVMValueRef vals[4] = { - params, - results, - lb_const_bool(m, t_bool, t->Proc.variadic).value, - lb_const_int(m, t_u8, t->Proc.calling_convention).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - case Type_Tuple: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_tuple_ptr); - - - lbValue memory_types = lb_type_info_member_types_offset(p, t->Tuple.variables.count); - lbValue memory_names = lb_type_info_member_names_offset(p, t->Tuple.variables.count); - - - for_array(i, t->Tuple.variables) { - // NOTE(bill): offset is not used for tuples - Entity *f = t->Tuple.variables[i]; - - lbValue index = lb_const_int(m, t_int, i); - lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); - - // TODO(bill): Make this constant if possible, 'lb_const_store' does not work - lb_emit_store(p, type_info, lb_type_info(m, f->type)); - if (f->token.string.len > 0) { - lbValue name = lb_emit_ptr_offset(p, memory_names, index); - lb_emit_store(p, name, lb_const_string(m, f->token.string)); - } - } - - lbValue count = lb_const_int(m, t_int, t->Tuple.variables.count); - - LLVMValueRef types_slice = llvm_const_slice(m, memory_types, count); - LLVMValueRef names_slice = llvm_const_slice(m, memory_names, count); - - LLVMValueRef vals[2] = { - types_slice, - names_slice, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - - break; - } - - case Type_Enum: - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enum_ptr); - - { - GB_ASSERT(t->Enum.base_type != nullptr); - // GB_ASSERT_MSG(type_size_of(t_type_info_enum_value) == 16, "%lld == 16", cast(long long)type_size_of(t_type_info_enum_value)); - - - LLVMValueRef vals[3] = {}; - vals[0] = lb_type_info(m, t->Enum.base_type).value; - if (t->Enum.fields.count > 0) { - auto fields = t->Enum.fields; - lbValue name_array = lb_generate_global_array(m, t_string, fields.count, - str_lit("$enum_names"), cast(i64)entry_index); - lbValue value_array = lb_generate_global_array(m, t_type_info_enum_value, fields.count, - str_lit("$enum_values"), cast(i64)entry_index); - - - LLVMValueRef *name_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count); - LLVMValueRef *value_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count); - - GB_ASSERT(is_type_integer(t->Enum.base_type)); - - LLVMTypeRef align_type = lb_alignment_prefix_type_hack(m, type_align_of(t)); - LLVMTypeRef array_type = LLVMArrayType(lb_type(m, t_u8), 8); - - for_array(i, fields) { - name_values[i] = lb_const_string(m, fields[i]->token.string).value; - value_values[i] = lb_const_value(m, t_i64, fields[i]->Constant.value).value; - } - - LLVMValueRef name_init = llvm_const_array(lb_type(m, t_string), name_values, cast(unsigned)fields.count); - LLVMValueRef value_init = llvm_const_array(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count); - LLVMSetInitializer(name_array.value, name_init); - LLVMSetInitializer(value_array.value, value_init); - - lbValue v_count = lb_const_int(m, t_int, fields.count); - - vals[1] = llvm_const_slice(m, lb_array_elem(p, name_array), v_count); - vals[2] = llvm_const_slice(m, lb_array_elem(p, value_array), v_count); - } else { - vals[1] = LLVMConstNull(lb_type(m, base_type(t_type_info_enum)->Struct.fields[1]->type)); - vals[2] = LLVMConstNull(lb_type(m, base_type(t_type_info_enum)->Struct.fields[2]->type)); - } - - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Type_Union: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_union_ptr); - - { - LLVMValueRef vals[7] = {}; - - isize variant_count = gb_max(0, t->Union.variants.count); - lbValue memory_types = lb_type_info_member_types_offset(p, variant_count); - - // NOTE(bill): Zeroth is nil so ignore it - for (isize variant_index = 0; variant_index < variant_count; variant_index++) { - Type *vt = t->Union.variants[variant_index]; - lbValue tip = lb_get_type_info_ptr(m, vt); - - lbValue index = lb_const_int(m, t_int, variant_index); - lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); - lb_emit_store(p, type_info, lb_type_info(m, vt)); - } - - lbValue count = lb_const_int(m, t_int, variant_count); - vals[0] = llvm_const_slice(m, memory_types, count); - - i64 tag_size = union_tag_size(t); - i64 tag_offset = align_formula(t->Union.variant_block_size, tag_size); - - if (tag_size > 0) { - vals[1] = lb_const_int(m, t_uintptr, tag_offset).value; - vals[2] = lb_type_info(m, union_tag_type(t)).value; - } else { - vals[1] = lb_const_int(m, t_uintptr, 0).value; - vals[2] = LLVMConstNull(lb_type(m, t_type_info_ptr)); - } - - if (is_type_comparable(t) && !is_type_simple_compare(t)) { - vals[3] = lb_get_equal_proc_for_type(m, t).value; - } - - vals[4] = lb_const_bool(m, t_bool, t->Union.custom_align != 0).value; - vals[5] = lb_const_bool(m, t_bool, t->Union.no_nil).value; - vals[6] = lb_const_bool(m, t_bool, t->Union.maybe).value; - - for (isize i = 0; i < gb_count_of(vals); i++) { - if (vals[i] == nullptr) { - vals[i] = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i))); - } - } - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - - break; - } - - case Type_Struct: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_struct_ptr); - - LLVMValueRef vals[12] = {}; - - - { - lbValue is_packed = lb_const_bool(m, t_bool, t->Struct.is_packed); - lbValue is_raw_union = lb_const_bool(m, t_bool, t->Struct.is_raw_union); - lbValue is_custom_align = lb_const_bool(m, t_bool, t->Struct.custom_align != 0); - vals[5] = is_packed.value; - vals[6] = is_raw_union.value; - vals[7] = is_custom_align.value; - if (is_type_comparable(t) && !is_type_simple_compare(t)) { - vals[8] = lb_get_equal_proc_for_type(m, t).value; - } - - - if (t->Struct.soa_kind != StructSoa_None) { - lbValue kind = lb_emit_struct_ep(p, tag, 9); - Type *kind_type = type_deref(kind.type); - - lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind)); - lbValue soa_type = lb_type_info(m, t->Struct.soa_elem); - lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count); - - vals[9] = soa_kind.value; - vals[10] = soa_type.value; - vals[11] = soa_len.value; - } - } - - isize count = t->Struct.fields.count; - if (count > 0) { - lbValue memory_types = lb_type_info_member_types_offset (p, count); - lbValue memory_names = lb_type_info_member_names_offset (p, count); - lbValue memory_offsets = lb_type_info_member_offsets_offset(p, count); - lbValue memory_usings = lb_type_info_member_usings_offset (p, count); - lbValue memory_tags = lb_type_info_member_tags_offset (p, count); - - type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet - for (isize source_index = 0; source_index < count; source_index++) { - // TODO(bill): Order fields in source order not layout order - Entity *f = t->Struct.fields[source_index]; - lbValue tip = lb_get_type_info_ptr(m, f->type); - i64 foffset = 0; - if (!t->Struct.is_raw_union) { - foffset = t->Struct.offsets[f->Variable.field_index]; - } - GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); - - lbValue index = lb_const_int(m, t_int, source_index); - lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); - lbValue offset = lb_emit_ptr_offset(p, memory_offsets, index); - lbValue is_using = lb_emit_ptr_offset(p, memory_usings, index); - - lb_emit_store(p, type_info, lb_type_info(m, f->type)); - if (f->token.string.len > 0) { - lbValue name = lb_emit_ptr_offset(p, memory_names, index); - lb_emit_store(p, name, lb_const_string(m, f->token.string)); - } - lb_emit_store(p, offset, lb_const_int(m, t_uintptr, foffset)); - lb_emit_store(p, is_using, lb_const_bool(m, t_bool, (f->flags&EntityFlag_Using) != 0)); - - if (t->Struct.tags.count > 0) { - String tag_string = t->Struct.tags[source_index]; - if (tag_string.len > 0) { - lbValue tag_ptr = lb_emit_ptr_offset(p, memory_tags, index); - lb_emit_store(p, tag_ptr, lb_const_string(m, tag_string)); - } - } - - } - - lbValue cv = lb_const_int(m, t_int, count); - vals[0] = llvm_const_slice(m, memory_types, cv); - vals[1] = llvm_const_slice(m, memory_names, cv); - vals[2] = llvm_const_slice(m, memory_offsets, cv); - vals[3] = llvm_const_slice(m, memory_usings, cv); - vals[4] = llvm_const_slice(m, memory_tags, cv); - } - for (isize i = 0; i < gb_count_of(vals); i++) { - if (vals[i] == nullptr) { - vals[i] = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i))); - } - } - - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - - break; - } - - case Type_Map: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr); - init_map_internal_types(t); - - LLVMValueRef vals[5] = { - lb_get_type_info_ptr(m, t->Map.key).value, - lb_get_type_info_ptr(m, t->Map.value).value, - lb_get_type_info_ptr(m, t->Map.generated_struct_type).value, - lb_get_equal_proc_for_type(m, t->Map.key).value, - lb_get_hasher_proc_for_type(m, t->Map.key).value - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - break; - } - - case Type_BitSet: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_bit_set_ptr); - - GB_ASSERT(is_type_typed(t->BitSet.elem)); - - - LLVMValueRef vals[4] = { - lb_get_type_info_ptr(m, t->BitSet.elem).value, - LLVMConstNull(lb_type(m, t_type_info_ptr)), - lb_const_int(m, t_i64, t->BitSet.lower).value, - lb_const_int(m, t_i64, t->BitSet.upper).value, - }; - if (t->BitSet.underlying != nullptr) { - vals[1] =lb_get_type_info_ptr(m, t->BitSet.underlying).value; - } - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Type_SimdVector: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_simd_vector_ptr); - - LLVMValueRef vals[3] = {}; - - vals[0] = lb_get_type_info_ptr(m, t->SimdVector.elem).value; - vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value; - vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - case Type_RelativePointer: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_pointer_ptr); - LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->RelativePointer.pointer_type).value, - lb_get_type_info_ptr(m, t->RelativePointer.base_integer).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - case Type_RelativeSlice: - { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_slice_ptr); - LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->RelativeSlice.slice_type).value, - lb_get_type_info_ptr(m, t->RelativeSlice.base_integer).value, - }; - - lbValue res = {}; - res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); - lb_emit_store(p, tag, res); - } - break; - - } - - - if (tag.value != nullptr) { - Type *tag_type = type_deref(tag.type); - GB_ASSERT(is_type_named(tag_type)); - // lb_emit_store_union_variant(p, variant_ptr, lb_emit_load(p, tag), tag_type); - lb_emit_store_union_variant_tag(p, variant_ptr, tag_type); - } else { - if (t != t_llvm_bool) { - GB_PANIC("Unhandled Type_Info variant: %s", type_to_string(t)); - } - } - } -} - struct lbGlobalVariable { lbValue var; lbValue init; |