From 44baf56d624240aae3302a38a5083341d8fede3a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 8 Nov 2020 23:54:09 +0000 Subject: Fix cyclic check in `is_type_polymorphic` --- src/types.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/types.cpp') diff --git a/src/types.cpp b/src/types.cpp index fc4544385..f4d375f4f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -323,6 +323,7 @@ String const type_strings[] = { enum TypeFlag : u32 { TypeFlag_Polymorphic = 1<<1, TypeFlag_PolySpecialized = 1<<2, + TypeFlag_InProcessOfCheckingPolymorphic = 1<<3, }; struct Type { @@ -1695,12 +1696,23 @@ TypeTuple *get_record_polymorphic_params(Type *t) { bool is_type_polymorphic(Type *t, bool or_specialized=false) { + if (t->flags & TypeFlag_InProcessOfCheckingPolymorphic) { + return false; + } + switch (t->kind) { case Type_Generic: return true; case Type_Named: - return is_type_polymorphic(t->Named.base, or_specialized); + { + u32 flags = t->flags; + t->flags |= TypeFlag_InProcessOfCheckingPolymorphic; + bool ok = is_type_polymorphic(t->Named.base, or_specialized); + t->flags = flags; + return ok; + } + case Type_Opaque: return is_type_polymorphic(t->Opaque.elem, or_specialized); case Type_Pointer: -- cgit v1.2.3 From c26cb470a22e1985bbb7ec878a402ad8f78ef75e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 9 Nov 2020 10:27:27 +0000 Subject: Fix LLVM-API type cycle for procedures of named procedures --- src/check_type.cpp | 24 +++++++++++++++++++++--- src/llvm_backend.cpp | 3 ++- src/types.cpp | 1 + 3 files changed, 24 insertions(+), 4 deletions(-) (limited to 'src/types.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 93040e493..62b5fd8e1 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2209,6 +2209,11 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall return new_type; } + if (is_type_proc(original_type)) { + // NOTE(bill): Force a cast to prevent a possible type cycle + return t_rawptr; + } + if (cc == ProcCC_None || cc == ProcCC_PureNone || cc == ProcCC_InlineAsm) { return new_type; } @@ -2332,6 +2337,11 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal return new_type; } + if (is_type_proc(single_type)) { + // NOTE(bill): Force a cast to prevent a possible type cycle + return t_rawptr; + } + if (is_type_simd_vector(single_type)) { return new_type; } @@ -2451,22 +2461,29 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) { return; } - if (type->Proc.abi_types_set) { + if (type->Proc.abi_types_set || type->flags & TypeFlag_InProcessOfCheckingABI) { return; } + u32 flags = type->flags; + type->flags |= TypeFlag_InProcessOfCheckingABI; + type->Proc.abi_compat_params = array_make(allocator, cast(isize)type->Proc.param_count); for (i32 i = 0; i < type->Proc.param_count; i++) { Entity *e = type->Proc.params->Tuple.variables[i]; if (e->kind == Entity_Variable) { Type *original_type = e->type; + if (is_type_named(original_type) && is_type_proc(original_type)) { + continue; + } + Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention); type->Proc.abi_compat_params[i] = new_type; switch (type->Proc.calling_convention) { case ProcCC_Odin: case ProcCC_Contextless: case ProcCC_Pure: - if (is_type_pointer(new_type) & !is_type_pointer(e->type)) { + if (is_type_pointer(new_type) && !is_type_pointer(e->type) && !is_type_proc(e->type)) { e->flags |= EntityFlag_ImplicitReference; } break; @@ -2474,7 +2491,7 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) { if (build_context.ODIN_OS == "linux" || build_context.ODIN_OS == "darwin") { - if (is_type_pointer(new_type) & !is_type_pointer(e->type)) { + if (is_type_pointer(new_type) & !is_type_pointer(e->type) && !is_type_proc(e->type)) { e->flags |= EntityFlag_ByVal; } } @@ -2499,6 +2516,7 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) { type->Proc.return_by_pointer = abi_compat_return_by_pointer(allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type); type->Proc.abi_types_set = true; + type->flags = flags; } // NOTE(bill): 'operands' is for generating non generic procedure type diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 4abc65ab4..c6fee8ab8 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1370,7 +1370,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { // Sanity check continue; } - array_add(¶m_types, lb_type(m, v->type)); + LLVMTypeRef t = lb_type(m, v->type); + array_add(¶m_types, t); } } else { array_add(¶m_types, lb_type(m, param)); diff --git a/src/types.cpp b/src/types.cpp index f4d375f4f..acc1c7b2e 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -324,6 +324,7 @@ enum TypeFlag : u32 { TypeFlag_Polymorphic = 1<<1, TypeFlag_PolySpecialized = 1<<2, TypeFlag_InProcessOfCheckingPolymorphic = 1<<3, + TypeFlag_InProcessOfCheckingABI = 1<<4, }; struct Type { -- cgit v1.2.3 From 70b8b3c7dde193c9c67e4b5fd86fd2f99ee1d987 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 12 Nov 2020 00:43:49 +0000 Subject: Update LLVM backend to begin work on a generic ABI system --- src/llvm_abi.cpp | 762 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/llvm_backend.cpp | 693 +++++++++++++++++++++++++++++++++++----------- src/llvm_backend.hpp | 3 + src/types.cpp | 10 + 4 files changed, 1307 insertions(+), 161 deletions(-) create mode 100644 src/llvm_abi.cpp (limited to 'src/types.cpp') diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp new file mode 100644 index 000000000..2bede5822 --- /dev/null +++ b/src/llvm_abi.cpp @@ -0,0 +1,762 @@ +enum lbArgKind { + lbArg_Direct, + lbArg_Indirect, + lbArg_Ignore, +}; + +struct lbArgType { + lbArgKind kind; + LLVMTypeRef type; + LLVMTypeRef cast_type; // Optional + LLVMTypeRef pad_type; // Optional + LLVMAttributeRef attribute; // Optional +}; + +lbArgType lb_arg_type_direct(LLVMTypeRef type, LLVMTypeRef cast_type, LLVMTypeRef pad_type, LLVMAttributeRef attr) { + return lbArgType{lbArg_Direct, type, cast_type, pad_type, attr}; +} +lbArgType lb_arg_type_direct(LLVMTypeRef type) { + return lb_arg_type_direct(type, nullptr, nullptr, nullptr); +} + +lbArgType lb_arg_type_indirect(LLVMTypeRef type, LLVMAttributeRef attr) { + return lbArgType{lbArg_Indirect, type, nullptr, nullptr, attr}; +} + +lbArgType lb_arg_type_ignore(LLVMTypeRef type) { + return lbArgType{lbArg_Ignore, type, nullptr, nullptr, nullptr}; +} + +struct lbFunctionType { + LLVMContextRef ctx; + ProcCallingConvention calling_convention; + Array args; + lbArgType ret; +}; + + +bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) { + return LLVMGetTypeKind(type) == kind; +} + +LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) { + unsigned arg_count = cast(unsigned)ft->args.count; + unsigned offset = 0; + + LLVMTypeRef ret = nullptr; + if (ft->ret.kind == lbArg_Direct) { + if (ft->ret.cast_type != nullptr) { + ret = ft->ret.cast_type; + } else { + ret = ft->ret.type; + } + } else if (ft->ret.kind == lbArg_Indirect) { + offset += 1; + ret = LLVMVoidTypeInContext(ft->ctx); + } else if (ft->ret.kind == lbArg_Ignore) { + ret = LLVMVoidTypeInContext(ft->ctx); + } + GB_ASSERT_MSG(ret != nullptr, "%d", ft->ret.kind); + + unsigned maximum_arg_count = offset+arg_count; + LLVMTypeRef *args = gb_alloc_array(heap_allocator(), LLVMTypeRef, maximum_arg_count); + if (offset == 1) { + GB_ASSERT(ft->ret.kind == lbArg_Indirect); + args[0] = ft->ret.type; + } + + unsigned arg_index = offset; + for (unsigned i = 0; i < arg_count; i++) { + lbArgType *arg = &ft->args[i]; + if (arg->kind == lbArg_Direct) { + LLVMTypeRef arg_type = nullptr; + if (ft->args[i].cast_type != nullptr) { + arg_type = arg->cast_type; + } else { + arg_type = arg->type; + } + args[arg_index++] = arg_type; + } else if (arg->kind == lbArg_Indirect) { + GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind)); + args[arg_index++] = LLVMPointerType(arg->type, 0); + } else if (arg->kind == lbArg_Ignore) { + // ignore + } + } + unsigned total_arg_count = arg_index; + LLVMTypeRef func_type = LLVMFunctionType(ret, args, total_arg_count, is_var_arg); + return LLVMPointerType(func_type, 0); +} + + +void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) { + if (ft == nullptr) { + return; + } + unsigned arg_count = cast(unsigned)ft->args.count; + unsigned offset = 0; + if (ft->ret.kind == lbArg_Indirect) { + offset += 1; + } + + unsigned arg_index = offset; + for (unsigned i = 0; i < arg_count; i++) { + lbArgType *arg = &ft->args[i]; + if (arg->kind == lbArg_Ignore) { + continue; + } + + if (arg->attribute) { + LLVMAddAttributeAtIndex(fn, arg_index+1, arg->attribute); + } + + arg_index++; + } + + if (offset != 0 && ft->ret.kind == lbArg_Indirect && ft->ret.attribute != nullptr) { + LLVMAddAttributeAtIndex(fn, offset, ft->ret.attribute); + } + + lbCallingConventionKind cc_kind = lbCallingConvention_C; + // TODO(bill): Clean up this logic + if (build_context.metrics.os != TargetOs_js) { + cc_kind = lb_calling_convention_map[calling_convention]; + } + LLVMSetFunctionCallConv(fn, cc_kind); + if (calling_convention == ProcCC_Odin) { + unsigned context_index = offset+arg_count; + LLVMContextRef c = ft->ctx; + LLVMAddAttributeAtIndex(fn, context_index, lb_create_enum_attribute(c, "noalias", true)); + LLVMAddAttributeAtIndex(fn, context_index, lb_create_enum_attribute(c, "nonnull", true)); + LLVMAddAttributeAtIndex(fn, context_index, lb_create_enum_attribute(c, "nocapture", true)); + } + +} + +i64 lb_sizeof(LLVMTypeRef type); +i64 lb_alignof(LLVMTypeRef type); + +i64 lb_sizeof(LLVMTypeRef type) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMVoidTypeKind: + return 0; + case LLVMIntegerTypeKind: + { + unsigned w = LLVMGetIntTypeWidth(type); + return (w + 7)/8; + } + case LLVMFloatTypeKind: + return 4; + case LLVMDoubleTypeKind: + return 8; + case LLVMPointerTypeKind: + return build_context.word_size; + case LLVMStructTypeKind: + { + unsigned field_count = LLVMCountStructElementTypes(type); + i64 offset = 0; + if (LLVMIsPackedStruct(type)) { + for (unsigned i = 0; i < field_count; i++) { + LLVMTypeRef field = LLVMStructGetTypeAtIndex(type, i); + offset += lb_sizeof(field); + } + } else { + for (unsigned i = 0; i < field_count; i++) { + LLVMTypeRef field = LLVMStructGetTypeAtIndex(type, i); + i64 align = lb_alignof(field); + offset = align_formula(offset, align); + offset += lb_sizeof(field); + } + } + offset = align_formula(offset, lb_alignof(type)); + return offset; + } + break; + case LLVMArrayTypeKind: + { + LLVMTypeRef elem = LLVMGetElementType(type); + i64 elem_size = lb_sizeof(elem); + i64 count = LLVMGetVectorSize(type); + i64 size = count * elem_size; + return size; + } + break; + + case LLVMX86_MMXTypeKind: + return 8; + case LLVMVectorTypeKind: + { + LLVMTypeRef elem = LLVMGetElementType(type); + i64 elem_size = lb_sizeof(elem); + i64 count = LLVMGetVectorSize(type); + i64 size = count * elem_size; + return gb_clamp(next_pow2(size), 1, build_context.max_align); + } + + } + GB_PANIC("Unhandled type for lb_sizeof -> %s", LLVMPrintTypeToString(type)); + + // LLVMValueRef v = LLVMSizeOf(type); + // GB_ASSERT(LLVMIsConstant(v)); + // return cast(i64)LLVMConstIntGetSExtValue(v); + return 0; +} + +i64 lb_alignof(LLVMTypeRef type) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMVoidTypeKind: + return 1; + case LLVMIntegerTypeKind: + { + unsigned w = LLVMGetIntTypeWidth(type); + return gb_clamp((w + 7)/8, 1, build_context.max_align); + } + case LLVMFloatTypeKind: + return 4; + case LLVMDoubleTypeKind: + return 8; + case LLVMPointerTypeKind: + return build_context.word_size; + case LLVMStructTypeKind: + { + if (LLVMIsPackedStruct(type)) { + return 1; + } else { + unsigned field_count = LLVMCountStructElementTypes(type); + i64 max_align = 1; + for (unsigned i = 0; i < field_count; i++) { + LLVMTypeRef field = LLVMStructGetTypeAtIndex(type, i); + i64 field_align = lb_alignof(field); + max_align = gb_max(max_align, field_align); + } + return max_align; + } + } + break; + case LLVMArrayTypeKind: + { + LLVMTypeRef elem = LLVMGetElementType(type); + i64 elem_size = lb_sizeof(elem); + i64 count = LLVMGetVectorSize(type); + i64 size = count * elem_size; + return size; + } + break; + + case LLVMX86_MMXTypeKind: + return 8; + case LLVMVectorTypeKind: + { + LLVMTypeRef elem = LLVMGetElementType(type); + i64 elem_size = lb_sizeof(elem); + i64 count = LLVMGetVectorSize(type); + i64 size = count * elem_size; + return gb_clamp(next_pow2(size), 1, build_context.max_align); + } + + } + GB_PANIC("Unhandled type for lb_sizeof -> %s", LLVMPrintTypeToString(type)); + + // LLVMValueRef v = LLVMAlignOf(type); + // GB_ASSERT(LLVMIsConstant(v)); + // return LLVMConstIntGetSExtValue(v); + return 1; +} + +Type *lb_abi_to_odin_type(LLVMTypeRef type) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMVoidTypeKind: + return nullptr; + case LLVMIntegerTypeKind: + { + unsigned w = LLVMGetIntTypeWidth(type); + if (w == 1) { + return t_llvm_bool; + } + unsigned bytes = (w + 7)/8; + switch (bytes) { + case 1: return t_u8; + case 2: return t_u16; + case 4: return t_u32; + case 8: return t_u64; + case 16: return t_u128; + } + GB_PANIC("Unhandled integer type"); + } + case LLVMFloatTypeKind: + return t_f32; + case LLVMDoubleTypeKind: + return t_f64; + case LLVMPointerTypeKind: + return t_rawptr; + case LLVMStructTypeKind: + { + GB_PANIC("HERE"); + } + break; + case LLVMArrayTypeKind: + { + + i64 count = LLVMGetVectorSize(type); + Type *elem = lb_abi_to_odin_type(LLVMGetElementType(type)); + return alloc_type_array(elem, count); + } + break; + + case LLVMX86_MMXTypeKind: + return t_vector_x86_mmx; + case LLVMVectorTypeKind: + { + i64 count = LLVMGetVectorSize(type); + Type *elem = lb_abi_to_odin_type(LLVMGetElementType(type)); + return alloc_type_simd_vector(count, elem); + } + + } + GB_PANIC("Unhandled type for lb_abi_to_odin_type -> %s", LLVMPrintTypeToString(type)); + + // LLVMValueRef v = LLVMSizeOf(type); + // GB_ASSERT(LLVMIsConstant(v)); + // return cast(i64)LLVMConstIntGetSExtValue(v); + return 0; +} + + + +#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, ProcCallingConvention calling_convention) +typedef LB_ABI_INFO(lbAbiInfoType); + + +// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything +namespace lbAbi386 { + Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count); + lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined); + + LB_ABI_INFO(abi_info) { + lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType); + ft->ctx = c; + ft->args = compute_arg_types(c, arg_types, arg_count); + ft->ret = compute_return_type(c, return_type, return_is_defined); + ft->calling_convention = calling_convention; + return ft; + } + + lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) { + if (build_context.metrics.os == TargetOs_windows && + build_context.word_size == 8 && + lb_is_type_kind(type, LLVMIntegerTypeKind) && + lb_sizeof(type) == 16) { + + LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2); + return lb_arg_type_direct(type, cast_type, nullptr, nullptr); + } + + + + LLVMAttributeRef attr = nullptr; + LLVMTypeRef i1 = LLVMInt1TypeInContext(c); + if (type == i1) { + // attr = lb_create_enum_attribute(c, "zext", true); + // return lb_arg_type_direct(type, i1, nullptr, attr); + } + return lb_arg_type_direct(type, nullptr, nullptr, attr); + } + + Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { + auto args = array_make(heap_allocator(), arg_count); + + for (unsigned i = 0; i < arg_count; i++) { + LLVMTypeRef t = arg_types[i]; + LLVMTypeKind kind = LLVMGetTypeKind(t); + if (kind == LLVMStructTypeKind) { + i64 sz = lb_sizeof(t); + if (sz == 0) { + args[i] = lb_arg_type_ignore(t); + } else { + args[i] = lb_arg_type_indirect(t, lb_create_enum_attribute(c, "byval", true)); + } + } else { + args[i] = non_struct(c, t); + } + } + return args; + } + + lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) { + if (!return_is_defined) { + return lb_arg_type_direct(LLVMVoidTypeInContext(c)); + } else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) { + i64 sz = lb_sizeof(return_type); + switch (sz) { + case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr); + case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr); + case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr); + case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr); + } + return lb_arg_type_indirect(LLVMPointerType(return_type, 0), lb_create_enum_attribute(c, "sret", true)); + } + return non_struct(c, return_type); + } +}; + +namespace lbAbiAmd64Win64 { + Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count); + + + LB_ABI_INFO(abi_info) { + lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType); + ft->ctx = c; + ft->args = compute_arg_types(c, arg_types, arg_count); + ft->ret = lbAbi386::compute_return_type(c, return_type, return_is_defined); + ft->calling_convention = calling_convention; + return ft; + } + + Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { + auto args = array_make(heap_allocator(), arg_count); + + for (unsigned i = 0; i < arg_count; i++) { + LLVMTypeRef t = arg_types[i]; + LLVMTypeKind kind = LLVMGetTypeKind(t); + if (kind == LLVMStructTypeKind) { + i64 sz = lb_sizeof(t); + switch (sz) { + case 1: + case 2: + case 4: + case 8: + args[i] = lb_arg_type_direct(t, LLVMIntTypeInContext(c, 8*cast(unsigned)sz), nullptr, nullptr); + break; + default: + args[i] = lb_arg_type_indirect(t, nullptr); + break; + } + } else { + args[i] = lbAbi386::non_struct(c, t); + } + } + return args; + } +}; + +// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything +namespace lbAbiAmd64SysV { + enum RegClass { + RegClass_NoClass, + RegClass_Int, + RegClass_SSEFs, + RegClass_SSEFv, + RegClass_SSEDs, + RegClass_SSEDv, + RegClass_SSEInt, + RegClass_SSEUp, + RegClass_X87, + RegClass_X87Up, + RegClass_ComplexX87, + RegClass_Memory, + }; + + bool is_sse(RegClass reg_class) { + switch (reg_class) { + case RegClass_SSEFs: + case RegClass_SSEFv: + case RegClass_SSEDv: + return true; + } + return false; + } + + void all_mem(Array *cs) { + for_array(i, *cs) { + (*cs)[i] = RegClass_Memory; + } + } + + Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count); + lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined); + void classify_with(LLVMTypeRef t, Array *cls, i64 ix, i64 off); + void fixup(LLVMTypeRef t, Array *cls); + + LB_ABI_INFO(abi_info) { + lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType); + ft->ctx = c; + // TODO(bill): THIS IS VERY VERY WRONG! + ft->args = compute_arg_types(c, arg_types, arg_count); + ft->ret = compute_return_type(c, return_type, return_is_defined); + ft->calling_convention = calling_convention; + return ft; + } + + lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) { + LLVMAttributeRef attr = nullptr; + LLVMTypeRef i1 = LLVMInt1TypeInContext(c); + if (type == i1) { + attr = lb_create_enum_attribute(c, "zext", true); + } + return lb_arg_type_direct(type, nullptr, nullptr, attr); + } + + Array classify(LLVMTypeRef t) { + i64 sz = lb_sizeof(t); + i64 words = (sz + 7)/8; + auto reg_classes = array_make(heap_allocator(), cast(isize)words); + if (words > 4) { + all_mem(®_classes); + } else { + classify_with(t, ®_classes, 0, 0); + fixup(t, ®_classes); + } + return reg_classes; + } + + void classify_struct(LLVMTypeRef *fields, unsigned field_count, Array *cls, i64 i, i64 off, LLVMBool packed) { + i64 field_off = off; + for (unsigned i = 0; i < field_count; i++) { + LLVMTypeRef t = fields[i]; + if (!packed) { + field_off = align_formula(field_off, lb_alignof(t)); + } + classify_with(t, cls, i, field_off); + field_off += lb_sizeof(t); + } + } + + void unify(Array *cls, i64 i, RegClass newv) { + RegClass &oldv = (*cls)[i]; + if (oldv == newv) { + return; + } else if (oldv == RegClass_NoClass) { + oldv = newv; + } else if (newv == RegClass_NoClass) { + return; + } else if (oldv == RegClass_Memory || newv == RegClass_Memory) { + return; + } else if (oldv == RegClass_Int || newv == RegClass_Int) { + return; + } else if (oldv == RegClass_X87 || oldv == RegClass_X87Up || oldv == RegClass_ComplexX87 || + newv == RegClass_X87 || newv == RegClass_X87Up || newv == RegClass_ComplexX87) { + oldv = RegClass_Memory; + } else { + oldv = newv; + } + } + + void fixup(LLVMTypeRef t, Array *cls) { + i64 i = 0; + i64 e = cls->count; + if (e > 2 && (lb_is_type_kind(t, LLVMStructTypeKind) || lb_is_type_kind(t, LLVMArrayTypeKind))) { + RegClass &oldv = (*cls)[i]; + if (is_sse(oldv)) { + for (i++; i < e; i++) { + if (oldv != RegClass_SSEUp) { + all_mem(cls); + return; + } + } + } else { + all_mem(cls); + return; + } + } else { + while (i < e) { + RegClass &oldv = (*cls)[i]; + if (oldv == RegClass_Memory) { + all_mem(cls); + return; + } else if (oldv == RegClass_X87Up) { + // NOTE(bill): Darwin + all_mem(cls); + return; + } else if (oldv == RegClass_SSEUp) { + oldv = RegClass_SSEDv; + } else if (is_sse(oldv)) { + i++; + while (i != e && oldv == RegClass_SSEUp) { + i++; + } + } else if (oldv == RegClass_X87) { + i++; + while (i != e && oldv == RegClass_X87Up) { + i++; + } + } else { + i++; + } + } + } + } + + unsigned llvec_len(Array const ®_classes) { + unsigned len = 1; + for_array(i, reg_classes) { + if (reg_classes[i] != RegClass_SSEUp) { + break; + } + len++; + } + return len; + } + + + LLVMTypeRef llreg(LLVMContextRef c, Array const ®_classes) {; + auto types = array_make(heap_allocator(), 0, reg_classes.count); + for_array(i, reg_classes) { + switch (reg_classes[i]) { + case RegClass_Int: + array_add(&types, LLVMIntTypeInContext(c, 64)); + break; + case RegClass_SSEFv: + { + unsigned vec_len = llvec_len(array_slice(reg_classes, i+1, reg_classes.count)); + LLVMTypeRef vec_type = LLVMVectorType(LLVMFloatTypeInContext(c), vec_len); + array_add(&types, vec_type); + i += vec_len; + continue; + } + break; + case RegClass_SSEFs: + array_add(&types, LLVMFloatTypeInContext(c)); + break; + case RegClass_SSEDs: + array_add(&types, LLVMDoubleTypeInContext(c)); + break; + default: + GB_PANIC("Unhandled RegClass"); + } + } + + return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false); + } + + void classify_with(LLVMTypeRef t, Array *cls, i64 ix, i64 off) { + i64 t_align = lb_alignof(t); + i64 t_size = lb_sizeof(t); + + i64 mis_align = off % t_align; + if (mis_align != 0) { + i64 e = (off + t_size + 7) / 8; + for (i64 i = off / 8; i < e; i++) { + unify(cls, ix+1, RegClass_Memory); + } + return; + } + + switch (LLVMGetTypeKind(t)) { + case LLVMIntegerTypeKind: + case LLVMPointerTypeKind: + unify(cls, ix+off / 8, RegClass_Int); + break; + case LLVMFloatTypeKind: + unify(cls, ix+off / 8, (off%8 == 4) ? RegClass_SSEFv : RegClass_SSEFs); + break; + case LLVMDoubleTypeKind: + unify(cls, ix+off / 8, RegClass_SSEDs); + break; + case LLVMStructTypeKind: + { + unsigned field_count = LLVMCountStructElementTypes(t); + LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); // HACK(bill): LEAK + defer (gb_free(heap_allocator(), fields)); + + LLVMGetStructElementTypes(t, fields); + + classify_struct(fields, field_count, cls, ix, off, LLVMIsPackedStruct(t)); + } + break; + case LLVMArrayTypeKind: + { + i64 len = LLVMGetArrayLength(t); + LLVMTypeRef elem = LLVMGetElementType(t); + i64 elem_sz = lb_sizeof(elem); + for (i64 i = 0; i < len; i++) { + classify_with(elem, cls, ix, off + i*elem_sz); + } + } + break; + default: + GB_PANIC("Unhandled type"); + break; + } + } + + Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { + auto args = array_make(heap_allocator(), arg_count); + + for (unsigned i = 0; i < arg_count; i++) { + LLVMTypeRef t = arg_types[i]; + LLVMTypeKind kind = LLVMGetTypeKind(t); + if (kind == LLVMStructTypeKind) { + i64 sz = lb_sizeof(t); + if (sz == 0) { + args[i] = lb_arg_type_ignore(t); + } else { + args[i] = lb_arg_type_indirect(t, lb_create_enum_attribute(c, "byval", true)); + } + } else { + args[i] = non_struct(c, t); + } + } + return args; + } + + lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) { + if (!return_is_defined) { + return lb_arg_type_direct(LLVMVoidTypeInContext(c)); + } else if (lb_is_type_kind(return_type, LLVMStructTypeKind)) { + i64 sz = lb_sizeof(return_type); + switch (sz) { + case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr); + case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr); + case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr); + case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr); + } + return lb_arg_type_indirect(LLVMPointerType(return_type, 0), lb_create_enum_attribute(c, "sret", true)); + } else if (build_context.metrics.os == TargetOs_windows && lb_is_type_kind(return_type, LLVMIntegerTypeKind) && lb_sizeof(return_type) == 16) { + return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 128), nullptr, nullptr); + } + return non_struct(c, return_type); + } +}; + + + + +LB_ABI_INFO(lb_get_abi_info) { + switch (calling_convention) { + case ProcCC_None: + case ProcCC_PureNone: + case ProcCC_InlineAsm: + { + lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType); + ft->ctx = c; + ft->args = array_make(heap_allocator(), arg_count); + for (unsigned i = 0; i < arg_count; i++) { + ft->args[i] = lb_arg_type_direct(arg_types[i]); + } + if (return_is_defined) { + ft->ret = lb_arg_type_direct(return_type); + } else { + ft->ret = lb_arg_type_direct(LLVMVoidTypeInContext(c)); + } + ft->calling_convention = calling_convention; + return ft; + } + } + + if (build_context.metrics.arch == TargetArch_amd64) { + if (build_context.metrics.os == TargetOs_windows) { + return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + } else { + return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + } + } else if (build_context.metrics.arch == TargetArch_386) { + return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + } else if (build_context.metrics.arch == TargetArch_wasm32) { + return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + } + GB_PANIC("Unsupported ABI"); + return {}; +} diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index aab2248d9..a01dd7ede 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1,4 +1,11 @@ #include "llvm_backend.hpp" +#include "llvm_abi.cpp" + +#ifdef USE_NEW_LLVM_ABI_SYSTEM +#define USE_LLVM_ABI 1 +#else +#define USE_LLVM_ABI 0 +#endif gb_global lbAddr lb_global_type_info_data = {}; gb_global lbAddr lb_global_type_info_member_types = {}; @@ -459,7 +466,11 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { GB_ASSERT(value.value != nullptr); value = lb_emit_conv(p, value, lb_addr_type(addr)); - LLVMBuildStore(p->builder, value.value, addr.addr.value); + if (USE_LLVM_ABI) { + lb_emit_store(p, addr.addr, value); + } else { + LLVMBuildStore(p->builder, value.value, addr.addr.value); + } } void lb_const_store(lbValue ptr, lbValue value) { @@ -480,11 +491,25 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { 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)); - } 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); + if (USE_LLVM_ABI && is_type_proc(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) { + 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); + } } lbValue lb_emit_load(lbProcedure *p, lbValue value) { @@ -1132,7 +1157,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { switch (base->kind) { case Type_Basic: - return lb_type(m, base); + return lb_type_internal(m, base); case Type_Named: case Type_Generic: @@ -1141,7 +1166,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { break; case Type_Opaque: - return lb_type(m, base->Opaque.elem); + return lb_type_internal(m, base->Opaque.elem); case Type_Pointer: case Type_Array: @@ -1152,14 +1177,14 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Type_Enum: case Type_BitSet: case Type_SimdVector: - return lb_type(m, base); + return lb_type_internal(m, base); // TODO(bill): Deal with this correctly. Can this be named? case Type_Proc: - return lb_type(m, base); + return lb_type_internal(m, base); case Type_Tuple: - return lb_type(m, base); + return lb_type_internal(m, base); } LLVMTypeRef *found = map_get(&m->types, hash_type(base)); @@ -1196,7 +1221,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } - return lb_type(m, base); + return lb_type_internal(m, base); } case Type_Pointer: @@ -1320,16 +1345,83 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { for_array(i, type->Tuple.variables) { Entity *field = type->Tuple.variables[i]; - fields[i] = lb_type(m, field->type); + + 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: - { - set_procedure_abi_types(heap_allocator(), type); + if (USE_LLVM_ABI) { + if (m->internal_type_level > 1) { + 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; + } + param_count += 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, type->Proc.results); + if (ret != nullptr) { + if (is_calling_convention_none(type->Proc.calling_convention) && + is_type_boolean(single_ret) && + type_size_of(single_ret) <= 1) { + ret = LLVMInt1TypeInContext(m->ctx); + } + } + } + isize 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; + } + + LLVMTypeRef param_type = nullptr; + if (is_calling_convention_none(type->Proc.calling_convention) && + is_type_boolean(e->type) && + type_size_of(e->type) <= 1) { + param_type = LLVMInt1TypeInContext(m->ctx); + } 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_context_ptr); + } + GB_ASSERT(param_index == param_count); + + + lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention); + map_set(&m->function_type_map, hash_type(type), ft); + return lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg); + } + } else { + set_procedure_abi_types(heap_allocator(), type); LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx); if (type->Proc.return_by_pointer) { // Void @@ -1452,10 +1544,14 @@ LLVMTypeRef lb_type(lbModule *m, Type *type) { return *found; } - LLVMTypeRef llvm_type = lb_type_internal(m, type); - - map_set(&m->types, hash_type(type), llvm_type); + LLVMTypeRef llvm_type = nullptr; + m->internal_type_level += 1; + llvm_type = lb_type_internal(m, type); + m->internal_type_level -= 1; + if (USE_LLVM_ABI && m->internal_type_level == 0) { + map_set(&m->types, hash_type(type), llvm_type); + } return llvm_type; } @@ -1999,7 +2095,7 @@ lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) { LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value) { unsigned kind = LLVMGetEnumAttributeKindForName(name, gb_strlen(name)); - GB_ASSERT(kind != 0); + GB_ASSERT_MSG(kind != 0, "unknown attribute: %s", name); return LLVMCreateEnumAttribute(ctx, kind, value); } @@ -2076,12 +2172,26 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { p->value = LLVMAddFunction(m->mod, c_link_name, func_type); - 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]; + lbFunctionType **ft_found = map_get(&m->function_type_map, hash_type(p->type)); + if (USE_LLVM_ABI && ft_found) { + lbFunctionType *abi_ft = *ft_found; + p->abi_function_type = abi_ft; + lb_add_function_type_attributes(p->value, abi_ft, abi_ft->calling_convention); + } else { + 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); } - LLVMSetFunctionCallConv(p->value, cc_kind); + + // 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); @@ -2116,8 +2226,10 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { // 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"); + if (!USE_LLVM_ABI) { + lb_add_proc_attribute_at_index(p, 1, "sret"); + lb_add_proc_attribute_at_index(p, 1, "noalias"); + } offset = 2; } @@ -2150,7 +2262,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { } } - if (pt->Proc.calling_convention == ProcCC_Odin) { + if (!USE_LLVM_ABI && 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"); @@ -2242,7 +2354,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type } isize parameter_index = 0; - if (pt->Proc.param_count) { + if (!USE_LLVM_ABI && 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]; @@ -2397,6 +2509,47 @@ void lb_start_block(lbProcedure *p, lbBlock *b) { p->curr_block = b; } +LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) { + LLVMTypeRef src_type = LLVMTypeOf(val); + GB_ASSERT(lb_sizeof(src_type) == lb_sizeof(dst_type)); + + LLVMTypeKind src_kind = LLVMGetTypeKind(src_type); + LLVMTypeKind dst_kind = LLVMGetTypeKind(dst_type); + if (src_kind == dst_kind) { + if (src_kind == LLVMPointerTypeKind) { + return LLVMBuildPointerCast(p->builder, val, dst_type, ""); + } 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, ""); + } + } + + if (LLVMIsALoadInst(val)) { + LLVMValueRef val_ptr = LLVMGetOperand(val, 0); + val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), ""); + return LLVMBuildLoad(p->builder, val_ptr, ""); + } 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_begin_procedure_body(lbProcedure *p) { DeclInfo *decl = decl_info_of_entity(p->entity); @@ -2429,82 +2582,190 @@ void lb_begin_procedure_body(lbProcedure *p) { GB_ASSERT(p->type != nullptr); - i32 parameter_index = 0; + if (p->abi_function_type) { + lbFunctionType *ft = p->abi_function_type; + unsigned param_offset = 0; - lbValue return_ptr_value = {}; - if (p->type->Proc.return_by_pointer) { - // NOTE(bill): this must be parameter 0 - Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); - Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false); - e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; + lbValue return_ptr_value = {}; + if (ft->ret.kind == lbArg_Indirect) { + // NOTE(bill): this must be parameter 0 + Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); + Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false); + e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; - return_ptr_value.value = LLVMGetParam(p->value, 0); - return_ptr_value.type = ptr_type; - p->return_ptr = lb_addr(return_ptr_value); + return_ptr_value.value = LLVMGetParam(p->value, 0); + return_ptr_value.type = ptr_type; + p->return_ptr = lb_addr(return_ptr_value); - lb_add_entity(p->module, e, return_ptr_value); + lb_add_entity(p->module, e, return_ptr_value); - parameter_index += 1; - } + param_offset += 1; + } - if (p->type->Proc.params != nullptr) { - TypeTuple *params = &p->type->Proc.params->Tuple; - auto abi_types = p->type->Proc.abi_compat_params; + if (p->type->Proc.params != nullptr) { + TypeTuple *params = &p->type->Proc.params->Tuple; - for_array(i, params->variables) { - Entity *e = params->variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - Type *abi_type = e->type; - if (abi_types.count > 0) { - abi_type = abi_types[i]; - } - if (e->token.string != "") { - lb_add_param(p, e, nullptr, abi_type, parameter_index); - } - if (is_type_tuple(abi_type)) { - parameter_index += cast(i32)abi_type->Tuple.variables.count; - } else { - parameter_index += 1; + 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); + + if (USE_LLVM_ABI && LLVMTypeOf(value) == LLVMInt1TypeInContext(p->module->ctx)) { + value = LLVMBuildZExtOrBitCast(p->builder, value, param_type, ""); + } else { + 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; - 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); - 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)); - 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); + } - lbAddr res = {}; - if (p->type->Proc.return_by_pointer) { - 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); } - res = lb_addr(ptr); - lb_add_entity(p->module, e, ptr); + 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); + } + } + } + } + } else { + i32 parameter_index = 0; + lbValue return_ptr_value = {}; + if (p->type->Proc.return_by_pointer) { + // NOTE(bill): this must be parameter 0 + Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); + Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false); + e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; + + return_ptr_value.value = LLVMGetParam(p->value, 0); + return_ptr_value.type = ptr_type; + p->return_ptr = lb_addr(return_ptr_value); + + lb_add_entity(p->module, e, return_ptr_value); + + parameter_index += 1; + } + + if (p->type->Proc.params != nullptr) { + TypeTuple *params = &p->type->Proc.params->Tuple; + auto abi_types = p->type->Proc.abi_compat_params; + + for_array(i, params->variables) { + Entity *e = params->variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + Type *abi_type = e->type; + if (abi_types.count > 0) { + abi_type = abi_types[i]; + } + if (e->token.string != "") { + lb_add_param(p, e, nullptr, abi_type, parameter_index); + } + if (is_type_tuple(abi_type)) { + parameter_index += cast(i32)abi_type->Tuple.variables.count; } else { - res = lb_add_local(p, e->type, e); + parameter_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 (p->type->Proc.return_by_pointer) { + lbValue ptr = return_ptr_value; + if (results->variables.count != 1) { + ptr = lb_emit_struct_ep(p, ptr, cast(i32)i); + } - 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); + 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) { Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false); e->flags |= EntityFlag_NoAlias; @@ -6997,15 +7258,33 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, if (context_ptr.addr.value != nullptr) { args[arg_index++] = context_ptr.addr.value; } + LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder); + GB_ASSERT(curr_block != p->decl_block->block); - LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder); - GB_ASSERT(curr_block != p->decl_block->block); + if (USE_LLVM_ABI) { - LLVMValueRef ret = LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(p->module, value.type)), value.value, args, arg_count, "");; - lbValue res = {}; - res.value = ret; - res.type = abi_rt; - return res; + 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)); + + LLVMValueRef ret = LLVMBuildCall2(p->builder, ft, fn, args, arg_count, "");; + lbValue res = {}; + res.value = ret; + res.type = abi_rt; + return res; + } else { + + LLVMValueRef ret = LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(p->module, value.type)), value.value, args, arg_count, "");; + lbValue res = {}; + res.value = ret; + res.type = abi_rt; + return res; + } } lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array const &args) { @@ -7061,95 +7340,186 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count); } + lbValue result = {}; + auto processed_args = array_make(heap_allocator(), 0, args.count); - for (isize i = 0; i < param_count; i++) { - Entity *e = pt->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - // array_add(&processed_args, args[i]); - continue; + if (USE_LLVM_ABI) { + 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(e->flags & EntityFlag_Param); - - Type *original_type = e->type; - Type *new_type = pt->Proc.abi_compat_params[i]; - Type *arg_type = args[i].type; - - if (are_types_identical(arg_type, new_type)) { - // NOTE(bill): Done - array_add(&processed_args, args[i]); - } else if (!are_types_identical(original_type, new_type)) { - if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { - Type *av = core_type(type_deref(new_type)); - if (are_types_identical(av, core_type(original_type))) { - if (e->flags&EntityFlag_ImplicitReference) { - array_add(&processed_args, lb_address_from_load_or_generate_local(p, args[i])); - } else if (!is_type_pointer(arg_type)) { - array_add(&processed_args, lb_copy_value_to_ptr(p, args[i], original_type, 16)); - } - } else { - array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); + GB_ASSERT(ft_found != nullptr); + + lbFunctionType *abi_ft = *ft_found; + bool return_by_pointer = abi_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 = &abi_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; } - } else if (new_type == t_llvm_bool) { - array_add(&processed_args, lb_emit_conv(p, args[i], new_type)); - } else if (is_type_integer(new_type) || is_type_float(new_type) || is_type_boolean(new_type)) { - array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); - } else if (is_type_simd_vector(new_type)) { - array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); - } else if (is_type_tuple(new_type)) { - Type *abi_type = pt->Proc.abi_compat_params[i]; - Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type); - lbValue x = {}; - i64 st_sz = type_size_of(st); - i64 arg_sz = type_size_of(args[i].type); - if (st_sz == arg_sz) { - x = lb_emit_transmute(p, args[i], st); + if (xt == abi_type) { + array_add(&processed_args, x); } else { - // NOTE(bill): struct{f32, f32, f32} != struct{#simd[2]f32, f32} - GB_ASSERT(st_sz > arg_sz); - lbAddr xx = lb_add_local_generated(p, st, false); - lbValue pp = lb_emit_conv(p, xx.addr, alloc_type_pointer(args[i].type)); - lb_emit_store(p, pp, args[i]); - x = lb_addr_load(p, xx); - } - for (isize j = 0; j < new_type->Tuple.variables.count; j++) { - lbValue xx = lb_emit_struct_ev(p, x, cast(i32)j); - array_add(&processed_args, xx); + Type *at = lb_abi_to_odin_type(abi_type); + if (at == t_llvm_bool) { + x = lb_emit_conv(p, x, at); + } else { + x = lb_emit_transmute(p, x, at); + } + array_add(&processed_args, x); } + + } else if (arg->kind == lbArg_Indirect) { + // lbValue ptr = lb_copy_value_to_ptr(p, x, original_type, 16); + lbValue ptr = lb_address_from_load_or_generate_local(p, x); + array_add(&processed_args, ptr); } - } else { - lbValue x = lb_emit_conv(p, args[i], new_type); - array_add(&processed_args, x); + + param_index += 1; } - } - if (inlining == ProcInlining_none) { - inlining = p->inlining; - } + if (inlining == ProcInlining_none) { + inlining = p->inlining; + } - lbValue result = {}; + Type *rt = reduce_tuple_to_single_type(results); + if (return_by_pointer) { - Type *abi_rt = reduce_tuple_to_single_type(pt->Proc.abi_compat_result_type); - Type *rt = reduce_tuple_to_single_type(results); - if (pt->Proc.return_by_pointer) { - lbValue return_ptr = {}; - if (use_return_ptr_hint && p->return_ptr_hint_value.value != nullptr) { - if (are_types_identical(type_deref(p->return_ptr_hint_value.type), rt)) { - return_ptr = p->return_ptr_hint_value; - p->return_ptr_hint_used = true; + lbValue return_ptr = {}; + // if (use_return_ptr_hint && p->return_ptr_hint_value.value != nullptr) { + // if (are_types_identical(type_deref(p->return_ptr_hint_value.type), rt)) { + // return_ptr = p->return_ptr_hint_value; + // p->return_ptr_hint_used = true; + // } + // } + // 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 { + LLVMTypeRef ret_type = abi_ft->ret.cast_type; + if (!ret_type) { + ret_type = abi_ft->ret.type; + } + Type *abi_rt = lb_abi_to_odin_type(ret_type); + result = lb_emit_call_internal(p, value, {}, processed_args, abi_rt, context_ptr, inlining); + if (abi_rt != rt) { + result = lb_emit_transmute(p, result, rt); } } - 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 { - result = lb_emit_call_internal(p, value, {}, processed_args, abi_rt, context_ptr, inlining); - if (abi_rt != rt) { - result = lb_emit_transmute(p, result, rt); + for (isize i = 0; i < param_count; i++) { + Entity *e = pt->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + // array_add(&processed_args, args[i]); + continue; + } + GB_ASSERT(e->flags & EntityFlag_Param); + + Type *original_type = e->type; + Type *new_type = pt->Proc.abi_compat_params[i]; + Type *arg_type = args[i].type; + + if (are_types_identical(arg_type, new_type)) { + // NOTE(bill): Done + array_add(&processed_args, args[i]); + } else if (!are_types_identical(original_type, new_type)) { + if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { + Type *av = core_type(type_deref(new_type)); + if (are_types_identical(av, core_type(original_type))) { + if (e->flags&EntityFlag_ImplicitReference) { + array_add(&processed_args, lb_address_from_load_or_generate_local(p, args[i])); + } else if (!is_type_pointer(arg_type)) { + array_add(&processed_args, lb_copy_value_to_ptr(p, args[i], original_type, 16)); + } + } else { + array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); + } + } else if (new_type == t_llvm_bool) { + array_add(&processed_args, lb_emit_conv(p, args[i], new_type)); + } else if (is_type_integer(new_type) || is_type_float(new_type) || is_type_boolean(new_type)) { + array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); + } else if (is_type_simd_vector(new_type)) { + array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); + } else if (is_type_tuple(new_type)) { + Type *abi_type = pt->Proc.abi_compat_params[i]; + Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type); + lbValue x = {}; + i64 st_sz = type_size_of(st); + i64 arg_sz = type_size_of(args[i].type); + if (st_sz == arg_sz) { + x = lb_emit_transmute(p, args[i], st); + } else { + // NOTE(bill): struct{f32, f32, f32} != struct{#simd[2]f32, f32} + GB_ASSERT(st_sz > arg_sz); + lbAddr xx = lb_add_local_generated(p, st, false); + lbValue pp = lb_emit_conv(p, xx.addr, alloc_type_pointer(args[i].type)); + lb_emit_store(p, pp, args[i]); + x = lb_addr_load(p, xx); + } + for (isize j = 0; j < new_type->Tuple.variables.count; j++) { + lbValue xx = lb_emit_struct_ev(p, x, cast(i32)j); + array_add(&processed_args, xx); + } + } + } else { + lbValue x = lb_emit_conv(p, args[i], new_type); + array_add(&processed_args, x); + } + } + + if (inlining == ProcInlining_none) { + inlining = p->inlining; + } + + + Type *abi_rt = reduce_tuple_to_single_type(pt->Proc.abi_compat_result_type); + Type *rt = reduce_tuple_to_single_type(results); + if (pt->Proc.return_by_pointer) { + lbValue return_ptr = {}; + if (use_return_ptr_hint && p->return_ptr_hint_value.value != nullptr) { + if (are_types_identical(type_deref(p->return_ptr_hint_value.type), rt)) { + return_ptr = p->return_ptr_hint_value; + p->return_ptr_hint_used = true; + } + } + 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 { + result = lb_emit_call_internal(p, value, {}, processed_args, abi_rt, context_ptr, inlining); + if (abi_rt != rt) { + result = lb_emit_transmute(p, result, rt); + } } } @@ -10969,6 +11339,7 @@ void lb_init_module(lbModule *m, Checker *c) { 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); array_init(&m->procedures_to_generate, a); array_init(&m->foreign_library_paths, a); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 4a0816e62..fc5968c93 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -74,6 +74,7 @@ struct lbModule { gbMutex mutex; Map types; // Key: Type * + i32 internal_type_level; Map values; // Key: Entity * StringMap members; @@ -83,6 +84,7 @@ struct lbModule { StringMap const_strings; Map anonymous_proc_lits; // Key: Ast * + Map function_type_map; // Key: Type * u32 global_array_index; u32 global_generated_index; @@ -199,6 +201,7 @@ struct lbProcedure { bool is_entry_point; bool is_startup; + lbFunctionType *abi_function_type; LLVMValueRef value; LLVMBuilderRef builder; diff --git a/src/types.cpp b/src/types.cpp index acc1c7b2e..528ea3a2d 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -886,6 +886,16 @@ Type *alloc_type_named(String name, Type *base, Entity *type_name) { return t; } +bool is_calling_convention_none(ProcCallingConvention calling_convention) { + switch (calling_convention) { + case ProcCC_None: + case ProcCC_PureNone: + case ProcCC_InlineAsm: + return true; + } + return false; +} + Type *alloc_type_tuple() { Type *t = alloc_type(Type_Tuple); return t; -- cgit v1.2.3 From a64ea342df4cffa881b5829b8864e22fb9e116ab Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 12 Nov 2020 23:40:13 +0000 Subject: Improve USE_NEW_LLVM_ABI_SYSTEM's System V ABI --- src/llvm_abi.cpp | 116 +++++++++++++++++++++++-------------- src/llvm_backend.cpp | 160 ++++++++++++++++++++++++++++++++++++++++----------- src/types.cpp | 1 - 3 files changed, 198 insertions(+), 79 deletions(-) (limited to 'src/types.cpp') diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 1fa004c8c..d9e115a34 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -66,7 +66,7 @@ LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) { LLVMTypeRef *args = gb_alloc_array(heap_allocator(), LLVMTypeRef, maximum_arg_count); if (offset == 1) { GB_ASSERT(ft->ret.kind == lbArg_Indirect); - args[0] = ft->ret.type; + args[0] = LLVMPointerType(ft->ret.type, 0); } unsigned arg_index = offset; @@ -172,8 +172,8 @@ i64 lb_sizeof(LLVMTypeRef type) { offset = llvm_align_formula(offset, align); offset += lb_sizeof(field); } + offset = llvm_align_formula(offset, lb_alignof(type)); } - offset = llvm_align_formula(offset, lb_alignof(type)); return offset; } break; @@ -240,14 +240,7 @@ i64 lb_alignof(LLVMTypeRef type) { } break; case LLVMArrayTypeKind: - { - LLVMTypeRef elem = LLVMGetElementType(type); - i64 elem_size = lb_sizeof(elem); - i64 count = LLVMGetArrayLength(type); - i64 size = count * elem_size; - return size; - } - break; + return lb_alignof(LLVMGetElementType(type)); case LLVMX86_MMXTypeKind: return 8; @@ -269,7 +262,37 @@ i64 lb_alignof(LLVMTypeRef type) { return 1; } -Type *lb_abi_to_odin_type(LLVMTypeRef type) { +Type *alloc_type_struct_from_field_types(Type **field_types, isize field_count, bool is_packed) { + Type *t = alloc_type_struct(); + t->Struct.fields = array_make(heap_allocator(), field_count); + + Scope *scope = nullptr; + for_array(i, t->Struct.fields) { + t->Struct.fields[i] = alloc_entity_field(scope, blank_token, field_types[i], false, cast(i32)i, EntityState_Resolved); + } + t->Struct.is_packed = is_packed; + + return t; +} + +Type *alloc_type_tuple_from_field_types(Type **field_types, isize field_count, bool is_packed) { + if (field_count == 1) { + return field_types[0]; + } + + Type *t = alloc_type_tuple(); + t->Tuple.variables = array_make(heap_allocator(), field_count); + + Scope *scope = nullptr; + for_array(i, t->Tuple.variables) { + t->Tuple.variables[i] = alloc_entity_param(scope, blank_token, field_types[i], false, false); + } + t->Tuple.is_packed = is_packed; + + return t; +} + +Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) { LLVMTypeKind kind = LLVMGetTypeKind(type); switch (kind) { case LLVMVoidTypeKind: @@ -282,10 +305,10 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type) { } unsigned bytes = (w + 7)/8; switch (bytes) { - case 1: return t_u8; - case 2: return t_u16; - case 4: return t_u32; - case 8: return t_u64; + case 1: return t_u8; + case 2: return t_u16; + case 4: return t_u32; + case 8: return t_u64; case 16: return t_u128; } GB_PANIC("Unhandled integer type"); @@ -298,14 +321,23 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type) { return t_rawptr; case LLVMStructTypeKind: { - GB_PANIC("HERE"); + unsigned field_count = LLVMCountStructElementTypes(type); + Type **fields = gb_alloc_array(heap_allocator(), Type *, field_count); + for (unsigned i = 0; i < field_count; i++) { + fields[i] = lb_abi_to_odin_type(LLVMStructGetTypeAtIndex(type, i), false, level+1); + } + if (is_return) { + return alloc_type_tuple_from_field_types(fields, field_count, !!LLVMIsPackedStruct(type)); + } else { + return alloc_type_struct_from_field_types(fields, field_count, !!LLVMIsPackedStruct(type)); + } } break; case LLVMArrayTypeKind: { i64 count = LLVMGetArrayLength(type); - Type *elem = lb_abi_to_odin_type(LLVMGetElementType(type)); + Type *elem = lb_abi_to_odin_type(LLVMGetElementType(type), false, level+1); return alloc_type_array(elem, count); } break; @@ -315,7 +347,7 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type) { case LLVMVectorTypeKind: { i64 count = LLVMGetVectorSize(type); - Type *elem = lb_abi_to_odin_type(LLVMGetElementType(type)); + Type *elem = lb_abi_to_odin_type(LLVMGetElementType(type), false, level+1); return alloc_type_simd_vector(count, elem); } @@ -400,7 +432,7 @@ namespace lbAbi386 { case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr); case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr); } - return lb_arg_type_indirect(LLVMPointerType(return_type, 0), lb_create_enum_attribute(c, "sret", true)); + return lb_arg_type_indirect(return_type, lb_create_enum_attribute(c, "sret", true)); } return non_struct(c, return_type); } @@ -588,18 +620,6 @@ namespace lbAbiAmd64SysV { return reg_classes; } - void classify_struct(LLVMTypeRef *fields, unsigned field_count, Array *cls, i64 i, i64 off, LLVMBool packed) { - i64 field_off = off; - for (unsigned i = 0; i < field_count; i++) { - LLVMTypeRef t = fields[i]; - if (!packed) { - field_off = llvm_align_formula(field_off, lb_alignof(t)); - } - classify_with(t, cls, i, field_off); - field_off += lb_sizeof(t); - } - } - void unify(Array *cls, i64 i, RegClass newv) { RegClass &oldv = (*cls)[i]; if (oldv == newv) { @@ -665,10 +685,10 @@ namespace lbAbiAmd64SysV { } } - unsigned llvec_len(Array const ®_classes) { + unsigned llvec_len(Array const ®_classes, isize offset) { unsigned len = 1; - for_array(i, reg_classes) { - if (reg_classes[i] != RegClass_SSEUp) { + for (isize i = offset+1; i < reg_classes.count; i++) { + if (reg_classes[offset] != RegClass_SSEFv && reg_classes[i] != RegClass_SSEUp) { break; } len++; @@ -680,7 +700,8 @@ namespace lbAbiAmd64SysV { LLVMTypeRef llreg(LLVMContextRef c, Array const ®_classes) { auto types = array_make(heap_allocator(), 0, reg_classes.count); for_array(i, reg_classes) { - switch (reg_classes[i]) { + RegClass reg_class = reg_classes[i]; + switch (reg_class) { case RegClass_Int: array_add(&types, LLVMIntTypeInContext(c, 64)); break; @@ -693,7 +714,7 @@ namespace lbAbiAmd64SysV { { unsigned elems_per_word = 0; LLVMTypeRef elem_type = nullptr; - switch (reg_classes[i]) { + switch (reg_class) { case RegClass_SSEFv: elems_per_word = 2; elem_type = LLVMFloatTypeInContext(c); @@ -720,7 +741,7 @@ namespace lbAbiAmd64SysV { break; } - unsigned vec_len = llvec_len(array_slice(reg_classes, i+1, reg_classes.count)); + unsigned vec_len = llvec_len(reg_classes, i); LLVMTypeRef vec_type = LLVMVectorType(elem_type, vec_len * elems_per_word); array_add(&types, vec_type); i += vec_len; @@ -738,6 +759,10 @@ namespace lbAbiAmd64SysV { } } + GB_ASSERT(types.count != 0); + if (types.count == 1) { + return types[0]; + } return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false); } @@ -767,13 +792,18 @@ namespace lbAbiAmd64SysV { break; case LLVMStructTypeKind: { + LLVMBool packed = LLVMIsPackedStruct(t); unsigned field_count = LLVMCountStructElementTypes(t); - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); // HACK(bill): LEAK - defer (gb_free(heap_allocator(), fields)); - - LLVMGetStructElementTypes(t, fields); - classify_struct(fields, field_count, cls, ix, off, LLVMIsPackedStruct(t)); + i64 field_off = off; + for (unsigned field_index = 0; field_index < field_count; field_index++) { + LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(t, field_index); + if (!packed) { + field_off = llvm_align_formula(field_off, lb_alignof(field_type)); + } + classify_with(field_type, cls, ix, field_off); + field_off += lb_sizeof(field_type); + } } break; case LLVMArrayTypeKind: @@ -859,7 +889,7 @@ namespace lbAbiAmd64SysV { case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr); case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr); } - return lb_arg_type_indirect(LLVMPointerType(return_type, 0), lb_create_enum_attribute(c, "sret", true)); + return lb_arg_type_indirect(return_type, lb_create_enum_attribute(c, "sret", true)); } else if (build_context.metrics.os == TargetOs_windows && lb_is_type_kind(return_type, LLVMIntegerTypeKind) && lb_sizeof(return_type) == 16) { return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 128), nullptr, nullptr); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index a01dd7ede..fbddb893e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1380,7 +1380,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { 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, type->Proc.results); + ret = lb_type(m, single_ret); if (ret != nullptr) { if (is_calling_convention_none(type->Proc.calling_convention) && is_type_boolean(single_ret) && @@ -1399,13 +1399,15 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { continue; } + Type *e_type = reduce_tuple_to_single_type(e->type); + LLVMTypeRef param_type = nullptr; if (is_calling_convention_none(type->Proc.calling_convention) && - is_type_boolean(e->type) && - type_size_of(e->type) <= 1) { + is_type_boolean(e_type) && + type_size_of(e_type) <= 1) { param_type = LLVMInt1TypeInContext(m->ctx); } else { - param_type = lb_type(m, e->type); + param_type = lb_type(m, e_type); } params[param_index++] = param_type; } @@ -2511,7 +2513,13 @@ void lb_start_block(lbProcedure *p, lbBlock *b) { LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) { LLVMTypeRef src_type = LLVMTypeOf(val); - GB_ASSERT(lb_sizeof(src_type) == lb_sizeof(dst_type)); + i64 src_size = lb_sizeof(src_type); + i64 dst_size = lb_sizeof(dst_type); + if (src_size != dst_size && (lb_is_type_kind(src_type, LLVMVectorTypeKind) ^ lb_is_type_kind(dst_type, LLVMVectorTypeKind))) { + // Okay + } else { + GB_ASSERT_MSG(src_size == dst_size, "%s == %s", LLVMPrintTypeToString(src_type), LLVMPrintTypeToString(dst_type)); + } LLVMTypeKind src_kind = LLVMGetTypeKind(src_type); LLVMTypeKind dst_kind = LLVMGetTypeKind(dst_type); @@ -4538,27 +4546,51 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { } - if (p->type->Proc.return_by_pointer) { - if (res.value != nullptr) { - lb_addr_store(p, p->return_ptr, res); + if (p->abi_function_type) { + if (p->abi_function_type->ret.kind == lbArg_Indirect) { + 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 { - lb_addr_store(p, p->return_ptr, lb_const_nil(p->module, p->type->Proc.abi_compat_result_type)); + LLVMValueRef ret_val = res.value; + 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); } + } else { + GB_ASSERT(!USE_LLVM_ABI); - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + if (p->type->Proc.return_by_pointer) { + if (res.value != nullptr) { + lb_addr_store(p, p->return_ptr, res); + } else { + lb_addr_store(p, p->return_ptr, lb_const_nil(p->module, p->type->Proc.abi_compat_result_type)); + } - LLVMBuildRetVoid(p->builder); - } else { - GB_ASSERT_MSG(res.value != nullptr, "%.*s", LIT(p->name)); - Type *abi_rt = p->type->Proc.abi_compat_result_type; - if (!are_types_identical(res.type, abi_rt)) { - res = lb_emit_transmute(p, res, abi_rt); - } + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + LLVMBuildRetVoid(p->builder); + } else { + GB_ASSERT_MSG(res.value != nullptr, "%.*s", LIT(p->name)); - LLVMBuildRet(p->builder, res.value); + Type *abi_rt = p->type->Proc.abi_compat_result_type; + if (!are_types_identical(res.type, abi_rt)) { + res = lb_emit_transmute(p, res, abi_rt); + } + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + LLVMBuildRet(p->builder, res.value); + } } + + case_end; case_ast_node(is, IfStmt, node); @@ -6585,8 +6617,6 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return res; } - - // []byte/[]u8 <-> string if (is_type_u8_slice(src) && is_type_string(dst)) { return lb_emit_transmute(p, value, t); @@ -6636,6 +6666,34 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { 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); @@ -6716,6 +6774,14 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { 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 @@ -7353,8 +7419,8 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, } GB_ASSERT(ft_found != nullptr); - lbFunctionType *abi_ft = *ft_found; - bool return_by_pointer = abi_ft->ret.kind == lbArg_Indirect; + lbFunctionType *ft = *ft_found; + bool return_by_pointer = ft->ret.kind == lbArg_Indirect; unsigned param_index = 0; for (isize i = 0; i < param_count; i++) { @@ -7365,7 +7431,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, GB_ASSERT(e->flags & EntityFlag_Param); Type *original_type = e->type; - lbArgType *arg = &abi_ft->args[param_index]; + lbArgType *arg = &ft->args[param_index]; if (arg->kind == lbArg_Ignore) { continue; } @@ -7381,9 +7447,15 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, if (xt == abi_type) { array_add(&processed_args, x); } else { - Type *at = lb_abi_to_odin_type(abi_type); + Type *at = lb_abi_to_odin_type(abi_type, false); if (at == t_llvm_bool) { x = lb_emit_conv(p, x, at); + } else if (is_type_simd_vector(at) && lb_sizeof(abi_type) > lb_sizeof(xt)) { + lbAddr v = lb_add_local_generated(p, at, false); + lbValue ptr = lb_addr_get_ptr(p, v); + ptr = lb_emit_conv(p, ptr, alloc_type_pointer(x.type)); + lb_emit_store(p, ptr, x); + x = lb_addr_load(p, v); } else { x = lb_emit_transmute(p, x, at); } @@ -7420,16 +7492,27 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, 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 { - LLVMTypeRef ret_type = abi_ft->ret.cast_type; + } else if (rt != nullptr) { + LLVMTypeRef ret_type = ft->ret.cast_type; if (!ret_type) { - ret_type = abi_ft->ret.type; + ret_type = ft->ret.type; } - Type *abi_rt = lb_abi_to_odin_type(ret_type); + Type *abi_rt = lb_abi_to_odin_type(ret_type, true); result = lb_emit_call_internal(p, value, {}, processed_args, abi_rt, context_ptr, inlining); - if (abi_rt != rt) { - result = lb_emit_transmute(p, result, rt); + if (ret_type != lb_type(m, rt)) { + if (is_type_simd_vector(abi_rt) && lb_sizeof(ret_type) > type_size_of(rt)) { + lbValue ptr = lb_address_from_load_or_generate_local(p, result); + ptr = lb_emit_conv(p, ptr, alloc_type_pointer(rt)); + result = lb_emit_load(p, ptr); + } else { + result = lb_emit_transmute(p, result, rt); + } } + 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); } } else { @@ -12856,6 +12939,10 @@ void lb_generate_code(lbGenerator *gen) { LLVMRunFunctionPassManager(default_function_pass_manager, p->value); } + + String filepath_ll = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".ll")); + defer (gb_free(heap_allocator(), filepath_ll.text)); + TIME_SECTION("LLVM Procedure Generation"); for_array(i, m->procedures_to_generate) { lbProcedure *p = m->procedures_to_generate[i]; @@ -12886,7 +12973,11 @@ void lb_generate_code(lbGenerator *gen) { gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name)); LLVMDumpValue(p->value); gb_printf_err("\n\n\n\n"); - LLVMVerifyFunction(p->value, LLVMAbortProcessAction); + if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + } + LLVMVerifyFunction(p->value, LLVMPrintMessageAction); + gb_exit(1); } } @@ -12933,9 +13024,6 @@ void lb_generate_code(lbGenerator *gen) { llvm_error = nullptr; defer (LLVMDisposeMessage(llvm_error)); - String filepath_ll = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".ll")); - defer (gb_free(heap_allocator(), filepath_ll.text)); - String filepath_obj = {}; LLVMCodeGenFileType code_gen_file_type = LLVMObjectFile; @@ -12962,6 +13050,7 @@ void lb_generate_code(lbGenerator *gen) { LLVMDIBuilderFinalize(m->debug_builder); if (LLVMVerifyModule(mod, LLVMAbortProcessAction, &llvm_error)) { gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); return; } llvm_error = nullptr; @@ -12969,6 +13058,7 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Print Module to File"); if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) { gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); return; } } diff --git a/src/types.cpp b/src/types.cpp index 528ea3a2d..1a55c9b05 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2388,7 +2388,6 @@ Selection lookup_field_from_index(Type *type, i64 index) { return empty_selection; } - Entity *scope_lookup_current(Scope *s, String const &name); Selection lookup_field_with_selection(Type *type_, String field_name, bool is_type, Selection sel, bool allow_blank_ident) { -- cgit v1.2.3 From 3c1c10a1785a97831a69fb6d94356d5cc4989bd6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Nov 2020 18:08:52 +0000 Subject: Begin clarifying allocation patterns by changing from `heap_allocator` to specific arenas --- src/checker.cpp | 4 +- src/checker.hpp | 2 - src/common.cpp | 48 +++++++-- src/entity.cpp | 2 +- src/llvm_abi.cpp | 7 +- src/llvm_backend.cpp | 279 +++++++++++++++++++++------------------------------ src/main.cpp | 16 ++- src/parser.cpp | 43 ++++---- src/parser.hpp | 1 + src/types.cpp | 8 +- 10 files changed, 209 insertions(+), 201 deletions(-) (limited to 'src/types.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index fe669ab8c..a07a3ffbe 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -690,8 +690,10 @@ void add_global_type_entity(String name, Type *type) { void init_universal(void) { BuildContext *bc = &build_context; + // NOTE(bill): No need to free these - gbAllocator a = heap_allocator(); + // gbAllocator a = heap_allocator(); + gbAllocator a = permanent_allocator(); builtin_pkg = gb_alloc_item(a, AstPackage); builtin_pkg->name = str_lit("builtin"); diff --git a/src/checker.hpp b/src/checker.hpp index 3d21a4cec..88e9451ee 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -337,8 +337,6 @@ struct Checker { - - gb_global AstPackage *builtin_pkg = nullptr; gb_global AstPackage *intrinsics_pkg = nullptr; gb_global AstPackage *config_pkg = nullptr; diff --git a/src/common.cpp b/src/common.cpp index 350127e1e..567655c04 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -373,8 +373,8 @@ typedef struct Arena { gbAllocator backing; isize block_size; gbMutex mutex; - isize total_used; + bool use_mutex; } Arena; #define ARENA_MIN_ALIGNMENT 16 @@ -388,8 +388,9 @@ void arena_init(Arena *arena, gbAllocator backing, isize block_size=ARENA_DEFAUL } void arena_grow(Arena *arena, isize min_size) { - // gb_mutex_lock(&arena->mutex); - // defer (gb_mutex_unlock(&arena->mutex)); + if (arena->use_mutex) { + gb_mutex_lock(&arena->mutex); + } isize size = gb_max(arena->block_size, min_size); size = ALIGN_UP(size, ARENA_MIN_ALIGNMENT); @@ -399,11 +400,16 @@ void arena_grow(Arena *arena, isize min_size) { GB_ASSERT(arena->ptr == ALIGN_DOWN_PTR(arena->ptr, ARENA_MIN_ALIGNMENT)); arena->end = arena->ptr + size; array_add(&arena->blocks, arena->ptr); + + if (arena->use_mutex) { + gb_mutex_unlock(&arena->mutex); + } } void *arena_alloc(Arena *arena, isize size, isize alignment) { - // gb_mutex_lock(&arena->mutex); - // defer (gb_mutex_unlock(&arena->mutex)); + if (arena->use_mutex) { + gb_mutex_lock(&arena->mutex); + } arena->total_used += size; @@ -419,12 +425,17 @@ void *arena_alloc(Arena *arena, isize size, isize alignment) { GB_ASSERT(arena->ptr <= arena->end); GB_ASSERT(ptr == ALIGN_DOWN_PTR(ptr, align)); // zero_size(ptr, size); + + if (arena->use_mutex) { + gb_mutex_unlock(&arena->mutex); + } return ptr; } void arena_free_all(Arena *arena) { - // gb_mutex_lock(&arena->mutex); - // defer (gb_mutex_unlock(&arena->mutex)); + if (arena->use_mutex) { + gb_mutex_lock(&arena->mutex); + } for_array(i, arena->blocks) { gb_free(arena->backing, arena->blocks[i]); @@ -432,6 +443,10 @@ void arena_free_all(Arena *arena) { array_clear(&arena->blocks); arena->ptr = nullptr; arena->end = nullptr; + + if (arena->use_mutex) { + gb_mutex_unlock(&arena->mutex); + } } @@ -460,7 +475,14 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) { // GB_PANIC("gbAllocation_Free not supported"); break; case gbAllocation_Resize: - GB_PANIC("gbAllocation_Resize: not supported"); + if (size == 0) { + ptr = nullptr; + } else if (size <= old_size) { + ptr = old_memory; + } else { + ptr = arena_alloc(arena, size, alignment); + gb_memmove(ptr, old_memory, old_size); + } break; case gbAllocation_FreeAll: arena_free_all(arena); @@ -472,6 +494,16 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) { +gb_global Arena permanent_arena = {}; +gb_global Arena temporary_arena = {}; + +gbAllocator permanent_allocator() { + return arena_allocator(&permanent_arena); +} +gbAllocator temporary_allocator() { + return arena_allocator(&temporary_arena); +} + diff --git a/src/entity.cpp b/src/entity.cpp index a9d598735..708b0862c 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -220,7 +220,7 @@ bool entity_has_deferred_procedure(Entity *e) { gb_global u64 global_entity_id = 0; Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) { - gbAllocator a = heap_allocator(); + gbAllocator a = permanent_allocator(); Entity *entity = gb_alloc_item(a, Entity); entity->kind = kind; entity->state = EntityState_Unresolved; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 79f7948a3..f0422e0f8 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -276,6 +276,9 @@ Type *alloc_type_struct_from_field_types(Type **field_types, isize field_count, } Type *alloc_type_tuple_from_field_types(Type **field_types, isize field_count, bool is_packed, bool must_be_tuple) { + if (field_count == 0) { + return nullptr; + } if (!must_be_tuple && field_count == 1) { return field_types[0]; } @@ -297,7 +300,9 @@ Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type Type *params = alloc_type_tuple_from_field_types(param_types, param_count, false, true); isize results_count = 0; if (results != nullptr) { - GB_ASSERT(results->kind == Type_Tuple); + if (results->kind != Type_Tuple) { + results = alloc_type_tuple_from_field_types(&results, 1, false, true); + } results_count = results->Tuple.variables.count; } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 1f20c607d..43f4125ba 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -144,7 +144,7 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { lbValue h = lb_gen_map_header(p, addr.addr, map_type); lbValue key = lb_gen_map_key(p, addr.map.key, map_type->Map.key); - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = h; args[1] = key; @@ -209,7 +209,7 @@ void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index, lbValue le lbValue line = lb_const_int(p->module, t_int, token.pos.line); lbValue column = lb_const_int(p->module, t_int, token.pos.column); - auto args = array_make(heap_allocator(), 5); + auto args = array_make(permanent_allocator(), 5); args[0] = file; args[1] = line; args[2] = column; @@ -233,7 +233,7 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu high = lb_emit_conv(p, high, t_int); if (!lower_value_used) { - auto args = array_make(heap_allocator(), 5); + auto args = array_make(permanent_allocator(), 5); args[0] = file; args[1] = line; args[2] = column; @@ -245,7 +245,7 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu // No need to convert unless used low = lb_emit_conv(p, low, t_int); - auto args = array_make(heap_allocator(), 6); + auto args = array_make(permanent_allocator(), 6); args[0] = file; args[1] = line; args[2] = column; @@ -357,7 +357,7 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { } - auto args = array_make(heap_allocator(), gb_max(arg_count, param_count)); + auto args = array_make(permanent_allocator(), gb_max(arg_count, param_count)); args[0] = ptr; args[1] = index; args[2] = value; @@ -594,7 +594,7 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { lbValue h = lb_gen_map_header(p, addr.addr, map_type); lbValue key = lb_gen_map_key(p, addr.map.key, map_type->Map.key); - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = h; args[1] = key; @@ -773,7 +773,6 @@ void lb_emit_store_union_variant_tag(lbProcedure *p, lbValue parent, Type *varia } void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant, Type *variant_type) { - gbAllocator a = heap_allocator(); lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); lb_emit_store(p, underlying, variant); @@ -783,10 +782,9 @@ void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) { unsigned field_count = LLVMCountStructElementTypes(src); - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); LLVMGetStructElementTypes(src, fields); LLVMStructSetBody(dst, fields, field_count, LLVMIsPackedStruct(src)); - gb_free(heap_allocator(), fields); } LLVMTypeRef lb_alignment_prefix_type_hack(lbModule *m, i64 alignment) { @@ -821,8 +819,6 @@ bool lb_is_elem_const(Ast *elem, Type *elem_type) { } String lb_mangle_name(lbModule *m, Entity *e) { - gbAllocator a = heap_allocator(); - String name = e->token.string; AstPackage *pkg = e->pkg; @@ -848,7 +844,7 @@ String lb_mangle_name(lbModule *m, Entity *e) { max_len += 21; } - char *new_name = gb_alloc_array(a, char, max_len); + 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) @@ -899,7 +895,7 @@ String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p) { if (p != nullptr) { isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(heap_allocator(), char, name_len); + 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); @@ -909,7 +905,7 @@ String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p) { } 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(heap_allocator(), char, name_len); + 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); @@ -1191,7 +1187,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { if (found) { LLVMTypeKind kind = LLVMGetTypeKind(*found); if (kind == LLVMStructTypeKind) { - char const *name = alloc_cstring(heap_allocator(), lb_get_entity_name(m, type->Named.type_name)); + 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; @@ -1208,7 +1204,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Type_Union: case Type_BitField: { - char const *name = alloc_cstring(heap_allocator(), lb_get_entity_name(m, type->Named.type_name)); + 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; @@ -1265,7 +1261,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { { if (type->Struct.is_raw_union) { unsigned field_count = 2; - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + 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); @@ -1282,9 +1278,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { defer (m->internal_type_level -= 1); unsigned field_count = cast(unsigned)(type->Struct.fields.count + offset); - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); GB_ASSERT(fields != nullptr); - defer (gb_free(heap_allocator(), fields)); for_array(i, type->Struct.fields) { Entity *field = type->Struct.fields[i]; @@ -1344,8 +1339,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return lb_type(m, type->Tuple.variables[0]->type); } else { unsigned field_count = cast(unsigned)(type->Tuple.variables.count); - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); - defer (gb_free(heap_allocator(), fields)); + LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); for_array(i, type->Tuple.variables) { Entity *field = type->Tuple.variables[i]; @@ -1444,8 +1438,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } isize param_count = type->Proc.abi_compat_params.count + extra_param_count; - auto param_types = array_make(heap_allocator(), 0, param_count); - defer (array_free(¶m_types)); + auto param_types = array_make(temporary_allocator(), 0, param_count); if (type->Proc.return_by_pointer) { array_add(¶m_types, LLVMPointerType(lb_type(m, type->Proc.abi_compat_result_type), 0)); @@ -1492,8 +1485,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { { GB_ASSERT(type->BitField.fields.count == type->BitField.sizes.count); unsigned field_count = cast(unsigned)type->BitField.fields.count; - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); - defer (gb_free(heap_allocator(), fields)); + LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); for_array(i, type->BitField.sizes) { u32 size = type->BitField.sizes[i]; @@ -2135,7 +2127,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { } - lbProcedure *p = gb_alloc_item(heap_allocator(), lbProcedure); + lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); p->module = m; entity->code_gen_module = m; @@ -2149,7 +2141,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { Type *pt = base_type(entity->type); GB_ASSERT(pt->kind == Type_Proc); - set_procedure_abi_types(heap_allocator(), entity->type); + set_procedure_abi_types(permanent_allocator(), entity->type); p->type = entity->type; p->type_expr = decl->type_expr; @@ -2172,7 +2164,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); } - char *c_link_name = alloc_cstring(heap_allocator(), p->name); + 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); @@ -2209,19 +2201,19 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { LLVMSetVisibility(p->value, LLVMDefaultVisibility); if (build_context.metrics.os == TargetOs_js) { - char const *export_name = alloc_cstring(heap_allocator(), p->name); + char const *export_name = alloc_cstring(permanent_allocator(), p->name); LLVMAddTargetDependentFunctionAttr(p->value, "wasm-export-name", export_name); } } if (p->is_foreign) { if (build_context.metrics.os == TargetOs_js) { - char const *import_name = alloc_cstring(heap_allocator(), p->name); + 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(heap_allocator(), foreign_library->LibraryName.paths[0]); + module_name = alloc_cstring(permanent_allocator(), foreign_library->LibraryName.paths[0]); } } LLVMAddTargetDependentFunctionAttr(p->value, "wasm-import-name", import_name); @@ -2310,7 +2302,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type GB_ASSERT(found == nullptr); } - lbProcedure *p = gb_alloc_item(heap_allocator(), lbProcedure); + lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); p->module = m; p->name = link_name; @@ -2324,7 +2316,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type p->is_export = false; p->is_entry_point = false; - gbAllocator a = heap_allocator(); + gbAllocator a = permanent_allocator(); p->children.allocator = a; p->params.allocator = a; p->defer_stmts.allocator = a; @@ -2333,7 +2325,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type p->context_stack.allocator = a; - char *c_link_name = alloc_cstring(heap_allocator(), p->name); + 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); @@ -2833,7 +2825,7 @@ void lb_add_edge(lbBlock *from, lbBlock *to) { lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append) { - lbBlock *b = gb_alloc_item(heap_allocator(), lbBlock); + lbBlock *b = gb_alloc_item(permanent_allocator(), lbBlock); b->block = LLVMCreateBasicBlockInContext(p->module->ctx, name); b->appended = false; if (append) { @@ -2932,7 +2924,7 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p char const *name = ""; if (e != nullptr) { - // name = alloc_cstring(heap_allocator(), e->token.string); + // name = alloc_cstring(permanent_allocator(), e->token.string); } LLVMTypeRef llvm_type = lb_type(p->module, type); @@ -2980,13 +2972,13 @@ void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) { isize name_len = p->name.len + 1 + pd_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(heap_allocator(), char, name_len); + 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); - set_procedure_abi_types(heap_allocator(), e->type); + set_procedure_abi_types(permanent_allocator(), e->type); e->Procedure.link_name = name; @@ -3123,7 +3115,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) { return; } - set_procedure_abi_types(heap_allocator(), e->type); + set_procedure_abi_types(permanent_allocator(), e->type); e->Procedure.link_name = name; lbProcedure *nested_proc = lb_create_procedure(p->module, e); @@ -3179,7 +3171,7 @@ lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) { lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) { - lbTargetList *tl = gb_alloc_item(heap_allocator(), lbTargetList); + lbTargetList *tl = gb_alloc_item(permanent_allocator(), lbTargetList); tl->prev = p->target_list; tl->break_ = break_; tl->continue_ = continue_; @@ -3400,7 +3392,7 @@ void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type, 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(heap_allocator(), 1); + auto args = array_make(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); @@ -4275,14 +4267,14 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { String mangled_name = {}; { - gbString str = gb_string_make_length(heap_allocator(), p->name.text, p->name.len); + 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(heap_allocator(), mangled_name); + 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))); @@ -4329,8 +4321,8 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { } } } else { // Tuple(s) - auto lvals = array_make(heap_allocator(), 0, vd->names.count); - auto inits = array_make(heap_allocator(), 0, vd->names.count); + auto lvals = array_make(permanent_allocator(), 0, vd->names.count); + auto inits = array_make(permanent_allocator(), 0, vd->names.count); for_array(i, vd->names) { Ast *name = vd->names[i]; @@ -4367,7 +4359,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { case_ast_node(as, AssignStmt, node); if (as->op.kind == Token_Eq) { - auto lvals = array_make(heap_allocator(), 0, as->lhs.count); + auto lvals = array_make(permanent_allocator(), 0, as->lhs.count); for_array(i, as->lhs) { Ast *lhs = as->lhs[i]; @@ -4385,7 +4377,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { lbValue init = lb_build_expr(p, rhs); lb_addr_store(p, lvals[0], init); } else { - auto inits = array_make(heap_allocator(), 0, lvals.count); + auto inits = array_make(permanent_allocator(), 0, lvals.count); for_array(i, as->rhs) { lbValue init = lb_build_expr(p, as->rhs[i]); @@ -4399,7 +4391,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { } } } else { - auto inits = array_make(heap_allocator(), 0, lvals.count); + auto inits = array_make(permanent_allocator(), 0, lvals.count); for_array(i, as->rhs) { lbValue init = lb_build_expr(p, as->rhs[i]); @@ -4491,7 +4483,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { } } else { - auto results = array_make(heap_allocator(), 0, return_count); + auto results = array_make(permanent_allocator(), 0, return_count); if (res_count != 0) { for (isize res_index = 0; res_index < res_count; res_index++) { @@ -4794,9 +4786,8 @@ lbValue lb_emit_min(lbProcedure *p, Type *t, lbValue x, lbValue y) { y = lb_emit_conv(p, y, t); if (is_type_float(t)) { - gbAllocator a = heap_allocator(); i64 sz = 8*type_size_of(t); - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = x; args[1] = y; switch (sz) { @@ -4812,9 +4803,8 @@ lbValue lb_emit_max(lbProcedure *p, Type *t, lbValue x, lbValue y) { y = lb_emit_conv(p, y, t); if (is_type_float(t)) { - gbAllocator a = heap_allocator(); i64 sz = 8*type_size_of(t); - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = x; args[1] = y; switch (sz) { @@ -4850,7 +4840,7 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { isize max_len = 7+8+1; - char *name = gb_alloc_array(heap_allocator(), char, max_len); + char *name = gb_alloc_array(permanent_allocator(), char, max_len); isize len = gb_snprintf(name, max_len, "csbs$%x", m->global_array_index); len -= 1; m->global_array_index++; @@ -4892,7 +4882,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) char *name = nullptr; { isize max_len = 7+8+1; - name = gb_alloc_array(heap_allocator(), char, max_len); + name = gb_alloc_array(permanent_allocator(), char, max_len); isize len = gb_snprintf(name, max_len, "csbs$%x", m->global_array_index); len -= 1; m->global_array_index++; @@ -5103,7 +5093,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } } else { isize max_len = 7+8+1; - char *str = gb_alloc_array(heap_allocator(), char, max_len); + char *str = gb_alloc_array(permanent_allocator(), char, max_len); isize len = gb_snprintf(str, max_len, "csba$%x", m->global_array_index); m->global_array_index++; @@ -5151,7 +5141,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc lbValue single_elem = lb_const_value(m, elem, value, allow_local); - LLVMValueRef *elems = gb_alloc_array(heap_allocator(), LLVMValueRef, count); + LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count); for (i64 i = 0; i < count; i++) { elems[i] = single_elem.value; } @@ -5204,7 +5194,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc isize byte_len = gb_size_of(u64)*len; u8 *old_bytes = cast(u8 *)words; // TODO(bill): Use a different allocator here for a temporary allocation - u8 *new_bytes = cast(u8 *)gb_alloc_align(heap_allocator(), byte_len, gb_align_of(u64)); + u8 *new_bytes = cast(u8 *)gb_alloc_align(permanent_allocator(), byte_len, gb_align_of(u64)); for (i64 i = 0; i < sz; i++) { new_bytes[i] = old_bytes[sz-1-i]; } @@ -5291,8 +5281,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc 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(heap_allocator(), LLVMValueRef, type->Array.count); - defer (gb_free(heap_allocator(), values)); + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->Array.count); isize value_index = 0; for (i64 i = 0; i < type->Array.count; i++) { @@ -5349,8 +5338,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } else { GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, type->Array.count); - defer (gb_free(heap_allocator(), values)); + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->Array.count); for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; @@ -5374,8 +5362,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc 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(heap_allocator(), LLVMValueRef, type->EnumeratedArray.count); - defer (gb_free(heap_allocator(), values)); + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->EnumeratedArray.count); isize value_index = 0; @@ -5436,8 +5423,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } else { GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count); - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, type->EnumeratedArray.count); - defer (gb_free(heap_allocator(), values)); + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->EnumeratedArray.count); for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; @@ -5462,8 +5448,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc GB_ASSERT(elem_type_can_be_constant(elem_type)); isize total_elem_count = type->SimdVector.count; - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, total_elem_count); - defer (gb_free(heap_allocator(), values)); + 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; @@ -5489,11 +5474,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } isize value_count = type->Struct.fields.count + offset; - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, value_count); - bool *visited = gb_alloc_array(heap_allocator(), bool, value_count); - defer (gb_free(heap_allocator(), values)); - defer (gb_free(heap_allocator(), visited)); - + 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) { @@ -5822,7 +5804,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty Type *ft = base_complex_elem_type(type); if (op == Token_Quo) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = lhs; args[1] = rhs; @@ -5896,7 +5878,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty return lb_addr_load(p, res); } else if (op == Token_Mul) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = lhs; args[1] = rhs; @@ -5906,7 +5888,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty default: GB_PANIC("Unknown float type"); break; } } else if (op == Token_Quo) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = lhs; args[1] = rhs; @@ -6132,7 +6114,7 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { lbValue h = lb_gen_map_header(p, addr, rt); lbValue key = lb_gen_map_key(p, left, rt->Map.key); - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = h; args[1] = key; @@ -6378,7 +6360,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { 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(heap_allocator(), 1); + auto args = array_make(permanent_allocator(), 1); args[0] = c; lbValue s = lb_emit_runtime_call(p, "cstring_to_string", args); return lb_emit_conv(p, s, dst); @@ -6395,7 +6377,6 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { // float -> float if (is_type_float(src) && is_type_float(dst)) { - gbAllocator a = heap_allocator(); i64 sz = type_size_of(src); i64 dz = type_size_of(dst); @@ -6837,8 +6818,7 @@ void lb_emit_init_context(lbProcedure *p, lbAddr addr) { GB_ASSERT(addr.ctx.sel.index.count == 0); lbModule *m = p->module; - gbAllocator a = heap_allocator(); - auto args = array_make(a, 1); + auto args = array_make(permanent_allocator(), 1); args[0] = addr.addr; lb_emit_runtime_call(p, "__init_context", args); } @@ -6907,7 +6887,6 @@ lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 al } lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { - gbAllocator a = heap_allocator(); GB_ASSERT(is_type_pointer(s.type)); Type *t = base_type(type_deref(s.type)); Type *result_type = nullptr; @@ -7015,7 +6994,6 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { return lb_emit_load(p, ptr); } - gbAllocator a = heap_allocator(); Type *t = base_type(s.type); Type *result_type = nullptr; @@ -7121,7 +7099,6 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) { GB_ASSERT(sel.index.count > 0); Type *type = type_deref(e.type); - gbAllocator a = heap_allocator(); for_array(i, sel.index) { i32 index = cast(i32)sel.index[i]; @@ -7292,14 +7269,14 @@ Array lb_value_to_array(lbProcedure *p, lbValue value) { GB_ASSERT(t->kind == Type_Tuple); auto *rt = &t->Tuple; if (rt->variables.count > 0) { - array = array_make(heap_allocator(), rt->variables.count); + array = array_make(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(heap_allocator(), 1); + array = array_make(permanent_allocator(), 1); array[0] = value; } return array; @@ -7316,7 +7293,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, arg_count += 1; } - LLVMValueRef *args = gb_alloc_array(heap_allocator(), LLVMValueRef, arg_count); + 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; @@ -7399,7 +7376,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, LLVMBuildUnreachable(p->builder); }); - set_procedure_abi_types(heap_allocator(), pt); + set_procedure_abi_types(permanent_allocator(), pt); bool is_c_vararg = pt->Proc.c_vararg; isize param_count = pt->Proc.param_count; @@ -7412,7 +7389,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, lbValue result = {}; - auto processed_args = array_make(heap_allocator(), 0, args.count); + auto processed_args = array_make(permanent_allocator(), 0, args.count); if (USE_LLVM_ABI) { lbFunctionType **ft_found = nullptr; @@ -7635,7 +7612,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, case DeferredProcedure_in_out: { auto out_args = lb_value_to_array(p, result); - array_init(&result_as_args, heap_allocator(), in_args.count + out_args.count); + 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); } @@ -7744,7 +7721,7 @@ lbValue lb_string_len(lbProcedure *p, lbValue string) { lbValue lb_cstring_len(lbProcedure *p, lbValue value) { GB_ASSERT(is_type_cstring(value.type)); - auto args = array_make(heap_allocator(), 1); + auto args = array_make(permanent_allocator(), 1); args[0] = lb_emit_conv(p, value, t_cstring); return lb_emit_runtime_call(p, "cstring_len", args); } @@ -7782,7 +7759,6 @@ lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da) { } lbValue lb_map_entries(lbProcedure *p, lbValue value) { - gbAllocator a = heap_allocator(); Type *t = base_type(value.type); GB_ASSERT_MSG(t->kind == Type_Map, "%s", type_to_string(t)); init_map_internal_types(t); @@ -7793,7 +7769,6 @@ lbValue lb_map_entries(lbProcedure *p, lbValue value) { } lbValue lb_map_entries_ptr(lbProcedure *p, lbValue value) { - gbAllocator a = heap_allocator(); 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); @@ -7917,7 +7892,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } GB_ASSERT(is_type_typeid(tav.type)); - auto args = array_make(heap_allocator(), 1); + auto args = array_make(permanent_allocator(), 1); args[0] = lb_build_expr(p, arg); return lb_emit_runtime_call(p, "__type_info_of", args); } @@ -7994,7 +7969,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } unsigned mask_len = cast(unsigned)index_count; - LLVMValueRef *mask_elems = gb_alloc_array(heap_allocator(), LLVMValueRef, 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)); @@ -8224,7 +8199,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_abs: { - gbAllocator a = heap_allocator(); lbValue x = lb_build_expr(p, ce->args[0]); Type *t = x.type; if (is_type_unsigned(t)) { @@ -8232,7 +8206,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } if (is_type_quaternion(t)) { i64 sz = 8*type_size_of(t); - auto args = array_make(heap_allocator(), 1); + auto args = array_make(permanent_allocator(), 1); args[0] = x; switch (sz) { case 128: return lb_emit_runtime_call(p, "abs_quaternion128", args); @@ -8241,7 +8215,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, GB_PANIC("Unknown complex type"); } else if (is_type_complex(t)) { i64 sz = 8*type_size_of(t); - auto args = array_make(heap_allocator(), 1); + auto args = array_make(permanent_allocator(), 1); args[0] = x; switch (sz) { case 64: return lb_emit_runtime_call(p, "abs_complex64", args); @@ -8250,7 +8224,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, GB_PANIC("Unknown complex type"); } else if (is_type_float(t)) { i64 sz = 8*type_size_of(t); - auto args = array_make(heap_allocator(), 1); + auto args = array_make(permanent_allocator(), 1); args[0] = x; switch (sz) { case 32: return lb_emit_runtime_call(p, "abs_f32", args); @@ -8506,7 +8480,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, GB_ASSERT(tv.type->kind == Type_Tuple); Type *fix_typed = alloc_type_tuple(); - array_init(&fix_typed->Tuple.variables, heap_allocator(), 2); + 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); @@ -8621,10 +8595,10 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { Type *proc_type_ = base_type(value.type); GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *pt = &proc_type_->Proc; - set_procedure_abi_types(heap_allocator(), proc_type_); + set_procedure_abi_types(permanent_allocator(), proc_type_); if (is_call_expr_field_value(ce)) { - auto args = array_make(heap_allocator(), pt->param_count); + auto args = array_make(permanent_allocator(), pt->param_count); for_array(arg_index, ce->args) { Ast *arg = ce->args[arg_index]; @@ -8693,7 +8667,7 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { param_count = pt->params->Tuple.variables.count; } - auto args = array_make(heap_allocator(), cast(isize)gb_max(param_count, arg_count)); + auto args = array_make(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; @@ -8801,7 +8775,6 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { if (variadic && !vari_expand && !is_c_vararg) { // variadic call argument generation - gbAllocator allocator = heap_allocator(); Type *slice_type = param_tuple->variables[variadic_index]->type; Type *elem_type = base_type(slice_type)->Slice.elem; lbAddr slice = lb_add_local_generated(p, slice_type, true); @@ -9077,7 +9050,7 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { lbValue invalid_typeid = lb_const_value(p->module, t_typeid, exact_value_i64(0)); return lb_emit_comp(p, op_kind, x, invalid_typeid); } else if (is_type_bit_field(t)) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(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)); @@ -9106,7 +9079,7 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { } } } else if (is_type_struct(t) && type_has_nil(t)) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(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)); @@ -9141,8 +9114,6 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } else if (lb_is_const(right) || lb_is_const_nil(right)) { right = lb_emit_conv(p, right, left.type); } else { - gbAllocator a = heap_allocator(); - Type *lt = left.type; Type *rt = right.type; @@ -9222,7 +9193,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } 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(heap_allocator(), 3); + auto args = array_make(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)); @@ -9265,7 +9236,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } GB_ASSERT(runtime_procedure != nullptr); - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = left; args[1] = right; return lb_emit_runtime_call(p, runtime_procedure, args); @@ -9290,7 +9261,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } GB_ASSERT(runtime_procedure != nullptr); - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = left; args[1] = right; return lb_emit_runtime_call(p, runtime_procedure, args); @@ -9315,7 +9286,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } GB_ASSERT(runtime_procedure != nullptr); - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = left; args[1] = right; return lb_emit_runtime_call(p, runtime_procedure, args); @@ -9464,14 +9435,14 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A // NOTE(bill): Generate a new name // parent$count isize name_len = prefix_name.len + 1 + 8 + 1; - char *name_text = gb_alloc_array(heap_allocator(), char, name_len); + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); i32 name_id = cast(i32)m->anonymous_proc_lits.entries.count; name_len = gb_snprintf(name_text, name_len, "%.*s$anon-%d", LIT(prefix_name), name_id); String name = make_string((u8 *)name_text, name_len-1); Type *type = type_of_expr(expr); - set_procedure_abi_types(heap_allocator(), type); + set_procedure_abi_types(permanent_allocator(), type); Token token = {}; @@ -9567,7 +9538,7 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p 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(heap_allocator(), 6); + auto args = array_make(permanent_allocator(), 6); args[0] = ok; args[1] = lb_const_string(m, pos.file); @@ -9628,7 +9599,7 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos // NOTE(bill): Panic on invalid conversion lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make(heap_allocator(), 6); + auto args = array_make(permanent_allocator(), 6); args[0] = ok; args[1] = lb_const_string(m, pos.file); @@ -9912,7 +9883,6 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { return addr.addr; } else if (ue_expr->kind == Ast_TypeAssertion) { - gbAllocator a = heap_allocator(); GB_ASSERT(is_type_pointer(tv.type)); ast_node(ta, TypeAssertion, ue_expr); @@ -9934,7 +9904,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { lbValue 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(heap_allocator(), 6); + auto args = array_make(permanent_allocator(), 6); args[0] = ok; args[1] = lb_find_or_add_entity_string(p->module, pos.file); @@ -9959,7 +9929,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); - auto args = array_make(heap_allocator(), 6); + auto args = array_make(permanent_allocator(), 6); args[0] = ok; args[1] = lb_find_or_add_entity_string(p->module, pos.file); @@ -10110,7 +10080,6 @@ lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) { 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)); - gbAllocator a = heap_allocator(); lbAddr h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later map_type = base_type(map_type); GB_ASSERT(map_type->kind == Type_Map); @@ -10154,7 +10123,7 @@ lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { u64 hs = fnv64a(v.text, v.len); hashed_str = lb_const_int(p->module, t_u64, hs); } else { - auto args = array_make(heap_allocator(), 1); + auto args = array_make(permanent_allocator(), 1); args[0] = str; hashed_str = lb_emit_runtime_call(p, "default_hash_string", args); } @@ -10167,7 +10136,7 @@ lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { i64 sz = type_size_of(t); GB_ASSERT(sz <= 8); if (sz != 0) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = lb_address_from_load_or_generate_local(p, key); args[1] = lb_const_int(p->module, t_int, sz); lbValue hash = lb_emit_runtime_call(p, "default_hash_ptr", args); @@ -10197,7 +10166,7 @@ void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_ lbAddr value_addr = lb_add_local_generated(p, v.type, false); lb_addr_store(p, value_addr, v); - auto args = array_make(heap_allocator(), 4); + auto args = array_make(permanent_allocator(), 4); args[0] = h; args[1] = key; args[2] = lb_emit_conv(p, value_addr.addr, t_rawptr); @@ -10356,7 +10325,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_end; case_ast_node(ta, TypeAssertion, expr); - gbAllocator a = heap_allocator(); TokenPos pos = ast_token(expr).pos; lbValue e = lb_build_expr(p, ta->expr); Type *t = type_deref(e.type); @@ -10393,7 +10361,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_ast_node(ie, IndexExpr, expr); Type *t = base_type(type_of_expr(ie->expr)); - gbAllocator a = heap_allocator(); bool deref = is_type_pointer(t); t = base_type(type_deref(t)); @@ -10593,7 +10560,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_end; case_ast_node(se, SliceExpr, expr); - gbAllocator a = heap_allocator(); lbValue low = lb_const_int(p->module, t_int, 0); lbValue high = {}; @@ -10892,9 +10858,8 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - gbAllocator a = heap_allocator(); { - auto args = array_make(a, 3); + auto args = array_make(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); @@ -10915,8 +10880,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { 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(heap_allocator(), 0, cl->elems.count); - defer (array_free(&temp_data)); + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); // NOTE(bill): Separate value, gep, store into their own chunks for_array(i, cl->elems) { @@ -11015,8 +10979,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { 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(heap_allocator(), 0, cl->elems.count); - defer (array_free(&temp_data)); + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); // NOTE(bill): Separate value, gep, store into their own chunks for_array(i, cl->elems) { @@ -11124,8 +11087,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { lbValue data = lb_slice_elem(p, slice); - auto temp_data = array_make(heap_allocator(), 0, cl->elems.count); - defer (array_free(&temp_data)); + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); for_array(i, cl->elems) { Ast *elem = cl->elems[i]; @@ -11218,14 +11180,13 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { break; } Type *et = bt->DynamicArray.elem; - gbAllocator a = heap_allocator(); 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(a, 5); + auto args = array_make(permanent_allocator(), 5); args[0] = lb_emit_conv(p, lb_addr_get_ptr(p, v), t_rawptr); args[1] = size; args[2] = align; @@ -11279,7 +11240,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { } { - auto args = array_make(a, 6); + auto args = array_make(permanent_allocator(), 6); args[0] = lb_emit_conv(p, v.addr, t_rawptr); args[1] = size; args[2] = align; @@ -11491,7 +11452,7 @@ lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) { type = default_type(type); isize max_len = 7+8+1; - u8 *str = cast(u8 *)gb_alloc_array(heap_allocator(), u8, max_len); + u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len); isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", m->global_generated_index); m->global_generated_index++; String name = make_string(str, len-1); @@ -11571,12 +11532,11 @@ lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool } lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id) { - gbAllocator a = heap_allocator(); Token token = {Token_Ident}; isize name_len = prefix.len + 1 + 20; auto suffix_id = cast(unsigned long long)id; - char *text = gb_alloc_array(a, char, name_len+1); + 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; @@ -11598,7 +11558,6 @@ lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data lbModule *m = p->module; LLVMContextRef ctx = m->ctx; - gbAllocator a = heap_allocator(); CheckerInfo *info = m->info; { @@ -11976,10 +11935,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da str_lit("$enum_values"), cast(i64)entry_index); - LLVMValueRef *name_values = gb_alloc_array(heap_allocator(), LLVMValueRef, fields.count); - LLVMValueRef *value_values = gb_alloc_array(heap_allocator(), LLVMValueRef, fields.count); - defer (gb_free(heap_allocator(), name_values)); - defer (gb_free(heap_allocator(), value_values)); + 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)); @@ -12328,10 +12285,6 @@ void lb_generate_code(lbGenerator *gen) { LLVMModuleRef mod = gen->module.mod; CheckerInfo *info = gen->info; - Arena temp_arena = {}; - arena_init(&temp_arena, heap_allocator()); - gbAllocator temp_allocator = arena_allocator(&temp_arena); - auto *min_dep_set = &info->minimum_dependency_set; @@ -12344,8 +12297,8 @@ void lb_generate_code(lbGenerator *gen) { LLVMInitializeNativeTarget(); - char const *target_triple = alloc_cstring(heap_allocator(), build_context.metrics.target_triplet); - char const *target_data_layout = alloc_cstring(heap_allocator(), build_context.metrics.target_data_layout); + char const *target_triple = alloc_cstring(permanent_allocator(), build_context.metrics.target_triplet); + char const *target_data_layout = alloc_cstring(permanent_allocator(), build_context.metrics.target_data_layout); LLVMSetTarget(mod, target_triple); LLVMTargetRef target = {}; @@ -12367,7 +12320,7 @@ void lb_generate_code(lbGenerator *gen) { if (build_context.microarch == "native") { llvm_cpu = host_cpu_name; } else { - llvm_cpu = alloc_cstring(heap_allocator(), build_context.microarch); + llvm_cpu = alloc_cstring(permanent_allocator(), build_context.microarch); } if (gb_strcmp(llvm_cpu, host_cpu_name) == 0) { llvm_features = LLVMGetHostCPUFeatures(); @@ -12538,7 +12491,7 @@ void lb_generate_code(lbGenerator *gen) { lbValue init; DeclInfo *decl; }; - auto global_variables = array_make(heap_allocator(), 0, global_variable_max_count); + auto global_variables = array_make(permanent_allocator(), 0, global_variable_max_count); for_array(i, info->variable_init_order) { DeclInfo *d = info->variable_init_order[i]; @@ -12565,7 +12518,7 @@ void lb_generate_code(lbGenerator *gen) { lbValue g = {}; - g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(heap_allocator(), name)); + g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); g.type = alloc_type_pointer(e->type); if (e->Variable.thread_local_model != "") { LLVMSetThreadLocal(g.value, true); @@ -12619,9 +12572,6 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Global Procedures and Types"); for_array(i, info->entities) { - // arena_free_all(&temp_arena); - // gbAllocator a = temp_allocator; - Entity *e = info->entities[i]; String name = e->token.string; DeclInfo *decl = e->decl_info; @@ -12906,12 +12856,12 @@ void lb_generate_code(lbGenerator *gen) { if (build_context.metrics.os == TargetOs_windows && build_context.metrics.arch == TargetArch_386) { name = str_lit("mainCRTStartup"); } else { - array_init(¶ms->Tuple.variables, heap_allocator(), 2); + array_init(¶ms->Tuple.variables, permanent_allocator(), 2); params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true); params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), alloc_type_pointer(t_cstring), false, true); } - array_init(&results->Tuple.variables, heap_allocator(), 1); + array_init(&results->Tuple.variables, permanent_allocator(), 1); results->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("_"), t_i32, false, true); Type *proc_type = alloc_type_proc(nullptr, @@ -12944,8 +12894,7 @@ void lb_generate_code(lbGenerator *gen) { } - String filepath_ll = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".ll")); - defer (gb_free(heap_allocator(), filepath_ll.text)); + String filepath_ll = concatenate_strings(temporary_allocator(), gen->output_base, STR_LIT(".ll")); TIME_SECTION("LLVM Procedure Generation"); for_array(i, m->procedures_to_generate) { @@ -13032,20 +12981,20 @@ void lb_generate_code(lbGenerator *gen) { LLVMCodeGenFileType code_gen_file_type = LLVMObjectFile; if (build_context.build_mode == BuildMode_Assembly) { - filepath_obj = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".S")); + filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".S")); code_gen_file_type = LLVMAssemblyFile; } else { switch (build_context.metrics.os) { case TargetOs_windows: - filepath_obj = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".obj")); + filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".obj")); break; case TargetOs_darwin: case TargetOs_linux: case TargetOs_essence: - filepath_obj = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".o")); + filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".o")); break; case TargetOs_js: - filepath_obj = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".wasm-obj")); + filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".wasm-obj")); break; } } diff --git a/src/main.cpp b/src/main.cpp index 3717a4147..d0d2e2bbb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1643,12 +1643,15 @@ int main(int arg_count, char const **arg_ptr) { timings_init(timings, str_lit("Total Time"), 128); defer (timings_destroy(timings)); + arena_init(&permanent_arena, heap_allocator()); + arena_init(&temporary_arena, heap_allocator()); + arena_init(&global_ast_arena, heap_allocator()); + init_string_buffer_memory(); init_string_interner(); init_global_error_collector(); init_keyword_hash_table(); global_big_int_init(); - arena_init(&global_ast_arena, heap_allocator()); array_init(&library_collections, heap_allocator()); // NOTE(bill): 'core' cannot be (re)defined by the user @@ -1795,6 +1798,8 @@ int main(int arg_count, char const **arg_ptr) { return 1; } + arena_free_all(&temporary_arena); + if (build_context.generate_docs) { // generate_documentation(&parser); return 0; @@ -1812,6 +1817,7 @@ int main(int arg_count, char const **arg_ptr) { check_parsed_files(&checker); } + arena_free_all(&temporary_arena); if (build_context.no_output_files) { if (build_context.query_data_set_settings.ok) { @@ -1842,6 +1848,8 @@ int main(int arg_count, char const **arg_ptr) { } lb_generate_code(&gen); + arena_free_all(&temporary_arena); + switch (build_context.build_mode) { case BuildMode_Executable: case BuildMode_DynamicLibrary: @@ -1919,12 +1927,18 @@ int main(int arg_count, char const **arg_ptr) { timings_start_section(timings, str_lit("llvm ir gen")); ir_gen_tree(&ir_gen); + arena_free_all(&temporary_arena); + timings_start_section(timings, str_lit("llvm ir opt tree")); ir_opt_tree(&ir_gen); + arena_free_all(&temporary_arena); + timings_start_section(timings, str_lit("llvm ir print")); print_llvm_ir(&ir_gen); + arena_free_all(&temporary_arena); + String output_name = ir_gen.output_name; String output_base = ir_gen.output_base; diff --git a/src/parser.cpp b/src/parser.cpp index 794ff231d..5e04aea17 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -108,6 +108,30 @@ Token ast_token(Ast *node) { return empty_token; } + +gb_global gbAtomic64 total_allocated_node_memory = {0}; +gb_global gbAtomic64 total_subtype_node_memory_test = {0}; + +isize ast_node_size(AstKind kind) { + return align_formula_isize(gb_size_of(AstCommonStuff) + ast_variant_sizes[kind], gb_align_of(void *)); + +} +// NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++ +Ast *alloc_ast_node(AstFile *f, AstKind kind) { + gbAllocator a = ast_allocator(f); + + isize size = ast_node_size(kind); + + gb_atomic64_fetch_add(&total_allocated_node_memory, cast(i64)(gb_size_of(Ast))); + gb_atomic64_fetch_add(&total_subtype_node_memory_test, cast(i64)(gb_size_of(AstCommonStuff) + ast_variant_sizes[kind])); + + // Ast *node = gb_alloc_item(a, Ast); + Ast *node = cast(Ast *)gb_alloc(a, size); + node->kind = kind; + node->file = f; + return node; +} + Ast *clone_ast(Ast *node); Array clone_ast_array(Array array) { Array result = {}; @@ -125,7 +149,7 @@ Ast *clone_ast(Ast *node) { return nullptr; } Ast *n = alloc_ast_node(node->file, node->kind); - gb_memmove(n, node, gb_size_of(Ast)); + gb_memmove(n, node, ast_node_size(node->kind)); switch (n->kind) { default: GB_PANIC("Unhandled Ast %.*s", LIT(ast_strings[n->kind])); break; @@ -463,23 +487,6 @@ bool ast_node_expect(Ast *node, AstKind kind) { return true; } - -gb_global gbAtomic64 total_allocated_node_memory = {0}; -gb_global gbAtomic64 total_subtype_node_memory_test = {0}; - -// NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++ -Ast *alloc_ast_node(AstFile *f, AstKind kind) { - gbAllocator a = ast_allocator(f); - - gb_atomic64_fetch_add(&total_allocated_node_memory, cast(i64)(gb_size_of(Ast))); - gb_atomic64_fetch_add(&total_subtype_node_memory_test, cast(i64)(gb_size_of(AstCommonStuff) + ast_variant_sizes[kind])); - - Ast *node = gb_alloc_item(a, Ast); - node->kind = kind; - node->file = f; - return node; -} - Ast *ast_bad_expr(AstFile *f, Token begin, Token end) { Ast *result = alloc_ast_node(f, Ast_BadExpr); result->BadExpr.begin = begin; diff --git a/src/parser.hpp b/src/parser.hpp index 8e210876f..0804652a3 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -655,6 +655,7 @@ struct Ast { Scope * scope; TypeAndValue tav; + // IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant union { #define AST_KIND(_kind_name_, name, ...) GB_JOIN2(Ast, _kind_name_) _kind_name_; AST_KINDS diff --git a/src/types.cpp b/src/types.cpp index 1a55c9b05..17dcedf45 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -771,7 +771,8 @@ void set_base_type(Type *t, Type *base) { Type *alloc_type(TypeKind kind) { - gbAllocator a = heap_allocator(); + // gbAllocator a = heap_allocator(); + gbAllocator a = permanent_allocator(); Type *t = gb_alloc_item(a, Type); zero_item(t); t->kind = kind; @@ -2340,7 +2341,7 @@ Selection lookup_field_from_index(Type *type, i64 index) { GB_ASSERT(is_type_struct(type) || is_type_union(type) || is_type_tuple(type)); type = base_type(type); - gbAllocator a = heap_allocator(); + gbAllocator a = permanent_allocator(); isize max_count = 0; switch (type->kind) { case Type_Struct: max_count = type->Struct.fields.count; break; @@ -2397,7 +2398,6 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty return empty_selection; } - gbAllocator a = heap_allocator(); Type *type = type_deref(type_); bool is_ptr = type != type_; sel.indirect = sel.indirect || is_ptr; @@ -2986,7 +2986,7 @@ i64 type_align_of_internal(Type *t, TypePath *path) { } Array type_set_offsets_of(Array const &fields, bool is_packed, bool is_raw_union) { - gbAllocator a = heap_allocator(); + gbAllocator a = permanent_allocator(); auto offsets = array_make(a, fields.count); i64 curr_offset = 0; if (is_raw_union) { -- cgit v1.2.3 From db0bcbc4f47afbb69bb172401ead7f484eed6b6c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Nov 2020 21:19:08 +0000 Subject: Fix calling convention for new LLVM ABI, and change`PtrSet` index to be `u32` rather than `isize` --- src/checker.cpp | 9 +++----- src/llvm_abi.cpp | 24 ++++++++++----------- src/llvm_backend.cpp | 27 +++++++++++++---------- src/ptr_set.cpp | 61 +++++++++++++++++++++++++++------------------------- src/types.cpp | 9 ++++++++ 5 files changed, 71 insertions(+), 59 deletions(-) (limited to 'src/types.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index 76d8cceb3..de1d8091d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1679,8 +1679,6 @@ void add_dependency_to_set(Checker *c, Entity *entity) { CheckerInfo *info = &c->info; auto *set = &info->minimum_dependency_set; - String name = entity->token.string; - if (entity->type != nullptr && is_type_polymorphic(entity->type)) { @@ -1714,16 +1712,15 @@ void add_dependency_to_set(Checker *c, Entity *entity) { if (fl != nullptr) { GB_ASSERT_MSG(fl->kind == Entity_LibraryName && (fl->flags&EntityFlag_Used), - "%.*s", LIT(name)); + "%.*s", LIT(entity->token.string)); add_dependency_to_set(c, fl); } - } - if (e->kind == Entity_Variable && e->Variable.is_foreign) { + } else if (e->kind == Entity_Variable && e->Variable.is_foreign) { Entity *fl = e->Variable.foreign_library; if (fl != nullptr) { GB_ASSERT_MSG(fl->kind == Entity_LibraryName && (fl->flags&EntityFlag_Used), - "%.*s", LIT(name)); + "%.*s", LIT(entity->token.string)); add_dependency_to_set(c, fl); } } diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index f0422e0f8..9722bf302 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -103,6 +103,11 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa offset += 1; } + LLVMContextRef c = ft->ctx; + LLVMAttributeRef noalias_attr = lb_create_enum_attribute(c, "noalias", true); + LLVMAttributeRef nonnull_attr = lb_create_enum_attribute(c, "nonnull", true); + LLVMAttributeRef nocapture_attr = lb_create_enum_attribute(c, "nocapture", true); + unsigned arg_index = offset; for (unsigned i = 0; i < arg_count; i++) { lbArgType *arg = &ft->args[i]; @@ -129,10 +134,9 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa LLVMSetFunctionCallConv(fn, cc_kind); if (calling_convention == ProcCC_Odin) { unsigned context_index = offset+arg_count; - LLVMContextRef c = ft->ctx; - LLVMAddAttributeAtIndex(fn, context_index, lb_create_enum_attribute(c, "noalias", true)); - LLVMAddAttributeAtIndex(fn, context_index, lb_create_enum_attribute(c, "nonnull", true)); - LLVMAddAttributeAtIndex(fn, context_index, lb_create_enum_attribute(c, "nocapture", true)); + LLVMAddAttributeAtIndex(fn, context_index, noalias_attr); + LLVMAddAttributeAtIndex(fn, context_index, nonnull_attr); + LLVMAddAttributeAtIndex(fn, context_index, nocapture_attr); } } @@ -201,9 +205,6 @@ i64 lb_sizeof(LLVMTypeRef type) { } GB_PANIC("Unhandled type for lb_sizeof -> %s", LLVMPrintTypeToString(type)); - // LLVMValueRef v = LLVMSizeOf(type); - // GB_ASSERT(LLVMIsConstant(v)); - // return cast(i64)LLVMConstIntGetSExtValue(v); return 0; } @@ -400,9 +401,6 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) { } GB_PANIC("Unhandled type for lb_abi_to_odin_type -> %s", LLVMPrintTypeToString(type)); - // LLVMValueRef v = LLVMSizeOf(type); - // GB_ASSERT(LLVMIsConstant(v)); - // return cast(i64)LLVMConstIntGetSExtValue(v); return 0; } @@ -441,7 +439,7 @@ namespace lbAbi386 { LLVMAttributeRef attr = nullptr; LLVMTypeRef i1 = LLVMInt1TypeInContext(c); if (type == i1) { - // attr = lb_create_enum_attribute(c, "zext", true); + attr = lb_create_enum_attribute(c, "zeroext", true); // return lb_arg_type_direct(type, i1, nullptr, attr); } return lb_arg_type_direct(type, nullptr, nullptr, attr); @@ -625,7 +623,7 @@ namespace lbAbiAmd64SysV { if (is_register(type)) { LLVMAttributeRef attribute = nullptr; if (type == LLVMInt1TypeInContext(c)) { - attribute = lb_create_enum_attribute(c, "zext", true); + attribute = lb_create_enum_attribute(c, "zeroext", true); } return lb_arg_type_direct(type, nullptr, nullptr, attribute); } @@ -648,7 +646,7 @@ namespace lbAbiAmd64SysV { LLVMAttributeRef attr = nullptr; LLVMTypeRef i1 = LLVMInt1TypeInContext(c); if (type == i1) { - attr = lb_create_enum_attribute(c, "zext", true); + attr = lb_create_enum_attribute(c, "zeroext", true); } return lb_arg_type_direct(type, nullptr, nullptr, attr); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 9eb641716..6542da69b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -7440,8 +7440,14 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, } } else if (arg->kind == lbArg_Indirect) { - // lbValue ptr = lb_copy_value_to_ptr(p, x, original_type, 16); - lbValue ptr = lb_address_from_load_or_generate_local(p, x); + lbValue ptr = {}; + 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); } @@ -7454,18 +7460,17 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, Type *rt = reduce_tuple_to_single_type(results); if (return_by_pointer) { - lbValue return_ptr = {}; - // if (use_return_ptr_hint && p->return_ptr_hint_value.value != nullptr) { - // if (are_types_identical(type_deref(p->return_ptr_hint_value.type), rt)) { - // return_ptr = p->return_ptr_hint_value; - // p->return_ptr_hint_used = true; - // } - // } - // if (return_ptr.value == nullptr) { + if (use_return_ptr_hint && p->return_ptr_hint_value.value != nullptr) { + if (are_types_identical(type_deref(p->return_ptr_hint_value.type), rt)) { + return_ptr = p->return_ptr_hint_value; + p->return_ptr_hint_used = true; + } + } + 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); diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index e343628af..890a0df1d 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -1,19 +1,23 @@ +typedef u32 PtrSetIndex; + struct PtrSetFindResult { - isize hash_index; - isize entry_prev; - isize entry_index; + PtrSetIndex hash_index; + PtrSetIndex entry_prev; + PtrSetIndex entry_index; }; +enum : PtrSetIndex { PTR_SET_SENTINEL = ~(PtrSetIndex)0 }; + template struct PtrSetEntry { - T ptr; - isize next; + T ptr; + PtrSetIndex next; }; template struct PtrSet { - Array hashes; + Array hashes; Array> entries; }; @@ -29,10 +33,12 @@ template void ptr_set_rehash (PtrSet *s, isize new_count); template void ptr_set_init(PtrSet *s, gbAllocator a, isize capacity) { + capacity = next_pow2(gb_max(16, capacity)); + array_init(&s->hashes, a, capacity); array_init(&s->entries, a, 0, capacity); for (isize i = 0; i < capacity; i++) { - s->hashes.data[i] = -1; + s->hashes.data[i] = PTR_SET_SENTINEL; } } @@ -43,24 +49,24 @@ void ptr_set_destroy(PtrSet *s) { } template -gb_internal isize ptr_set__add_entry(PtrSet *s, T ptr) { +gb_internal PtrSetIndex ptr_set__add_entry(PtrSet *s, T ptr) { PtrSetEntry e = {}; e.ptr = ptr; - e.next = -1; + e.next = PTR_SET_SENTINEL; array_add(&s->entries, e); - return s->entries.count-1; + return cast(PtrSetIndex)(s->entries.count-1); } template gb_internal PtrSetFindResult ptr_set__find(PtrSet *s, T ptr) { - PtrSetFindResult fr = {-1, -1, -1}; - if (s->hashes.count > 0) { + PtrSetFindResult fr = {PTR_SET_SENTINEL, PTR_SET_SENTINEL, PTR_SET_SENTINEL}; + if (s->hashes.count != 0) { u64 hash = 0xcbf29ce484222325ull ^ cast(u64)cast(uintptr)ptr; u64 n = cast(u64)s->hashes.count; - fr.hash_index = cast(isize)(hash % n); + fr.hash_index = cast(PtrSetIndex)(hash & (n-1)); fr.entry_index = s->hashes[fr.hash_index]; - while (fr.entry_index >= 0) { + while (fr.entry_index != PTR_SET_SENTINEL) { if (s->entries[fr.entry_index].ptr == ptr) { return fr; } @@ -72,28 +78,25 @@ gb_internal PtrSetFindResult ptr_set__find(PtrSet *s, T ptr) { } template -gb_internal b32 ptr_set__full(PtrSet *s) { +gb_internal bool ptr_set__full(PtrSet *s) { return 0.75f * s->hashes.count <= s->entries.count; } -#define PTR_ARRAY_GROW_FORMULA(x) (4*(x) + 7) -GB_STATIC_ASSERT(PTR_ARRAY_GROW_FORMULA(0) > 0); - template gb_inline void ptr_set_grow(PtrSet *s) { - isize new_count = PTR_ARRAY_GROW_FORMULA(s->entries.count); + isize new_count = s->hashes.count*2; ptr_set_rehash(s, new_count); } template void ptr_set_rehash(PtrSet *s, isize new_count) { - isize i, j; + PtrSetIndex i, j; PtrSet ns = {}; ptr_set_init(&ns, s->hashes.allocator); array_resize(&ns.hashes, new_count); array_reserve(&ns.entries, s->entries.count); for (i = 0; i < new_count; i++) { - ns.hashes[i] = -1; + ns.hashes[i] = PTR_SET_SENTINEL; } for (i = 0; i < s->entries.count; i++) { PtrSetEntry *e = &s->entries[i]; @@ -103,7 +106,7 @@ void ptr_set_rehash(PtrSet *s, isize new_count) { } fr = ptr_set__find(&ns, e->ptr); j = ptr_set__add_entry(&ns, e->ptr); - if (fr.entry_prev < 0) { + if (fr.entry_prev == PTR_SET_SENTINEL) { ns.hashes[fr.hash_index] = j; } else { ns.entries[fr.entry_prev].next = j; @@ -120,23 +123,23 @@ void ptr_set_rehash(PtrSet *s, isize new_count) { template gb_inline bool ptr_set_exists(PtrSet *s, T ptr) { isize index = ptr_set__find(s, ptr).entry_index; - return index >= 0; + return index != PTR_SET_SENTINEL; } // Returns true if it already exists template T ptr_set_add(PtrSet *s, T ptr) { - isize index; + PtrSetIndex index; PtrSetFindResult fr; if (s->hashes.count == 0) { ptr_set_grow(s); } fr = ptr_set__find(s, ptr); - if (fr.entry_index >= 0) { + if (fr.entry_index != PTR_SET_SENTINEL) { index = fr.entry_index; } else { index = ptr_set__add_entry(s, ptr); - if (fr.entry_prev >= 0) { + if (fr.entry_prev != PTR_SET_SENTINEL) { s->entries[fr.entry_prev].next = index; } else { s->hashes[fr.hash_index] = index; @@ -152,7 +155,7 @@ T ptr_set_add(PtrSet *s, T ptr) { template void ptr_set__erase(PtrSet *s, PtrSetFindResult fr) { PtrSetFindResult last; - if (fr.entry_prev < 0) { + if (fr.entry_prev == PTR_SET_SENTINEL) { s->hashes[fr.hash_index] = s->entries[fr.entry_index].next; } else { s->entries[fr.entry_prev].next = s->entries[fr.entry_index].next; @@ -163,7 +166,7 @@ void ptr_set__erase(PtrSet *s, PtrSetFindResult fr) { } s->entries[fr.entry_index] = s->entries[s->entries.count-1]; last = ptr_set__find(s, s->entries[fr.entry_index].ptr); - if (last.entry_prev >= 0) { + if (last.entry_prev != PTR_SET_SENTINEL) { s->entries[last.entry_prev].next = fr.entry_index; } else { s->hashes[last.hash_index] = fr.entry_index; @@ -173,7 +176,7 @@ void ptr_set__erase(PtrSet *s, PtrSetFindResult fr) { template void ptr_set_remove(PtrSet *s, T ptr) { PtrSetFindResult fr = ptr_set__find(s, ptr); - if (fr.entry_index >= 0) { + if (fr.entry_index != PTR_SET_SENTINEL) { ptr_set__erase(s, fr); } } diff --git a/src/types.cpp b/src/types.cpp index 17dcedf45..1147beb33 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -897,6 +897,15 @@ bool is_calling_convention_none(ProcCallingConvention calling_convention) { return false; } +bool is_calling_convention_odin(ProcCallingConvention calling_convention) { + switch (calling_convention) { + case ProcCC_Odin: + case ProcCC_Contextless: + return true; + } + return false; +} + Type *alloc_type_tuple() { Type *t = alloc_type(Type_Tuple); return t; -- cgit v1.2.3 From 6416a6f39cce4c65c80e29bb4ff4b93a3e463947 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 20 Nov 2020 16:01:59 +0000 Subject: Allow string literals for `[N]byte` --- src/check_expr.cpp | 6 ++++++ src/ir.cpp | 4 +++- src/ir_print.cpp | 10 +++++++--- src/llvm_backend.cpp | 10 +++++++++- src/parser.hpp | 4 ++-- src/types.cpp | 7 +++++++ 6 files changed, 34 insertions(+), 7 deletions(-) (limited to 'src/types.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index aa3d67dae..f258253f5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2955,6 +2955,12 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { if (check_is_assignable_to(c, operand, elem)) { operand->mode = Addressing_Value; } else { + if (operand->value.kind == ExactValue_String && is_type_u8_array(t)) { + String s = operand->value.value_string; + if (s.len == t->Array.count) { + break; + } + } operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); return; diff --git a/src/ir.cpp b/src/ir.cpp index 819442030..e8378bb97 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7801,7 +7801,9 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): Edge case - if (tv.value.kind != ExactValue_Compound && + if (is_type_u8_array(tv.type) && tv.value.kind == ExactValue_String) { + return ir_add_module_constant(proc->module, tv.type, tv.value); + } else if (tv.value.kind != ExactValue_Compound && is_type_array(tv.type)) { Type *elem = core_array_type(tv.type); ExactValue value = convert_exact_value_for_type(tv.value, elem); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 0605058ee..3ca9954ef 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -745,7 +745,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_write_byte(f, ']'); return; - } else if (is_type_array(type) && + } else if (is_type_array(type) && value.kind != ExactValue_Invalid && value.kind != ExactValue_String && value.kind != ExactValue_Compound) { @@ -796,7 +796,11 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * GB_ASSERT(is_type_array(type)); ir_write_str_lit(f, "c\""); ir_print_escape_string(f, str, false, false); - ir_write_str_lit(f, "\\00\""); + if (type->Array.count == str.len) { + ir_write_str_lit(f, "\""); + } else { + ir_write_str_lit(f, "\\00\""); + } } else if (is_type_cstring(t)) { // HACK NOTE(bill): This is a hack but it works because strings are created at the very end // of the .ll file @@ -810,7 +814,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_write_str_lit(f, ", "); ir_print_type(f, m, t_i32); ir_write_str_lit(f, " 0, i32 0)"); - }else { + } else { // HACK NOTE(bill): This is a hack but it works because strings are created at the very end // of the .ll file irValue *str_array = ir_add_global_string_array(m, str); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index ea5081be4..d47c45401 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -5126,7 +5126,15 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc LLVMValueRef data = LLVMConstStringInContext(ctx, cast(char const *)value.value_string.text, cast(unsigned)value.value_string.len, - false); + 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) && diff --git a/src/parser.hpp b/src/parser.hpp index aa288304e..cd0d59a48 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -646,7 +646,7 @@ struct AstCommonStuff { u16 viral_state_flags; AstFile * file; Scope * scope; - TypeAndValue tav; + TypeAndValue tav; // TODO(bill): Make this a pointer to minimize pointer size }; struct Ast { @@ -655,7 +655,7 @@ struct Ast { u16 viral_state_flags; AstFile * file; Scope * scope; - TypeAndValue tav; + TypeAndValue tav; // TODO(bill): Make this a pointer to minimize pointer size // IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant union { diff --git a/src/types.cpp b/src/types.cpp index 1147beb33..8c39b9979 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1221,6 +1221,13 @@ bool is_type_u8_slice(Type *t) { } return false; } +bool is_type_u8_array(Type *t) { + t = base_type(t); + if (t->kind == Type_Array) { + return is_type_u8(t->Array.elem); + } + return false; +} bool is_type_u8_ptr(Type *t) { t = base_type(t); if (t->kind == Type_Pointer) { -- cgit v1.2.3 From 63e4a2341f1409eec1f2e58036cd01b24b66b8f0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 20 Nov 2020 16:24:23 +0000 Subject: Support string literals for fixed arrays of runes; Add %q support for arrays/slices of bytes --- core/fmt/fmt.odin | 4 ++-- src/check_expr.cpp | 13 ++++++++++--- src/ir.cpp | 8 +++++--- src/ir_print.cpp | 22 ++++++++++++++++++++++ src/llvm_backend.cpp | 26 ++++++++++++++++++++++++++ src/types.cpp | 52 +++++++++++++++++++++++++++++++--------------------- 6 files changed, 96 insertions(+), 29 deletions(-) (limited to 'src/types.cpp') diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index fae380de5..79c62cc17 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1599,7 +1599,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } case runtime.Type_Info_Array: - if verb == 's' && reflect.is_byte(info.elem) { + if (verb == 's' || verb == 'q') && reflect.is_byte(info.elem) { s := strings.string_from_ptr((^byte)(v.data), info.count); fmt_string(fi, s, verb); } else { @@ -1664,7 +1664,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Slice: slice := cast(^mem.Raw_Slice)v.data; - if verb == 's' && reflect.is_byte(info.elem) { + if (verb == 's' || verb == 'q') && reflect.is_byte(info.elem) { s := strings.string_from_ptr((^byte)(slice.data), slice.len); fmt_string(fi, s, verb); } else if verb == 'p' { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f258253f5..c67ad22b8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2955,10 +2955,17 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { if (check_is_assignable_to(c, operand, elem)) { operand->mode = Addressing_Value; } else { - if (operand->value.kind == ExactValue_String && is_type_u8_array(t)) { + if (operand->value.kind == ExactValue_String) { String s = operand->value.value_string; - if (s.len == t->Array.count) { - break; + if (is_type_u8_array(t)) { + if (s.len == t->Array.count) { + break; + } + } else if (is_type_rune_array(t)) { + isize rune_count = s.len; + if (rune_count == t->Array.count) { + break; + } } } operand->mode = Addressing_Invalid; diff --git a/src/ir.cpp b/src/ir.cpp index e8378bb97..24fe15afb 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7801,9 +7801,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): Edge case - if (is_type_u8_array(tv.type) && tv.value.kind == ExactValue_String) { - return ir_add_module_constant(proc->module, tv.type, tv.value); - } else if (tv.value.kind != ExactValue_Compound && + if (is_type_u8_array(tv.type) && tv.value.kind == ExactValue_String) { + return ir_add_module_constant(proc->module, tv.type, tv.value); + } else if (is_type_rune_array(tv.type) && tv.value.kind == ExactValue_String) { + return ir_add_module_constant(proc->module, tv.type, tv.value); + } else if (tv.value.kind != ExactValue_Compound && is_type_array(tv.type)) { Type *elem = core_array_type(tv.type); ExactValue value = convert_exact_value_for_type(tv.value, elem); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3ca9954ef..a6bfc75d3 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -734,6 +734,28 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { i64 count = type->Array.count; Type *elem = type->Array.elem; + + if (is_type_rune_array(type)) { + Rune rune; + isize offset = 0; + isize width = 1; + String s = value.value_string; + ir_write_byte(f, '['); + for (i64 i = 0; i < count && offset < s.len; i++) { + width = gb_utf8_decode(s.text+offset, s.len-offset, &rune); + if (i > 0) ir_write_str_lit(f, ", "); + ir_print_type(f, m, elem); + ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_i64(rune), elem); + offset += width; + } + GB_ASSERT(offset == s.len); + + ir_write_byte(f, ']'); + return; + } + + ir_write_byte(f, '['); for (i64 i = 0; i < count; i++) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index d47c45401..62a0013bc 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -5123,6 +5123,32 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } } 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, count); + + for (i64 i = 0; i < count && offset < s.len; i++) { + width = gb_utf8_decode(s.text+offset, s.len-offset, &rune); + offset += width; + + elems[i] = LLVMConstInt(et, rune, true); + + } + GB_ASSERT(offset == s.len); + + res.value = LLVMConstArray(et, elems, cast(unsigned)count); + return res; + } + GB_PANIC("HERE!\n"); + LLVMValueRef data = LLVMConstStringInContext(ctx, cast(char const *)value.value_string.text, cast(unsigned)value.value_string.len, diff --git a/src/types.cpp b/src/types.cpp index 8c39b9979..b381ba9c9 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1214,27 +1214,6 @@ bool is_type_slice(Type *t) { t = base_type(t); return t->kind == Type_Slice; } -bool is_type_u8_slice(Type *t) { - t = base_type(t); - if (t->kind == Type_Slice) { - return is_type_u8(t->Slice.elem); - } - return false; -} -bool is_type_u8_array(Type *t) { - t = base_type(t); - if (t->kind == Type_Array) { - return is_type_u8(t->Array.elem); - } - return false; -} -bool is_type_u8_ptr(Type *t) { - t = base_type(t); - if (t->kind == Type_Pointer) { - return is_type_u8(t->Slice.elem); - } - return false; -} bool is_type_proc(Type *t) { t = base_type(t); return t->kind == Type_Proc; @@ -1278,6 +1257,37 @@ bool is_type_relative_slice(Type *t) { return t->kind == Type_RelativeSlice; } +bool is_type_u8_slice(Type *t) { + t = base_type(t); + if (t->kind == Type_Slice) { + return is_type_u8(t->Slice.elem); + } + return false; +} +bool is_type_u8_array(Type *t) { + t = base_type(t); + if (t->kind == Type_Array) { + return is_type_u8(t->Array.elem); + } + return false; +} +bool is_type_u8_ptr(Type *t) { + t = base_type(t); + if (t->kind == Type_Pointer) { + return is_type_u8(t->Slice.elem); + } + return false; +} +bool is_type_rune_array(Type *t) { + t = base_type(t); + if (t->kind == Type_Array) { + return is_type_rune(t->Array.elem); + } + return false; +} + + + Type *core_array_type(Type *t) { for (;;) { -- cgit v1.2.3 From 9e42cb159543546ca549eeba6c943cf0f4c8410b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 12:20:04 +0000 Subject: Add comparisons to structs where all fields are comparable `==` and `!=` --- core/runtime/internal.odin | 5 +- src/checker.cpp | 1 + src/ir.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++++- src/llvm_abi.cpp | 60 ++++------------------- src/llvm_backend.cpp | 98 ++++++++++++++++++++++++++++++++++++++ src/llvm_backend.hpp | 2 + src/types.cpp | 64 +++++++++++++++++++++++++ 7 files changed, 292 insertions(+), 53 deletions(-) (limited to 'src/types.cpp') diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index cd0c681b3..c313070ac 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -180,8 +180,9 @@ mem_resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = } return allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, 0, loc); } - - +memory_equal :: proc "contextless" (a, b: rawptr, n: int) -> bool { + return memory_compare(a, b, n) == 0; +} memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check { x := uintptr(a); y := uintptr(b); diff --git a/src/checker.cpp b/src/checker.cpp index 0559fd300..1a5a75152 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1768,6 +1768,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("memcpy"), str_lit("memmove"), + str_lit("memory_equal"), str_lit("memory_compare"), str_lit("memory_compare_zero"), diff --git a/src/ir.cpp b/src/ir.cpp index 24fe15afb..2d244f62c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -24,6 +24,7 @@ struct irModule { Map entity_names; // Key: Entity * of the typename Map debug_info; // Key: Unique pointer Map anonymous_proc_lits; // Key: Ast * + Map compare_procs; // Key: Type * irDebugInfo * debug_compile_unit; Array debug_location_stack; @@ -161,6 +162,7 @@ struct irProcedure { Ast * return_ptr_hint_ast; bool return_ptr_hint_used; + bool ignore_dead_instr; Array branch_blocks; @@ -525,6 +527,8 @@ struct irAddr { Type *ir_type(irValue *value); irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, Ast *expr, irProcedure *proc = nullptr); +void ir_begin_procedure_body(irProcedure *proc); +void ir_end_procedure_body(irProcedure *proc); irAddr ir_addr(irValue *addr) { irAddr v = {irAddr_Default, addr}; @@ -4859,6 +4863,87 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue return nullptr; } +irValue *ir_get_compare_proc_for_type(irModule *m, Type *type) { + Type *original_type = type; + type = base_type(type); + GB_ASSERT(type->kind == Type_Struct); + type_set_offsets(type); + Type *pt = alloc_type_pointer(type); + + auto key = hash_type(type); + irValue **found = map_get(&m->compare_procs, key); + if (found) { + return *found; + } + static Type *proc_type = nullptr; + if (proc_type == nullptr) { + Type *args[2] = {t_rawptr, t_rawptr}; + proc_type = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); + set_procedure_abi_types(proc_type); + } + + static u32 proc_index = 0; + + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$cmp%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + + Ast *body = alloc_ast_node(nullptr, Ast_Invalid); + Entity *e = alloc_entity_procedure(nullptr, make_token_ident(proc_name), proc_type, 0); + e->Procedure.link_name = proc_name; + irValue *p = ir_value_procedure(m, e, proc_type, nullptr, body, proc_name); + map_set(&m->values, hash_entity(e), p); + string_map_set(&m->members, proc_name, p); + + irProcedure *proc = &p->Proc; + proc->is_startup = true; + proc->ignore_dead_instr = true; + ir_begin_procedure_body(proc); + // ir_start_block(proc, proc->decl_block); + GB_ASSERT(proc->curr_block != nullptr); + + irBlock *done = ir_new_block(proc, nullptr, "done"); // NOTE(bill): Append later + + irValue *x = proc->params[0]; + irValue *y = proc->params[1]; + irValue *lhs = ir_emit_conv(proc, x, pt); + irValue *rhs = ir_emit_conv(proc, y, pt); + + irBlock *block_false = ir_new_block(proc, nullptr, "bfalse"); + + for_array(i, type->Struct.fields) { + irBlock *next_block = ir_new_block(proc, nullptr, "btrue"); + + irValue *pleft = ir_emit_struct_ep(proc, lhs, cast(i32)i); + irValue *pright = ir_emit_struct_ep(proc, rhs, cast(i32)i); + irValue *left = ir_emit_load(proc, pleft); + irValue *right = ir_emit_load(proc, pright); + irValue *ok = ir_emit_comp(proc, Token_CmpEq, left, right); + + ir_emit_if(proc, ok, next_block, block_false); + + ir_emit_jump(proc, next_block); + ir_start_block(proc, next_block); + } + + ir_emit_jump(proc, done); + ir_start_block(proc, block_false); + + ir_emit(proc, ir_instr_return(proc, ir_const_bool(false))); + + ir_emit_jump(proc, done); + ir_start_block(proc, done); + ir_emit(proc, ir_instr_return(proc, ir_const_bool(true))); + + ir_end_procedure_body(proc); + + map_set(&m->compare_procs, key, p); + + return p; +} + irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right) { Type *a = base_type(ir_type(left)); Type *b = base_type(ir_type(right)); @@ -4992,6 +5077,30 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal } } + if (is_type_struct(a) && is_type_comparable(a)) { + irValue *left_ptr = ir_address_from_load_or_generate_local(proc, left); + irValue *right_ptr = ir_address_from_load_or_generate_local(proc, right); + irValue *res = {}; + if (is_type_simple_compare(a)) { + // TODO(bill): Test to see if this is actually faster!!!! + auto args = array_make(permanent_allocator(), 3); + args[0] = ir_emit_conv(proc, left_ptr, t_rawptr); + args[1] = ir_emit_conv(proc, right_ptr, t_rawptr); + args[2] = ir_const_int(type_size_of(a)); + res = ir_emit_runtime_call(proc, "memory_equal", args); + } else { + irValue *value = ir_get_compare_proc_for_type(proc->module, a); + auto args = array_make(permanent_allocator(), 2); + args[0] = ir_emit_conv(proc, left_ptr, t_rawptr); + args[1] = ir_emit_conv(proc, right_ptr, t_rawptr); + res = ir_emit_call(proc, value, args); + } + if (op_kind == Token_NotEq) { + res = ir_emit_unary_arith(proc, Token_Not, res, ir_type(res)); + } + return res; + } + if (is_type_string(a)) { if (is_type_cstring(a)) { left = ir_emit_conv(proc, left, t_string); @@ -11350,6 +11459,9 @@ void ir_begin_procedure_body(irProcedure *proc) { bool ir_remove_dead_instr(irProcedure *proc) { + if (proc->ignore_dead_instr) { + return false; + } isize elimination_count = 0; retry: #if 1 @@ -11476,7 +11588,7 @@ void ir_build_proc(irValue *value, irProcedure *parent) { proc->parent = parent; - if (proc->body != nullptr) { + if (proc->body != nullptr && proc->body->kind != Ast_Invalid) { u64 prev_state_flags = proc->module->state_flags; if (proc->tags != 0) { @@ -11578,6 +11690,7 @@ void ir_init_module(irModule *m, Checker *c) { map_init(&m->debug_info, heap_allocator()); map_init(&m->entity_names, heap_allocator()); map_init(&m->anonymous_proc_lits, heap_allocator()); + map_init(&m->compare_procs, heap_allocator()); array_init(&m->procs, heap_allocator()); array_init(&m->procs_to_generate, heap_allocator()); array_init(&m->foreign_library_paths, heap_allocator()); diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 7521ba2f7..77d4b42b0 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -267,56 +267,6 @@ i64 lb_alignof(LLVMTypeRef type) { return 1; } -Type *alloc_type_struct_from_field_types(Type **field_types, isize field_count, bool is_packed) { - Type *t = alloc_type_struct(); - t->Struct.fields = array_make(heap_allocator(), field_count); - - Scope *scope = nullptr; - for_array(i, t->Struct.fields) { - t->Struct.fields[i] = alloc_entity_field(scope, blank_token, field_types[i], false, cast(i32)i, EntityState_Resolved); - } - t->Struct.is_packed = is_packed; - - return t; -} - -Type *alloc_type_tuple_from_field_types(Type **field_types, isize field_count, bool is_packed, bool must_be_tuple) { - if (field_count == 0) { - return nullptr; - } - if (!must_be_tuple && field_count == 1) { - return field_types[0]; - } - - Type *t = alloc_type_tuple(); - t->Tuple.variables = array_make(heap_allocator(), field_count); - - Scope *scope = nullptr; - for_array(i, t->Tuple.variables) { - t->Tuple.variables[i] = alloc_entity_param(scope, blank_token, field_types[i], false, false); - } - t->Tuple.is_packed = is_packed; - - return t; -} - -Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type *results, bool is_c_vararg) { - - Type *params = alloc_type_tuple_from_field_types(param_types, param_count, false, true); - isize results_count = 0; - if (results != nullptr) { - if (results->kind != Type_Tuple) { - results = alloc_type_tuple_from_field_types(&results, 1, false, true); - } - results_count = results->Tuple.variables.count; - } - - Scope *scope = nullptr; - Type *t = alloc_type_proc(scope, params, param_count, results, results_count, false, /*not sure what to put here*/ProcCC_CDecl); - t->Proc.c_vararg = is_c_vararg; - return t; -} - #if 0 Type *lb_abi_to_odin_type(lbModule *m, LLVMTypeRef type, bool is_return, u32 level = 0) { Type **found = map_get(&m->llvm_types, hash_pointer(type)); @@ -959,6 +909,16 @@ namespace lbAbiAmd64SysV { }; +namespace lbAbiAarch64 { + LB_ABI_INFO(abi_info) { + lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType); + ft->ctx = c; + // ft->args = compute_arg_types(c, arg_types, arg_count); + // ft->ret = lbAbi386::compute_return_type(c, return_type, return_is_defined); + // ft->calling_convention = calling_convention; + return ft; + } +} LB_ABI_INFO(lb_get_abi_info) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 89a0ff667..665f9570a 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9143,6 +9143,78 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { return {}; } +lbValue lb_get_compare_proc_for_type(lbModule *m, Type *type) { + Type *original_type = type; + type = base_type(type); + GB_ASSERT(type->kind == Type_Struct); + type_set_offsets(type); + Type *pt = alloc_type_pointer(type); + LLVMTypeRef ptr_type = lb_type(m, pt); + + auto key = hash_type(type); + lbProcedure **found = map_get(&m->compare_procs, key); + lbProcedure *compare_proc = nullptr; + if (found) { + compare_proc = *found; + } else { + static Type *proc_type = nullptr; + if (proc_type == nullptr) { + Type *args[2] = {t_rawptr, t_rawptr}; + proc_type = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); + set_procedure_abi_types(proc_type); + } + + static u32 proc_index = 0; + + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$cmp%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, proc_type); + lb_begin_procedure_body(p); + + LLVMValueRef x = LLVMGetParam(p->value, 0); + LLVMValueRef y = LLVMGetParam(p->value, 1); + x = LLVMBuildPointerCast(p->builder, x, ptr_type, ""); + y = LLVMBuildPointerCast(p->builder, y, ptr_type, ""); + lbValue lhs = {x, pt}; + lbValue rhs = {y, pt}; + + lbBlock *block_false = lb_create_block(p, "bfalse"); + + lbValue res = lb_const_bool(m, t_bool, true); + for_array(i, type->Struct.fields) { + lbBlock *next_block = lb_create_block(p, "btrue"); + + lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); + lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); + lbValue left = lb_emit_load(p, pleft); + lbValue right = lb_emit_load(p, pright); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + + lb_emit_if(p, ok, next_block, block_false); + + lb_emit_jump(p, next_block); + lb_start_block(p, next_block); + } + + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); + + lb_start_block(p, block_false); + + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); + + lb_end_procedure_body(p); + + map_set(&m->compare_procs, key, p); + + compare_proc = p; + } + GB_ASSERT(compare_proc != nullptr); + + return {compare_proc->value, compare_proc->type}; +} lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) { Type *a = core_type(left.type); @@ -9272,6 +9344,31 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } } + + if (is_type_struct(a) && is_type_comparable(a)) { + 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(a)) { + // TODO(bill): Test to see if this is actually faster!!!! + auto args = array_make(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(a)); + res = lb_emit_runtime_call(p, "memory_equal", args); + } else { + lbValue value = lb_get_compare_proc_for_type(p->module, a); + auto args = array_make(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; + } + if (is_type_string(a)) { if (is_type_cstring(a)) { left = lb_emit_conv(p, left, t_string); @@ -11442,6 +11539,7 @@ void lb_init_module(lbModule *m, Checker *c) { string_map_init(&m->const_strings, a); map_init(&m->anonymous_proc_lits, a); map_init(&m->function_type_map, a); + map_init(&m->compare_procs, a); array_init(&m->procedures_to_generate, a); array_init(&m->foreign_library_paths, a); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 289f9d324..388176e9a 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -87,6 +87,8 @@ struct lbModule { Map anonymous_proc_lits; // Key: Ast * Map function_type_map; // Key: Type * + Map compare_procs; // Key: Type * + u32 global_array_index; u32 global_generated_index; u32 nested_type_name_guid; diff --git a/src/types.cpp b/src/types.cpp index b381ba9c9..80812e94b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1942,6 +1942,15 @@ bool is_type_comparable(Type *t) { case Type_Opaque: return is_type_comparable(t->Opaque.elem); + + case Type_Struct: + for_array(i, t->Struct.fields) { + Entity *f = t->Struct.fields[i]; + if (!is_type_comparable(f->type)) { + return false; + } + } + return true; } return false; } @@ -3401,6 +3410,58 @@ Type *reduce_tuple_to_single_type(Type *original_type) { } +Type *alloc_type_struct_from_field_types(Type **field_types, isize field_count, bool is_packed) { + Type *t = alloc_type_struct(); + t->Struct.fields = array_make(heap_allocator(), field_count); + + Scope *scope = nullptr; + for_array(i, t->Struct.fields) { + t->Struct.fields[i] = alloc_entity_field(scope, blank_token, field_types[i], false, cast(i32)i, EntityState_Resolved); + } + t->Struct.is_packed = is_packed; + + return t; +} + +Type *alloc_type_tuple_from_field_types(Type **field_types, isize field_count, bool is_packed, bool must_be_tuple) { + if (field_count == 0) { + return nullptr; + } + if (!must_be_tuple && field_count == 1) { + return field_types[0]; + } + + Type *t = alloc_type_tuple(); + t->Tuple.variables = array_make(heap_allocator(), field_count); + + Scope *scope = nullptr; + for_array(i, t->Tuple.variables) { + t->Tuple.variables[i] = alloc_entity_param(scope, blank_token, field_types[i], false, false); + } + t->Tuple.is_packed = is_packed; + + return t; +} + +Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type *results, bool is_c_vararg, ProcCallingConvention calling_convention) { + + Type *params = alloc_type_tuple_from_field_types(param_types, param_count, false, true); + isize results_count = 0; + if (results != nullptr) { + if (results->kind != Type_Tuple) { + results = alloc_type_tuple_from_field_types(&results, 1, false, true); + } + results_count = results->Tuple.variables.count; + } + + Scope *scope = nullptr; + Type *t = alloc_type_proc(scope, params, param_count, results, results_count, false, calling_convention); + t->Proc.c_vararg = is_c_vararg; + return t; +} + + + gbString write_type_to_string(gbString str, Type *type) { if (type == nullptr) { return gb_string_appendc(str, ""); @@ -3719,3 +3780,6 @@ gbString type_to_string(Type *type) { return write_type_to_string(gb_string_make(heap_allocator(), ""), type); } + + + -- cgit v1.2.3 From 0b30c3dc5ad3f3908719af19e9f7e61daae37706 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 14:35:31 +0000 Subject: Add `flags: Type_Info_Flags,` to `runtime.Type_Info` --- core/runtime/core.odin | 7 +++++++ src/checker.cpp | 5 +++-- src/checker.hpp | 4 ++++ src/ir.cpp | 9 +++++++-- src/llvm_backend.cpp | 10 ++++++++-- src/types.cpp | 23 +++++++++++++++++++++++ 6 files changed, 52 insertions(+), 6 deletions(-) (limited to 'src/types.cpp') diff --git a/core/runtime/core.odin b/core/runtime/core.odin index dfbe0d053..2989c4700 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -149,9 +149,16 @@ Type_Info_Relative_Slice :: struct { base_integer: ^Type_Info, }; +Type_Info_Flag :: enum u8 { + Comparable = 0, + Simple_Compare = 1, +}; +Type_Info_Flags :: distinct bit_set[Type_Info_Flag; u32]; + Type_Info :: struct { size: int, align: int, + flags: Type_Info_Flags, id: typeid, variant: union { diff --git a/src/checker.cpp b/src/checker.cpp index 1a5a75152..bba790cb2 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -899,6 +899,7 @@ bool init_checker(Checker *c, Parser *parser) { gbAllocator a = heap_allocator(); init_checker_info(&c->info); + c->info.checker = c; array_init(&c->procs_to_check, a); array_init(&c->procs_with_deferred_to_check, a); @@ -2179,9 +2180,9 @@ void init_core_type_info(Checker *c) { t_type_info_enum_value = type_info_enum_value->type; t_type_info_enum_value_ptr = alloc_type_pointer(t_type_info_enum_value); - GB_ASSERT(tis->fields.count == 4); + GB_ASSERT(tis->fields.count == 5); - Entity *type_info_variant = tis->fields[3]; + Entity *type_info_variant = tis->fields[4]; Type *tiv_type = type_info_variant->type; GB_ASSERT(is_type_union(tiv_type)); diff --git a/src/checker.hpp b/src/checker.hpp index 72c4b148c..168c00d33 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -252,8 +252,12 @@ struct AtomOpMapEntry { }; +struct CheckerContext; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { + Checker *checker; + Map untyped; // Key: Ast * | Expression -> ExprInfo // NOTE(bill): This needs to be a map and not on the Ast // as it needs to be iterated across diff --git a/src/ir.cpp b/src/ir.cpp index 2d244f62c..ce5dea86d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11974,6 +11974,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info // 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; @@ -11993,11 +11995,14 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *tag = nullptr; irValue *ti_ptr = ir_emit_array_epi(proc, ir_global_type_info_data, cast(i32)entry_index); - irValue *variant_ptr = ir_emit_struct_ep(proc, ti_ptr, 3); + irValue *variant_ptr = ir_emit_struct_ep(proc, ti_ptr, 4); + + irValue *type_info_flags = ir_value_constant(t_type_info_flags, exact_value_i64(type_info_flags_of_type(t))); ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 0), ir_const_int(type_size_of(t))); ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 1), ir_const_int(type_align_of(t))); - ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 2), ir_typeid(proc->module, t)); + ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 2), type_info_flags); + ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 3), ir_typeid(proc->module, t)); switch (t->kind) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 665f9570a..a2727b012 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -11732,6 +11732,9 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da // 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; @@ -11751,11 +11754,14 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue tag = {}; lbValue ti_ptr = lb_emit_array_epi(p, lb_global_type_info_data.addr, cast(i32)entry_index); - lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 3); + 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), lb_typeid(m, 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) { diff --git a/src/types.cpp b/src/types.cpp index 80812e94b..09888f878 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -373,7 +373,28 @@ enum Typeid_Kind : u8 { Typeid_Relative_Slice, }; +// IMPORTANT NOTE(bill): This must match the same as the in core.odin +enum TypeInfoFlag : u32 { + TypeInfoFlag_Comparable = 1<<0, + TypeInfoFlag_Simple_Compare = 1<<1, +}; +bool is_type_comparable(Type *t); +bool is_type_simple_compare(Type *t); + +u32 type_info_flags_of_type(Type *type) { + if (type == nullptr) { + return 0; + } + u32 flags = 0; + if (is_type_comparable(type)) { + flags |= TypeInfoFlag_Comparable; + } + if (is_type_simple_compare(type)) { + flags |= TypeInfoFlag_Comparable; + } + return flags; +} // TODO(bill): Should I add extra information here specifying the kind of selection? @@ -1348,6 +1369,8 @@ bool is_type_simple_compare(Type *t) { return false; } + + Type *base_complex_elem_type(Type *t) { t = core_type(t); if (t->kind == Type_Basic) { -- cgit v1.2.3 From 4e370e6ed8d6cfe3dee306dfbc298ba68722f12e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 15:53:49 +0000 Subject: Add `equal` procedure field to `runtime.Type_Info_Struct` --- core/reflect/reflect.odin | 78 +++++++++++++++++++++++++++++++++++++ core/runtime/core.odin | 5 +++ src/ir.cpp | 11 ++++-- src/llvm_backend.cpp | 14 ++++--- src/types.cpp | 97 ++++++++++++++++++++++++----------------------- 5 files changed, 149 insertions(+), 56 deletions(-) (limited to 'src/types.cpp') diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 947a10771..df183e2fd 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -1206,3 +1206,81 @@ as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) { return; } + + +not_equal :: proc(a, b: any) -> bool { + return !equal(a, b); +} +equal :: proc(a, b: any) -> bool { + if a == nil && b == nil { + return true; + } + + if a.id != b.id { + return false; + } + + if a.data == b.data { + return true; + } + + t := type_info_of(a.id); + if .Comparable not_in t.flags { + return false; + } + + if t.size == 0 { + return true; + } + + if .Simple_Compare in t.flags { + return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0; + } + + t = runtime.type_info_core(t); + + #partial switch v in t.variant { + case Type_Info_String: + if v.is_cstring { + x := string((^cstring)(a.data)^); + y := string((^cstring)(b.data)^); + return x == y; + } else { + x := (^string)(a.data)^; + y := (^string)(b.data)^; + return x == y; + } + + case Type_Info_Array: + for i in 0.. bool; Type_Info_Struct :: struct { types: []^Type_Info, names: []string, @@ -97,6 +99,9 @@ Type_Info_Struct :: struct { is_packed: bool, is_raw_union: bool, custom_align: bool, + + equal: Type_Struct_Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set + // These are only set iff this structure is an SOA structure soa_kind: Type_Info_Struct_Soa_Kind, soa_base_type: ^Type_Info, diff --git a/src/ir.cpp b/src/ir.cpp index ce5dea86d..28edd5981 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12353,8 +12353,13 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align); + if (is_type_comparable(t) && !is_type_simple_compare(t)) { + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 8), ir_get_compare_proc_for_type(proc->module, t)); + } + + if (t->Struct.soa_kind != StructSoa_None) { - irValue *kind = ir_emit_struct_ep(proc, tag, 8); + irValue *kind = ir_emit_struct_ep(proc, tag, 9); Type *kind_type = type_deref(ir_type(kind)); irValue *soa_kind = ir_value_constant(kind_type, exact_value_i64(t->Struct.soa_kind)); @@ -12363,8 +12368,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_emit_store(proc, kind, soa_kind); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 9), soa_type); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 10), soa_len); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 10), soa_type); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 11), soa_len); } } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index a2727b012..0272d1dfa 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -12178,7 +12178,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da case Type_Struct: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_struct_ptr); - LLVMValueRef vals[11] = {}; + LLVMValueRef vals[12] = {}; { @@ -12188,18 +12188,22 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da 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_compare_proc_for_type(m, t).value; + } + if (t->Struct.soa_kind != StructSoa_None) { - lbValue kind = lb_emit_struct_ep(p, tag, 8); + 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[8] = soa_kind.value; - vals[9] = soa_type.value; - vals[10] = soa_len.value; + vals[9] = soa_kind.value; + vals[1] = soa_type.value; + vals[11] = soa_len.value; } } diff --git a/src/types.cpp b/src/types.cpp index 09888f878..b8b4b32f5 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1321,54 +1321,6 @@ Type *core_array_type(Type *t) { return t; } -// NOTE(bill): type can be easily compared using memcmp -bool is_type_simple_compare(Type *t) { - t = core_type(t); - switch (t->kind) { - case Type_Array: - return is_type_simple_compare(t->Array.elem); - - case Type_EnumeratedArray: - return is_type_simple_compare(t->EnumeratedArray.elem); - - case Type_Basic: - if (t->Basic.flags & BasicFlag_SimpleCompare) { - return true; - } - return false; - - case Type_Pointer: - case Type_Proc: - case Type_BitSet: - case Type_BitField: - return true; - - case Type_Struct: - for_array(i, t->Struct.fields) { - Entity *f = t->Struct.fields[i]; - if (!is_type_simple_compare(f->type)) { - return false; - } - } - return true; - - case Type_Union: - for_array(i, t->Union.variants) { - Type *v = t->Union.variants[i]; - if (!is_type_simple_compare(v)) { - return false; - } - } - return true; - - case Type_SimdVector: - return is_type_simple_compare(t->SimdVector.elem); - - } - - return false; -} - Type *base_complex_elem_type(Type *t) { @@ -1978,6 +1930,55 @@ bool is_type_comparable(Type *t) { return false; } +// NOTE(bill): type can be easily compared using memcmp +bool is_type_simple_compare(Type *t) { + t = core_type(t); + switch (t->kind) { + case Type_Array: + return is_type_simple_compare(t->Array.elem); + + case Type_EnumeratedArray: + return is_type_simple_compare(t->EnumeratedArray.elem); + + case Type_Basic: + if (t->Basic.flags & BasicFlag_SimpleCompare) { + return true; + } + return false; + + case Type_Pointer: + case Type_Proc: + case Type_BitSet: + case Type_BitField: + return true; + + case Type_Struct: + for_array(i, t->Struct.fields) { + Entity *f = t->Struct.fields[i]; + if (!is_type_simple_compare(f->type)) { + return false; + } + } + return true; + + case Type_Union: + for_array(i, t->Union.variants) { + Type *v = t->Union.variants[i]; + if (!is_type_simple_compare(v)) { + return false; + } + } + return true; + + case Type_SimdVector: + return is_type_simple_compare(t->SimdVector.elem); + + } + + return false; +} + + Type *strip_type_aliasing(Type *x) { if (x == nullptr) { return x; -- cgit v1.2.3 From 67bc35e882800164c2a7a30cadc237d4051a4b46 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 16:19:26 +0000 Subject: Fix logic for comparisons of struct #raw_union types --- core/reflect/reflect.odin | 3 ++- src/types.cpp | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src/types.cpp') diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index df183e2fd..ed50d658b 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -1207,7 +1207,7 @@ as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) { return; } - +/* not_equal :: proc(a, b: any) -> bool { return !equal(a, b); } @@ -1284,3 +1284,4 @@ equal :: proc(a, b: any) -> bool { return true; } +*/ diff --git a/src/types.cpp b/src/types.cpp index b8b4b32f5..0fc529213 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1919,6 +1919,9 @@ bool is_type_comparable(Type *t) { return is_type_comparable(t->Opaque.elem); case Type_Struct: + if (t->Struct.is_raw_union) { + return is_type_simple_compare(t); + } for_array(i, t->Struct.fields) { Entity *f = t->Struct.fields[i]; if (!is_type_comparable(f->type)) { -- cgit v1.2.3 From 4762d2f2d15d64e012e2de876f1fd78c3ebd7c3e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 16:56:31 +0000 Subject: map type internal reorganization --- core/runtime/core.odin | 42 ------------------------ core/runtime/dynamic_map_internal.odin | 60 +++++++++++++++++++++++++++++----- src/check_type.cpp | 17 +++++----- src/checker.cpp | 8 ++--- src/ir.cpp | 2 +- src/llvm_backend.cpp | 2 +- src/types.cpp | 2 +- 7 files changed, 66 insertions(+), 67 deletions(-) (limited to 'src/types.cpp') diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 14d5c99ce..76454159c 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -351,48 +351,6 @@ Raw_Map :: struct { entries: Raw_Dynamic_Array, } -INITIAL_MAP_CAP :: 16; - -Map_Key :: struct { - hash: u64, - /* NOTE(bill) - size_of(Map_Key) == 16 Bytes on 32-bit systems - size_of(Map_Key) == 24 Bytes on 64-bit systems - - This does mean that an extra word is wasted for each map when a string is not used on 64-bit systems - however, this is probably not a huge problem in terms of memory usage - */ - key: struct #raw_union { - str: string, - val: u64, - }, -} - -Map_Find_Result :: struct { - hash_index: int, - entry_prev: int, - entry_index: int, -} - -Map_Entry_Header :: struct { - key: Map_Key, - next: int, -/* - value: Value_Type, -*/ -} - -Map_Header :: struct { - m: ^Raw_Map, - is_key_string: bool, - - entry_size: int, - entry_align: int, - - value_offset: uintptr, - value_size: int, -} - ///////////////////////////// // Init Startup Procedures // ///////////////////////////// diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index b4148e74e..71d3ba8f7 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -3,10 +3,52 @@ package runtime import "intrinsics" _ :: intrinsics; +INITIAL_MAP_CAP :: 16; + +Map_Hash :: struct { + hash: u64, + /* NOTE(bill) + size_of(Map_Hash) == 16 Bytes on 32-bit systems + size_of(Map_Hash) == 24 Bytes on 64-bit systems + + This does mean that an extra word is wasted for each map when a string is not used on 64-bit systems + however, this is probably not a huge problem in terms of memory usage + */ + key: struct #raw_union { + str: string, + val: u64, + }, +} + +Map_Find_Result :: struct { + hash_index: int, + entry_prev: int, + entry_index: int, +} + +Map_Entry_Header :: struct { + key: Map_Hash, + next: int, +/* + value: Value_Type, +*/ +} + +Map_Header :: struct { + m: ^Raw_Map, + is_key_string: bool, + + entry_size: int, + entry_align: int, + + value_offset: uintptr, + value_size: int, +} + __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { header := Map_Header{m = (^Raw_Map)(m)}; Entry :: struct { - key: Map_Key, + key: Map_Hash, next: int, value: V, }; @@ -19,9 +61,9 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { return header; } -__get_map_key :: proc "contextless" (k: $K) -> Map_Key { +__get_map_key :: proc "contextless" (k: $K) -> Map_Hash { key := k; - map_key: Map_Key; + map_key: Map_Hash; T :: intrinsics.type_core_type(K); @@ -169,7 +211,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c header.m^ = nm; } -__dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr { +__dynamic_map_get :: proc(h: Map_Header, key: Map_Hash) -> rawptr { index := __dynamic_map_find(h, key).entry_index; if index >= 0 { data := uintptr(__dynamic_map_get_entry(h, index)); @@ -178,7 +220,7 @@ __dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr { return nil; } -__dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #caller_location) #no_bounds_check { +__dynamic_map_set :: proc(h: Map_Header, key: Map_Hash, value: rawptr, loc := #caller_location) #no_bounds_check { index: int; assert(value != nil); @@ -223,7 +265,7 @@ __dynamic_map_full :: inline proc(using h: Map_Header) -> bool { } -__dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool { +__dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Hash) -> bool { if a.hash == b.hash { if h.is_key_string { return a.key.str == b.key.str; @@ -235,7 +277,7 @@ __dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool { return false; } -__dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result #no_bounds_check { +__dynamic_map_find :: proc(using h: Map_Header, key: Map_Hash) -> Map_Find_Result #no_bounds_check { fr := Map_Find_Result{-1, -1, -1}; if n := u64(len(m.hashes)); n > 0 { fr.hash_index = int(key.hash % n); @@ -252,7 +294,7 @@ __dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result return fr; } -__dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key, loc := #caller_location) -> int { +__dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Hash, loc := #caller_location) -> int { prev := m.entries.len; c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc); if c != prev { @@ -263,7 +305,7 @@ __dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key, loc := #calle return prev; } -__dynamic_map_delete_key :: proc(using h: Map_Header, key: Map_Key) { +__dynamic_map_delete_key :: proc(using h: Map_Header, key: Map_Hash) { fr := __dynamic_map_find(h, key); if fr.entry_index >= 0 { __dynamic_map_erase(h, fr); diff --git a/src/check_type.cpp b/src/check_type.cpp index dfd0f093d..a3b71a034 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2784,24 +2784,23 @@ void init_map_entry_type(Type *type) { if (type->Map.entry_type != nullptr) return; // NOTE(bill): The preload types may have not been set yet - GB_ASSERT(t_map_key != nullptr); + GB_ASSERT(t_map_hash != nullptr); Type *entry_type = alloc_type_struct(); /* struct { - hash: __MapKey; - next: int; - key: Key; - value: Value; + key: runtime.Map_Key, + next: int, + value: Value, } */ Ast *dummy_node = alloc_ast_node(nullptr, Ast_Invalid); Scope *s = create_scope(builtin_pkg->scope); - auto fields = array_make(permanent_allocator(), 0, 3); - array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")), t_map_key, false, 0, EntityState_Resolved)); - array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")), t_int, false, 1, EntityState_Resolved)); - array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, 2, EntityState_Resolved)); + auto fields = array_make(permanent_allocator(), 0, 4); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")), t_map_hash, false, cast(i32)fields.count, EntityState_Resolved)); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")), t_int, false, cast(i32)fields.count, EntityState_Resolved)); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, cast(i32)fields.count, EntityState_Resolved)); entry_type->Struct.fields = fields; diff --git a/src/checker.cpp b/src/checker.cpp index bba790cb2..efa7d76f7 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2278,14 +2278,14 @@ void init_core_source_code_location(Checker *c) { } void init_core_map_type(Checker *c) { - if (t_map_key == nullptr) { - Entity *e = find_core_entity(c, str_lit("Map_Key")); + if (t_map_hash == nullptr) { + Entity *e = find_core_entity(c, str_lit("Map_Hash")); if (e->state == EntityState_Unresolved) { auto ctx = c->init_ctx; check_entity_decl(&ctx, e, nullptr, nullptr); } - t_map_key = e->type; - GB_ASSERT(t_map_key != nullptr); + t_map_hash = e->type; + GB_ASSERT(t_map_hash != nullptr); } if (t_map_header == nullptr) { diff --git a/src/ir.cpp b/src/ir.cpp index 28edd5981..634e0a698 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3608,7 +3608,7 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val_ptr, Type *map_ty irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { Type *hash_type = t_u64; - irValue *v = ir_add_local_generated(proc, t_map_key, true); + irValue *v = ir_add_local_generated(proc, t_map_hash, true); Type *t = base_type(ir_type(key)); key = ir_emit_conv(proc, key, key_type); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 0272d1dfa..1fb0891b5 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -10259,7 +10259,7 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { Type *hash_type = t_u64; - lbAddr v = lb_add_local_generated(p, t_map_key, true); + lbAddr v = lb_add_local_generated(p, t_map_hash, true); lbValue vp = lb_addr_get_ptr(p, v); Type *t = base_type(key.type); key = lb_emit_conv(p, key, key_type); diff --git a/src/types.cpp b/src/types.cpp index 0fc529213..7ca9a3cc2 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -684,7 +684,7 @@ gb_global Type *t_context_ptr = nullptr; gb_global Type *t_source_code_location = nullptr; gb_global Type *t_source_code_location_ptr = nullptr; -gb_global Type *t_map_key = nullptr; +gb_global Type *t_map_hash = nullptr; gb_global Type *t_map_header = nullptr; gb_global Type *t_vector_x86_mmx = nullptr; -- cgit v1.2.3 From 39bed567b34a4bd74f7dfa99dd1ddb4621f67190 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 14:22:42 +0000 Subject: Add intrinsics.type_equal_proc; Make `map` use an internal equal procedure to compare keys --- core/intrinsics/intrinsics.odin | 3 ++ core/runtime/core.odin | 6 ++- core/runtime/dynamic_map_internal.odin | 15 ++---- src/check_expr.cpp | 21 +++++++++ src/checker.cpp | 8 ++++ src/checker_builtin_procs.hpp | 4 ++ src/ir.cpp | 84 ++++++++++++++++++++-------------- src/llvm_backend.cpp | 79 +++++++++++++++++++------------- src/llvm_backend.hpp | 2 + src/types.cpp | 2 + 10 files changed, 147 insertions(+), 77 deletions(-) (limited to 'src/types.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 3e20baecd..3738b57dd 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -1,4 +1,5 @@ // This is purely for documentation +//+ignore package intrinsics // Types @@ -152,3 +153,5 @@ type_polymorphic_record_parameter_value :: proc($T: typeid, index: int) -> $V -- type_field_index_of :: proc($T: typeid, $name: string) -> uintptr --- + +type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) --- diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 76454159c..1cc564ff2 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -42,6 +42,8 @@ Platform_Endianness :: enum u8 { Big = 2, } +Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; + Type_Info_Struct_Soa_Kind :: enum u8 { None = 0, Fixed = 1, @@ -89,7 +91,6 @@ Type_Info_Tuple :: struct { // Only used for procedures parameters and results names: []string, }; -Type_Struct_Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; Type_Info_Struct :: struct { types: []^Type_Info, names: []string, @@ -100,7 +101,7 @@ Type_Info_Struct :: struct { is_raw_union: bool, custom_align: bool, - equal: Type_Struct_Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set + equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set // These are only set iff this structure is an SOA structure soa_kind: Type_Info_Struct_Soa_Kind, @@ -351,6 +352,7 @@ Raw_Map :: struct { entries: Raw_Dynamic_Array, } + ///////////////////////////// // Init Startup Procedures // ///////////////////////////// diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 38618ea34..0c7146e25 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -63,13 +63,13 @@ Map_Entry_Header :: struct { Map_Header :: struct { m: ^Raw_Map, - is_key_string: bool, + equal: Equal_Proc, entry_size: int, entry_align: int, - key_offset: uintptr, - key_size: int, + key_offset: uintptr, + key_size: int, value_offset: uintptr, value_size: int, @@ -115,7 +115,7 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { value: V, }; - header.is_key_string = intrinsics.type_is_string(K); + header.equal = intrinsics.type_equal_proc(K); header.entry_size = int(size_of(Entry)); header.entry_align = int(align_of(Entry)); @@ -275,12 +275,7 @@ __dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Hash) -> bool { if a.key_ptr == b.key_ptr { return true; } - assert(a.key_ptr != nil && b.key_ptr != nil); - - if h.is_key_string { - return (^string)(a.key_ptr)^ == (^string)(b.key_ptr)^; - } - return memory_equal(a.key_ptr, b.key_ptr, h.key_size); + return h.equal(a.key_ptr, b.key_ptr); } return false; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4b17b4f27..e2a6089b9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6060,6 +6060,27 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } break; + + case BuiltinProc_type_equal_proc: + { + Operand op = {}; + Type *bt = check_type(c, ce->args[0]); + Type *type = base_type(bt); + if (type == nullptr || type == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (!is_type_comparable(type)) { + gbString t = type_to_string(type); + error(ce->args[0], "Expected a comparable type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + operand->mode = Addressing_Value; + operand->type = t_equal_proc; + break; + } } return true; diff --git a/src/checker.cpp b/src/checker.cpp index efa7d76f7..ee3496fbf 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -726,6 +726,14 @@ void init_universal(void) { } add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]); + { + void set_procedure_abi_types(Type *type); + + Type *args[2] = {t_rawptr, t_rawptr}; + t_equal_proc = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); + set_procedure_abi_types(t_equal_proc); + } + // Constants add_global_constant(str_lit("true"), t_untyped_bool, exact_value_bool(true)); add_global_constant(str_lit("false"), t_untyped_bool, exact_value_bool(false)); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index d0e009cc0..9a5cdb1b8 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -183,6 +183,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_field_index_of, + BuiltinProc_type_equal_proc, + BuiltinProc__type_end, @@ -367,5 +369,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, }; diff --git a/src/ir.cpp b/src/ir.cpp index 9607f8ce7..b1deda0b9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -529,6 +529,8 @@ Type *ir_type(irValue *value); irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, Ast *expr, irProcedure *proc = nullptr); void ir_begin_procedure_body(irProcedure *proc); void ir_end_procedure_body(irProcedure *proc); +irValue *ir_get_equal_proc_for_type(irModule *m, Type *type); + irAddr ir_addr(irValue *addr) { irAddr v = {irAddr_Default, addr}; @@ -3591,7 +3593,6 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val_ptr, Type *map_ty irValue *m = ir_emit_conv(proc, map_val_ptr, type_deref(ir_type(gep0))); ir_emit_store(proc, gep0, m); - ir_emit_store(proc, ir_emit_struct_ep(proc, h, 1), ir_const_bool(is_type_string(key_type))); i64 entry_size = type_size_of (map_type->Map.entry_type); i64 entry_align = type_align_of (map_type->Map.entry_type); @@ -3600,6 +3601,7 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val_ptr, Type *map_ty i64 value_offset = type_offset_of(map_type->Map.entry_type, 3); i64 value_size = type_size_of (map_type->Map.value); + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 1), ir_get_equal_proc_for_type(proc->module, key_type)); ir_emit_store(proc, ir_emit_struct_ep(proc, h, 2), ir_const_int(entry_size)); ir_emit_store(proc, ir_emit_struct_ep(proc, h, 3), ir_const_int(entry_align)); ir_emit_store(proc, ir_emit_struct_ep(proc, h, 4), ir_const_uintptr(key_offset)); @@ -4867,11 +4869,9 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue return nullptr; } -irValue *ir_get_compare_proc_for_type(irModule *m, Type *type) { +irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { Type *original_type = type; type = base_type(type); - GB_ASSERT(type->kind == Type_Struct); - type_set_offsets(type); Type *pt = alloc_type_pointer(type); auto key = hash_type(type); @@ -4879,12 +4879,6 @@ irValue *ir_get_compare_proc_for_type(irModule *m, Type *type) { if (found) { return *found; } - static Type *proc_type = nullptr; - if (proc_type == nullptr) { - Type *args[2] = {t_rawptr, t_rawptr}; - proc_type = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); - set_procedure_abi_types(proc_type); - } static u32 proc_index = 0; @@ -4895,9 +4889,9 @@ irValue *ir_get_compare_proc_for_type(irModule *m, Type *type) { Ast *body = alloc_ast_node(nullptr, Ast_Invalid); - Entity *e = alloc_entity_procedure(nullptr, make_token_ident(proc_name), proc_type, 0); + Entity *e = alloc_entity_procedure(nullptr, make_token_ident(proc_name), t_equal_proc, 0); e->Procedure.link_name = proc_name; - irValue *p = ir_value_procedure(m, e, proc_type, nullptr, body, proc_name); + irValue *p = ir_value_procedure(m, e, t_equal_proc, nullptr, body, proc_name); map_set(&m->values, hash_entity(e), p); string_map_set(&m->members, proc_name, p); @@ -4908,38 +4902,58 @@ irValue *ir_get_compare_proc_for_type(irModule *m, Type *type) { // ir_start_block(proc, proc->decl_block); GB_ASSERT(proc->curr_block != nullptr); - irBlock *done = ir_new_block(proc, nullptr, "done"); // NOTE(bill): Append later - irValue *x = proc->params[0]; irValue *y = proc->params[1]; irValue *lhs = ir_emit_conv(proc, x, pt); irValue *rhs = ir_emit_conv(proc, y, pt); - irBlock *block_false = ir_new_block(proc, nullptr, "bfalse"); + irBlock *block_same_ptr = ir_new_block(proc, nullptr, "same_ptr"); + irBlock *block_diff_ptr = ir_new_block(proc, nullptr, "diff_ptr"); - for_array(i, type->Struct.fields) { - irBlock *next_block = ir_new_block(proc, nullptr, "btrue"); + irValue *same_ptr = ir_emit_comp(proc, Token_CmpEq, lhs, rhs); + ir_emit_if(proc, same_ptr, block_same_ptr, block_diff_ptr); + ir_start_block(proc, block_same_ptr); + ir_emit(proc, ir_instr_return(proc, ir_const_bool(true))); - irValue *pleft = ir_emit_struct_ep(proc, lhs, cast(i32)i); - irValue *pright = ir_emit_struct_ep(proc, rhs, cast(i32)i); - irValue *left = ir_emit_load(proc, pleft); - irValue *right = ir_emit_load(proc, pright); - irValue *ok = ir_emit_comp(proc, Token_CmpEq, left, right); + ir_start_block(proc, block_diff_ptr); - ir_emit_if(proc, ok, next_block, block_false); + if (type->kind == Type_Struct) { + type_set_offsets(type); - ir_emit_jump(proc, next_block); - ir_start_block(proc, next_block); - } + irBlock *done = ir_new_block(proc, nullptr, "done"); // NOTE(bill): Append later - ir_emit_jump(proc, done); - ir_start_block(proc, block_false); + irBlock *block_false = ir_new_block(proc, nullptr, "bfalse"); - ir_emit(proc, ir_instr_return(proc, ir_const_bool(false))); + for_array(i, type->Struct.fields) { + irBlock *next_block = ir_new_block(proc, nullptr, "btrue"); - ir_emit_jump(proc, done); - ir_start_block(proc, done); - ir_emit(proc, ir_instr_return(proc, ir_const_bool(true))); + irValue *pleft = ir_emit_struct_ep(proc, lhs, cast(i32)i); + irValue *pright = ir_emit_struct_ep(proc, rhs, cast(i32)i); + irValue *left = ir_emit_load(proc, pleft); + irValue *right = ir_emit_load(proc, pright); + irValue *ok = ir_emit_comp(proc, Token_CmpEq, left, right); + + ir_emit_if(proc, ok, next_block, block_false); + + ir_emit_jump(proc, next_block); + ir_start_block(proc, next_block); + } + + ir_emit_jump(proc, done); + ir_start_block(proc, block_false); + + ir_emit(proc, ir_instr_return(proc, ir_const_bool(false))); + + ir_emit_jump(proc, done); + ir_start_block(proc, done); + ir_emit(proc, ir_instr_return(proc, ir_const_bool(true))); + } else { + irValue *left = ir_emit_load(proc, lhs); + irValue *right = ir_emit_load(proc, rhs); + irValue *ok = ir_emit_comp(proc, Token_CmpEq, left, right); + ok = ir_emit_conv(proc, ok, t_bool); + ir_emit(proc, ir_instr_return(proc, ok)); + } ir_end_procedure_body(proc); @@ -5093,7 +5107,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal args[2] = ir_const_int(type_size_of(a)); res = ir_emit_runtime_call(proc, "memory_equal", args); } else { - irValue *value = ir_get_compare_proc_for_type(proc->module, a); + irValue *value = ir_get_equal_proc_for_type(proc->module, a); auto args = array_make(permanent_allocator(), 2); args[0] = ir_emit_conv(proc, left_ptr, t_rawptr); args[1] = ir_emit_conv(proc, right_ptr, t_rawptr); @@ -7572,6 +7586,8 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu return ir_emit(proc, ir_instr_atomic_cxchg(proc, type, address, old_value, new_value, id)); } + case BuiltinProc_type_equal_proc: + return ir_get_equal_proc_for_type(proc->module, ce->args[0]->tav.type); } @@ -12353,7 +12369,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align); if (is_type_comparable(t) && !is_type_simple_compare(t)) { - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 8), ir_get_compare_proc_for_type(proc->module, t)); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 8), ir_get_equal_proc_for_type(proc->module, t)); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 57385a9d6..39b4030af 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -8555,6 +8555,10 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, res.type = fix_typed; return res; } + + + case BuiltinProc_type_equal_proc: + return lb_get_equal_proc_for_type(p->module, ce->args[0]->tav.type); } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); @@ -9156,11 +9160,11 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { return {}; } -lbValue lb_get_compare_proc_for_type(lbModule *m, Type *type) { +lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) { Type *original_type = type; type = base_type(type); - GB_ASSERT(type->kind == Type_Struct); - type_set_offsets(type); + GB_ASSERT(is_type_comparable(type)); + Type *pt = alloc_type_pointer(type); LLVMTypeRef ptr_type = lb_type(m, pt); @@ -9170,13 +9174,6 @@ lbValue lb_get_compare_proc_for_type(lbModule *m, Type *type) { if (found) { compare_proc = *found; } else { - static Type *proc_type = nullptr; - if (proc_type == nullptr) { - Type *args[2] = {t_rawptr, t_rawptr}; - proc_type = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); - set_procedure_abi_types(proc_type); - } - static u32 proc_index = 0; char buf[16] = {}; @@ -9184,7 +9181,7 @@ lbValue lb_get_compare_proc_for_type(lbModule *m, Type *type) { char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); String proc_name = make_string_c(str); - lbProcedure *p = lb_create_dummy_procedure(m, proc_name, proc_type); + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); lb_begin_procedure_body(p); LLVMValueRef x = LLVMGetParam(p->value, 0); @@ -9194,29 +9191,50 @@ lbValue lb_get_compare_proc_for_type(lbModule *m, Type *type) { lbValue lhs = {x, pt}; lbValue rhs = {y, pt}; - lbBlock *block_false = lb_create_block(p, "bfalse"); - lbValue res = lb_const_bool(m, t_bool, true); - for_array(i, type->Struct.fields) { - lbBlock *next_block = lb_create_block(p, "btrue"); + lbBlock *block_same_ptr = lb_create_block(p, "same_ptr"); + lbBlock *block_diff_ptr = lb_create_block(p, "diff_ptr"); - lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); - lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); - lbValue left = lb_emit_load(p, pleft); - lbValue right = lb_emit_load(p, pright); - lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + lbValue same_ptr = lb_emit_comp(p, Token_CmpEq, lhs, rhs); + lb_emit_if(p, same_ptr, block_same_ptr, block_diff_ptr); + lb_start_block(p, block_same_ptr); + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); - lb_emit_if(p, ok, next_block, block_false); + lb_start_block(p, block_diff_ptr); - lb_emit_jump(p, next_block); - lb_start_block(p, next_block); - } + if (type->kind == Type_Struct) { + type_set_offsets(type); - LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); + lbBlock *block_false = lb_create_block(p, "bfalse"); + lbValue res = lb_const_bool(m, t_bool, true); + + for_array(i, type->Struct.fields) { + lbBlock *next_block = lb_create_block(p, "btrue"); + + lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); + lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); + lbValue left = lb_emit_load(p, pleft); + lbValue right = lb_emit_load(p, pright); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + + lb_emit_if(p, ok, next_block, block_false); + + lb_emit_jump(p, next_block); + lb_start_block(p, next_block); + } - lb_start_block(p, block_false); + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); - LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); + lb_start_block(p, block_false); + + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); + } else { + lbValue left = lb_emit_load(p, lhs); + lbValue right = lb_emit_load(p, rhs); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + ok = lb_emit_conv(p, ok, t_bool); + LLVMBuildRet(p->builder, ok.value); + } lb_end_procedure_body(p); @@ -9370,7 +9388,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri args[2] = lb_const_int(p->module, t_int, type_size_of(a)); res = lb_emit_runtime_call(p, "memory_equal", args); } else { - lbValue value = lb_get_compare_proc_for_type(p->module, a); + lbValue value = lb_get_equal_proc_for_type(p->module, a); auto args = array_make(permanent_allocator(), 2); args[0] = lb_emit_conv(p, left_ptr, t_rawptr); args[1] = lb_emit_conv(p, right_ptr, t_rawptr); @@ -10255,8 +10273,6 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type)); lb_emit_store(p, gep0, m); - lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 1), lb_const_bool(p->module, t_bool, is_type_string(key_type))); - i64 entry_size = type_size_of (map_type->Map.entry_type); i64 entry_align = type_align_of (map_type->Map.entry_type); @@ -10266,6 +10282,7 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { i64 value_offset = type_offset_of(map_type->Map.entry_type, 3); i64 value_size = type_size_of (map_type->Map.value); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 1), lb_get_equal_proc_for_type(p->module, key_type)); lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 2), lb_const_int(p->module, t_int, entry_size)); lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 3), lb_const_int(p->module, t_int, entry_align)); lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 4), lb_const_int(p->module, t_uintptr, key_offset)); @@ -12204,7 +12221,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da 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_compare_proc_for_type(m, t).value; + vals[8] = lb_get_equal_proc_for_type(m, t).value; } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 09929c8cd..48ffd27a0 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -379,6 +379,8 @@ lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, To lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos); +lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type); +lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t); #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" #define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" diff --git a/src/types.cpp b/src/types.cpp index 7ca9a3cc2..75783f948 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -690,6 +690,8 @@ gb_global Type *t_map_header = nullptr; gb_global Type *t_vector_x86_mmx = nullptr; +gb_global Type *t_equal_proc = nullptr; + i64 type_size_of (Type *t); i64 type_align_of (Type *t); -- cgit v1.2.3 From 97c66c9c732af1e0735ee3f48a8af08b199bddf9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 15:27:53 +0000 Subject: Add `intrinsics.type_hasher_proc`; Make `map` work with generic hasher procedure --- core/intrinsics/intrinsics.odin | 3 +- core/runtime/core.odin | 5 +- core/runtime/dynamic_map_internal.odin | 64 +++++++----- src/check_expr.cpp | 25 ++++- src/check_type.cpp | 32 ++++-- src/checker.cpp | 8 +- src/checker_builtin_procs.hpp | 4 +- src/ir.cpp | 96 ++++++++++++++++- src/llvm_backend.cpp | 184 +++++++++++++++++++++++---------- src/llvm_backend.hpp | 4 +- src/types.cpp | 6 +- 11 files changed, 335 insertions(+), 96 deletions(-) (limited to 'src/types.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 3738b57dd..f817116f0 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -154,4 +154,5 @@ type_polymorphic_record_parameter_value :: proc($T: typeid, index: int) -> $V -- type_field_index_of :: proc($T: typeid, $name: string) -> uintptr --- -type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) --- +type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) --- +type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) --- diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 1cc564ff2..74b1338c7 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -42,7 +42,8 @@ Platform_Endianness :: enum u8 { Big = 2, } -Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; +Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; +Hasher_Proc :: distinct proc "contextless" (data: rawptr, seed: uintptr) -> uintptr; Type_Info_Struct_Soa_Kind :: enum u8 { None = 0, @@ -125,6 +126,8 @@ Type_Info_Map :: struct { key: ^Type_Info, value: ^Type_Info, generated_struct: ^Type_Info, + key_equal: Equal_Proc, + key_hasher: Hasher_Proc, }; Type_Info_Bit_Field :: struct { names: []string, diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 59661668f..99c2e92ee 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -11,31 +11,11 @@ Map_Hash :: struct { key_ptr: rawptr, // address of Map_Entry_Header.key } -__get_map_hash :: proc "contextless" (k: ^$K) -> Map_Hash { - key := k; - map_hash: Map_Hash; - - T :: intrinsics.type_core_type(K); - +__get_map_hash :: proc "contextless" (k: ^$K) -> (map_hash: Map_Hash) { + hasher := intrinsics.type_hasher_proc(K); map_hash.key_ptr = k; - - when intrinsics.type_is_integer(T) { - map_hash.hash = default_hash_ptr(key, size_of(T)); - } else when intrinsics.type_is_rune(T) { - map_hash.hash = default_hash_ptr(key, size_of(T)); - } else when intrinsics.type_is_pointer(T) { - map_hash.hash = default_hash_ptr(key, size_of(T)); - } else when intrinsics.type_is_float(T) { - map_hash.hash = default_hash_ptr(key, size_of(T)); - } else when intrinsics.type_is_string(T) { - #assert(T == string); - str := (^string)(key)^; - map_hash.hash = default_hash_string(str); - } else { - #panic("Unhandled map key type"); - } - - return map_hash; + map_hash.hash = hasher(k, 0); + return; } __get_map_hash_from_entry :: proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> (hash: Map_Hash) { @@ -96,6 +76,42 @@ default_hash_ptr :: inline proc "contextless" (data: rawptr, size: int) -> uintp return default_hash(transmute([]byte)(s)); } +_default_hasher_const :: inline proc "contextless" (data: rawptr, seed: uintptr, $N: uint) -> uintptr { + h := u64(seed) + 0xcbf29ce484222325; + p := uintptr(data); + inline for _ in 0.. uintptr { + h := u64(seed) + 0xcbf29ce484222325; + p := uintptr(data); + for _ in 0.. uintptr { return inline _default_hasher_const(data, seed, 1); } +default_hasher2 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 2); } +default_hasher4 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 4); } +default_hasher8 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 8); } +default_hasher16 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 16); } +default_hasher_string :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { + h := u64(seed) + 0xcbf29ce484222325; + str := (^[]byte)(data)^; + for b in str { + h = (h ~ u64(b)) * 0x100000001b3; + } + return uintptr(h); +} + + source_code_location_hash :: proc(s: Source_Code_Location) -> uintptr { hash := _fnv64a(transmute([]byte)s.file_path); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e2a6089b9..6ba25619f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -91,7 +91,7 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type); void set_procedure_abi_types(Type *type); void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); - +void add_map_key_type_dependencies(CheckerContext *ctx, Type *key); Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); @@ -6081,6 +6081,29 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->type = t_equal_proc; break; } + + case BuiltinProc_type_hasher_proc: + { + Operand op = {}; + Type *bt = check_type(c, ce->args[0]); + Type *type = base_type(bt); + if (type == nullptr || type == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (!is_type_valid_for_keys(type)) { + gbString t = type_to_string(type); + error(ce->args[0], "Expected a valid type for map keys for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + add_map_key_type_dependencies(c, type); + + operand->mode = Addressing_Value; + operand->type = t_hasher_proc; + break; + } } return true; diff --git a/src/check_type.cpp b/src/check_type.cpp index 2d2a5b3f0..758d1969b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2848,6 +2848,26 @@ void init_map_internal_types(Type *type) { type->Map.lookup_result_type = make_optional_ok_type(value); } +void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { + if (is_type_string(key)) { + add_package_dependency(ctx, "runtime", "default_hash_string"); + add_package_dependency(ctx, "runtime", "default_hasher_string"); + } else if (!is_type_polymorphic(key)) { + add_package_dependency(ctx, "runtime", "default_hash_ptr"); + GB_ASSERT_MSG(is_type_simple_compare(key), "%s", type_to_string(key)); + + i64 sz = type_size_of(key); + switch (sz) { + case 1: add_package_dependency(ctx, "runtime", "default_hasher1"); break; + case 2: add_package_dependency(ctx, "runtime", "default_hasher2"); break; + case 4: add_package_dependency(ctx, "runtime", "default_hasher4"); break; + case 8: add_package_dependency(ctx, "runtime", "default_hasher8"); break; + case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break; + default: GB_PANIC("unhandled hasher for key type: %s", type_to_string(key)); + } + } +} + void check_map_type(CheckerContext *ctx, Type *type, Ast *node) { GB_ASSERT(type->kind == Type_Map); ast_node(mt, MapType, node); @@ -2864,16 +2884,16 @@ void check_map_type(CheckerContext *ctx, Type *type, Ast *node) { gb_string_free(str); } } + if (type_size_of(key) == 0) { + gbString str = type_to_string(key); + error(node, "Invalid type of a key for a map of size 0, got '%s'", str); + gb_string_free(str); + } type->Map.key = key; type->Map.value = value; - if (is_type_string(key)) { - add_package_dependency(ctx, "runtime", "default_hash_string"); - } else { - add_package_dependency(ctx, "runtime", "default_hash_ptr"); - } - + add_map_key_type_dependencies(ctx, key); init_core_map_type(ctx->checker); init_map_internal_types(type); diff --git a/src/checker.cpp b/src/checker.cpp index ee3496fbf..901f5439c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -729,9 +729,13 @@ void init_universal(void) { { void set_procedure_abi_types(Type *type); - Type *args[2] = {t_rawptr, t_rawptr}; - t_equal_proc = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); + Type *equal_args[2] = {t_rawptr, t_rawptr}; + t_equal_proc = alloc_type_proc_from_types(equal_args, 2, t_bool, false, ProcCC_Contextless); set_procedure_abi_types(t_equal_proc); + + Type *hasher_args[2] = {t_rawptr, t_uintptr}; + t_hasher_proc = alloc_type_proc_from_types(hasher_args, 2, t_uintptr, false, ProcCC_Contextless); + set_procedure_abi_types(t_hasher_proc); } // Constants diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 9a5cdb1b8..b2157b3c1 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -184,6 +184,7 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_field_index_of, BuiltinProc_type_equal_proc, + BuiltinProc_type_hasher_proc, BuiltinProc__type_end, @@ -369,7 +370,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_hasher_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, }; diff --git a/src/ir.cpp b/src/ir.cpp index b1deda0b9..0c0a92667 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -24,7 +24,9 @@ struct irModule { Map entity_names; // Key: Entity * of the typename Map debug_info; // Key: Unique pointer Map anonymous_proc_lits; // Key: Ast * - Map compare_procs; // Key: Type * + + Map equal_procs; // Key: Type * + Map hasher_procs; // Key: Type * irDebugInfo * debug_compile_unit; Array debug_location_stack; @@ -4875,7 +4877,7 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { Type *pt = alloc_type_pointer(type); auto key = hash_type(type); - irValue **found = map_get(&m->compare_procs, key); + irValue **found = map_get(&m->equal_procs, key); if (found) { return *found; } @@ -4883,7 +4885,7 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { static u32 proc_index = 0; char buf[16] = {}; - isize n = gb_snprintf(buf, 16, "__$cmp%u", ++proc_index); + isize n = gb_snprintf(buf, 16, "__$equal%u", ++proc_index); char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); String proc_name = make_string_c(str); @@ -4894,6 +4896,7 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { irValue *p = ir_value_procedure(m, e, t_equal_proc, nullptr, body, proc_name); map_set(&m->values, hash_entity(e), p); string_map_set(&m->members, proc_name, p); + map_set(&m->equal_procs, key, p); irProcedure *proc = &p->Proc; proc->is_startup = true; @@ -4957,7 +4960,83 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { ir_end_procedure_body(proc); - map_set(&m->compare_procs, key, p); + return p; +} + + +irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { + Type *original_type = type; + type = base_type(type); + Type *pt = alloc_type_pointer(type); + + GB_ASSERT(is_type_valid_for_keys(type)); + + auto key = hash_type(type); + irValue **found = map_get(&m->hasher_procs, key); + if (found) { + return *found; + } + + static u32 proc_index = 0; + + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$hasher%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + + Ast *body = alloc_ast_node(nullptr, Ast_Invalid); + Entity *e = alloc_entity_procedure(nullptr, make_token_ident(proc_name), t_hasher_proc, 0); + e->Procedure.link_name = proc_name; + irValue *p = ir_value_procedure(m, e, t_hasher_proc, nullptr, body, proc_name); + map_set(&m->values, hash_entity(e), p); + string_map_set(&m->members, proc_name, p); + map_set(&m->hasher_procs, key, p); + + irProcedure *proc = &p->Proc; + proc->is_startup = true; + proc->ignore_dead_instr = true; + ir_begin_procedure_body(proc); + // ir_start_block(proc, proc->decl_block); + GB_ASSERT(proc->curr_block != nullptr); + + irValue *data = proc->params[0]; + irValue *seed = proc->params[1]; + + if (type->kind == Type_Struct) { + type_set_offsets(type); + + GB_PANIC("Type_Struct"); + } else if (is_type_string(type)) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + irValue *res = ir_emit_runtime_call(proc, "default_hasher_string", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); + + i64 sz = type_size_of(type); + char const *name = nullptr; + switch (sz) { + case 1: name = "default_hasher1"; break; + case 2: name = "default_hasher2"; break; + case 4: name = "default_hasher4"; break; + case 8: name = "default_hasher8"; break; + case 16: name = "default_hasher16"; break; + default: GB_PANIC("unhandled hasher for key type: %s", type_to_string(type)); + } + GB_ASSERT(name != nullptr); + + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + irValue *res = ir_emit_runtime_call(proc, name, args); + ir_emit(proc, ir_instr_return(proc, res)); + } + + + ir_end_procedure_body(proc); return p; } @@ -7589,6 +7668,8 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu case BuiltinProc_type_equal_proc: return ir_get_equal_proc_for_type(proc->module, ce->args[0]->tav.type); + case BuiltinProc_type_hasher_proc: + return ir_get_hasher_proc_for_type(proc->module, ce->args[0]->tav.type); } GB_PANIC("Unhandled built-in procedure"); @@ -11705,7 +11786,8 @@ void ir_init_module(irModule *m, Checker *c) { map_init(&m->debug_info, heap_allocator()); map_init(&m->entity_names, heap_allocator()); map_init(&m->anonymous_proc_lits, heap_allocator()); - map_init(&m->compare_procs, heap_allocator()); + map_init(&m->equal_procs, heap_allocator()); + map_init(&m->hasher_procs, heap_allocator()); array_init(&m->procs, heap_allocator()); array_init(&m->procs_to_generate, heap_allocator()); array_init(&m->foreign_library_paths, heap_allocator()); @@ -12447,10 +12529,14 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *key = ir_emit_struct_ep(proc, tag, 0); irValue *value = ir_emit_struct_ep(proc, tag, 1); irValue *generated_struct = ir_emit_struct_ep(proc, tag, 2); + irValue *key_equal = ir_emit_struct_ep(proc, tag, 3); + irValue *key_hasher = ir_emit_struct_ep(proc, tag, 4); ir_emit_store(proc, key, ir_get_type_info_ptr(proc, t->Map.key)); ir_emit_store(proc, value, ir_get_type_info_ptr(proc, t->Map.value)); ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, t->Map.generated_struct_type)); + ir_emit_store(proc, key_equal, ir_get_equal_proc_for_type(proc->module, t->Map.key)); + ir_emit_store(proc, key_hasher, ir_get_hasher_proc_for_type(proc->module, t->Map.key)); break; } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 39b4030af..bc024ab8b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -8559,6 +8559,9 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, 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); } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); @@ -9169,84 +9172,156 @@ lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) { LLVMTypeRef ptr_type = lb_type(m, pt); auto key = hash_type(type); - lbProcedure **found = map_get(&m->compare_procs, key); + lbProcedure **found = map_get(&m->equal_procs, key); lbProcedure *compare_proc = nullptr; if (found) { compare_proc = *found; - } else { - static u32 proc_index = 0; + GB_ASSERT(compare_proc != nullptr); + return {compare_proc->value, compare_proc->type}; + } - char buf[16] = {}; - isize n = gb_snprintf(buf, 16, "__$cmp%u", ++proc_index); - char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); - String proc_name = make_string_c(str); + static u32 proc_index = 0; - lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); - lb_begin_procedure_body(p); + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$equal%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); + map_set(&m->equal_procs, key, p); + lb_begin_procedure_body(p); + + LLVMValueRef x = LLVMGetParam(p->value, 0); + LLVMValueRef y = LLVMGetParam(p->value, 1); + x = LLVMBuildPointerCast(p->builder, x, ptr_type, ""); + y = LLVMBuildPointerCast(p->builder, y, ptr_type, ""); + lbValue lhs = {x, pt}; + lbValue rhs = {y, pt}; + + + lbBlock *block_same_ptr = lb_create_block(p, "same_ptr"); + lbBlock *block_diff_ptr = lb_create_block(p, "diff_ptr"); + + lbValue same_ptr = lb_emit_comp(p, Token_CmpEq, lhs, rhs); + lb_emit_if(p, same_ptr, block_same_ptr, block_diff_ptr); + lb_start_block(p, block_same_ptr); + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); + + lb_start_block(p, block_diff_ptr); + + if (type->kind == Type_Struct) { + type_set_offsets(type); - LLVMValueRef x = LLVMGetParam(p->value, 0); - LLVMValueRef y = LLVMGetParam(p->value, 1); - x = LLVMBuildPointerCast(p->builder, x, ptr_type, ""); - y = LLVMBuildPointerCast(p->builder, y, ptr_type, ""); - lbValue lhs = {x, pt}; - lbValue rhs = {y, pt}; + lbBlock *block_false = lb_create_block(p, "bfalse"); + lbValue res = lb_const_bool(m, t_bool, true); + for_array(i, type->Struct.fields) { + lbBlock *next_block = lb_create_block(p, "btrue"); - lbBlock *block_same_ptr = lb_create_block(p, "same_ptr"); - lbBlock *block_diff_ptr = lb_create_block(p, "diff_ptr"); + lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); + lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); + lbValue left = lb_emit_load(p, pleft); + lbValue right = lb_emit_load(p, pright); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + + lb_emit_if(p, ok, next_block, block_false); + + lb_emit_jump(p, next_block); + lb_start_block(p, next_block); + } - lbValue same_ptr = lb_emit_comp(p, Token_CmpEq, lhs, rhs); - lb_emit_if(p, same_ptr, block_same_ptr, block_diff_ptr); - lb_start_block(p, block_same_ptr); LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); - lb_start_block(p, block_diff_ptr); + lb_start_block(p, block_false); - if (type->kind == Type_Struct) { - type_set_offsets(type); + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); + } else { + lbValue left = lb_emit_load(p, lhs); + lbValue right = lb_emit_load(p, rhs); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + ok = lb_emit_conv(p, ok, t_bool); + LLVMBuildRet(p->builder, ok.value); + } - lbBlock *block_false = lb_create_block(p, "bfalse"); - lbValue res = lb_const_bool(m, t_bool, true); + lb_end_procedure_body(p); - for_array(i, type->Struct.fields) { - lbBlock *next_block = lb_create_block(p, "btrue"); + compare_proc = p; + return {compare_proc->value, compare_proc->type}; +} + +lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { + Type *original_type = type; + type = base_type(type); + GB_ASSERT(is_type_valid_for_keys(type)); - lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); - lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); - lbValue left = lb_emit_load(p, pleft); - lbValue right = lb_emit_load(p, pright); - lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + Type *pt = alloc_type_pointer(type); + LLVMTypeRef ptr_type = lb_type(m, pt); - lb_emit_if(p, ok, next_block, block_false); + auto key = hash_type(type); + lbProcedure **found = map_get(&m->hasher_procs, key); + lbProcedure *hasher_proc = nullptr; + if (found) { + hasher_proc = *found; + GB_ASSERT(hasher_proc != nullptr); + return {hasher_proc->value, hasher_proc->type}; + } - lb_emit_jump(p, next_block); - lb_start_block(p, next_block); - } + static u32 proc_index = 0; - LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$hasher%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); - lb_start_block(p, block_false); + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_hasher_proc); + map_set(&m->hasher_procs, key, p); + lb_begin_procedure_body(p); - LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); - } else { - lbValue left = lb_emit_load(p, lhs); - lbValue right = lb_emit_load(p, rhs); - lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); - ok = lb_emit_conv(p, ok, t_bool); - LLVMBuildRet(p->builder, ok.value); - } + LLVMValueRef x = LLVMGetParam(p->value, 0); + LLVMValueRef y = LLVMGetParam(p->value, 1); + lbValue data = {x, t_rawptr}; + lbValue seed = {y, t_uintptr}; - lb_end_procedure_body(p); + if (type->kind == Type_Struct) { + type_set_offsets(type); - map_set(&m->compare_procs, key, p); + GB_PANIC("Type_Struct"); + } else if (is_type_string(type)) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + lbValue res = lb_emit_runtime_call(p, "default_hasher_string", args); + LLVMBuildRet(p->builder, res.value); + } else { + GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); + + i64 sz = type_size_of(type); + char const *name = nullptr; + switch (sz) { + case 1: name = "default_hasher1"; break; + case 2: name = "default_hasher2"; break; + case 4: name = "default_hasher4"; break; + case 8: name = "default_hasher8"; break; + case 16: name = "default_hasher16"; break; + default: GB_PANIC("unhandled hasher for key type: %s", type_to_string(type)); + } + GB_ASSERT(name != nullptr); - compare_proc = p; + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + lbValue res = lb_emit_runtime_call(p, name, args); + LLVMBuildRet(p->builder, res.value); } - GB_ASSERT(compare_proc != nullptr); - return {compare_proc->value, compare_proc->type}; + lb_end_procedure_body(p); + + hasher_proc = p; + return {hasher_proc->value, hasher_proc->type}; } + + 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); @@ -11571,7 +11646,8 @@ void lb_init_module(lbModule *m, Checker *c) { string_map_init(&m->const_strings, a); map_init(&m->anonymous_proc_lits, a); map_init(&m->function_type_map, a); - map_init(&m->compare_procs, a); + map_init(&m->equal_procs, a); + map_init(&m->hasher_procs, a); array_init(&m->procedures_to_generate, a); array_init(&m->foreign_library_paths, a); @@ -12307,10 +12383,12 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr); init_map_internal_types(t); - LLVMValueRef vals[3] = { + 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 = {}; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 48ffd27a0..52b2b1e0f 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -106,7 +106,8 @@ struct lbModule { Map anonymous_proc_lits; // Key: Ast * Map function_type_map; // Key: Type * - Map compare_procs; // Key: Type * + Map equal_procs; // Key: Type * + Map hasher_procs; // Key: Type * u32 global_array_index; u32 global_generated_index; @@ -380,6 +381,7 @@ lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, To lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos); lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type); +lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type); lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t); #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" diff --git a/src/types.cpp b/src/types.cpp index 75783f948..5c8db71e1 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -690,7 +690,8 @@ gb_global Type *t_map_header = nullptr; gb_global Type *t_vector_x86_mmx = nullptr; -gb_global Type *t_equal_proc = nullptr; +gb_global Type *t_equal_proc = nullptr; +gb_global Type *t_hasher_proc = nullptr; i64 type_size_of (Type *t); @@ -1949,6 +1950,9 @@ bool is_type_simple_compare(Type *t) { if (t->Basic.flags & BasicFlag_SimpleCompare) { return true; } + if (t->Basic.kind == Basic_typeid) { + return true; + } return false; case Type_Pointer: -- cgit v1.2.3 From 1dfe0cdd1de44d6c8b94c4e902a731655f8972c9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 15:50:29 +0000 Subject: Simplify hashing approach `map` --- core/runtime/core.odin | 6 ++-- core/runtime/dynamic_map_internal.odin | 10 +++++++ src/check_type.cpp | 6 ++-- src/ir.cpp | 50 +++++++++++----------------------- src/llvm_backend.cpp | 44 ++++++++++-------------------- src/types.cpp | 3 ++ 6 files changed, 51 insertions(+), 68 deletions(-) (limited to 'src/types.cpp') diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 74b1338c7..b0c76720a 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -42,8 +42,10 @@ Platform_Endianness :: enum u8 { Big = 2, } -Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; -Hasher_Proc :: distinct proc "contextless" (data: rawptr, seed: uintptr) -> uintptr; +// Procedure type to test whether two values of the same type are equal +Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; +// Procedure type to hash a value, default seed value is 0 +Hasher_Proc :: distinct proc "contextless" (data: rawptr, seed: uintptr = 0) -> uintptr; Type_Info_Struct_Soa_Kind :: enum u8 { None = 0, diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 99c2e92ee..8ae366db3 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -110,6 +110,16 @@ default_hasher_string :: proc "contextless" (data: rawptr, seed: uintptr) -> uin } return uintptr(h); } +default_hasher_cstring :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { + h := u64(seed) + 0xcbf29ce484222325; + ptr := (^uintptr)(data)^; + for (^byte)(ptr)^ != 0 { + b := (^byte)(ptr)^; + h = (h ~ u64(b)) * 0x100000001b3; + ptr += 1; + } + return uintptr(h); +} diff --git a/src/check_type.cpp b/src/check_type.cpp index 758d1969b..8da410fa9 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2849,11 +2849,11 @@ void init_map_internal_types(Type *type) { } void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { - if (is_type_string(key)) { - add_package_dependency(ctx, "runtime", "default_hash_string"); + if (is_type_cstring(key)) { + add_package_dependency(ctx, "runtime", "default_hasher_cstring"); + } else if (is_type_string(key)) { add_package_dependency(ctx, "runtime", "default_hasher_string"); } else if (!is_type_polymorphic(key)) { - add_package_dependency(ctx, "runtime", "default_hash_ptr"); GB_ASSERT_MSG(is_type_simple_compare(key), "%s", type_to_string(key)); i64 sz = type_size_of(key); diff --git a/src/ir.cpp b/src/ir.cpp index 0c0a92667..90b0eda2a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -532,6 +532,7 @@ irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, Ast *expr, i void ir_begin_procedure_body(irProcedure *proc); void ir_end_procedure_body(irProcedure *proc); irValue *ir_get_equal_proc_for_type(irModule *m, Type *type); +irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type); irAddr ir_addr(irValue *addr) { @@ -3620,43 +3621,18 @@ irValue *ir_gen_map_hash(irProcedure *proc, irValue *key, Type *key_type) { Type *t = base_type(ir_type(key)); key = ir_emit_conv(proc, key, key_type); - if (is_type_string(t)) { - irValue *str = ir_emit_conv(proc, key, t_string); - irValue *hashed_str = nullptr; - - if (str->kind == irValue_Constant) { - ExactValue ev = str->Constant.value; - GB_ASSERT(ev.kind == ExactValue_String); - u64 hs = fnv64a(ev.value_string.text, ev.value_string.len); - if (build_context.word_size == 4) { - hs &= 0xffffffff; - } - hashed_str = ir_value_constant(t_uintptr, exact_value_u64(hs)); - } else { - auto args = array_make(ir_allocator(), 1); - args[0] = str; - hashed_str = ir_emit_runtime_call(proc, "default_hash_string", args); - } - ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str); - } else { - i64 sz = type_size_of(t); - GB_ASSERT(sz <= 8); - if (sz != 0) { - auto args = array_make(ir_allocator(), 2); - args[0] = ir_address_from_load_or_generate_local(proc, key); - args[1] = ir_const_int(sz); - irValue *hash = ir_emit_runtime_call(proc, "default_hash_ptr", args); - - irValue *hash_ptr = ir_emit_struct_ep(proc, v, 0); - ir_emit_store(proc, hash_ptr, hash); - } - } - irValue *key_ptr = ir_address_from_load_or_generate_local(proc, key); key_ptr = ir_emit_conv(proc, key_ptr, t_rawptr); - irValue *key_data = ir_emit_struct_ep(proc, v, 1); - ir_emit_store(proc, key_data, key_ptr); + irValue *hasher = ir_get_hasher_proc_for_type(proc->module, key_type); + + auto args = array_make(permanent_allocator(), 2); + args[0] = key_ptr; + args[1] = ir_value_constant(t_uintptr, exact_value_i64(0)); + irValue *hashed_key = ir_emit_call(proc, hasher, args); + + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_key); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), key_ptr); return ir_emit_load(proc, v); } @@ -5007,6 +4983,12 @@ irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { type_set_offsets(type); GB_PANIC("Type_Struct"); + } else if (is_type_cstring(type)) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + irValue *res = ir_emit_runtime_call(proc, "default_hasher_cstring", args); + ir_emit(proc, ir_instr_return(proc, res)); } else if (is_type_string(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index bc024ab8b..bea0beab9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9286,6 +9286,12 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { type_set_offsets(type); GB_PANIC("Type_Struct"); + } else if (is_type_cstring(type)) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + lbValue res = lb_emit_runtime_call(p, "default_hasher_cstring", args); + LLVMBuildRet(p->builder, res.value); } else if (is_type_string(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; @@ -10375,37 +10381,17 @@ lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { Type *t = base_type(key.type); key = lb_emit_conv(p, key, key_type); - if (is_type_string(t)) { - lbValue str = lb_emit_conv(p, key, t_string); - lbValue hashed_str = {}; - - if (lb_is_const(str)) { - String v = lb_get_const_string(p->module, str); - u64 hs = fnv64a(v.text, v.len); - if (build_context.word_size == 4) { - hs &= 0xffffffff; - } - hashed_str = lb_const_int(p->module, t_uintptr, hs); - } else { - auto args = array_make(permanent_allocator(), 1); - args[0] = str; - hashed_str = lb_emit_runtime_call(p, "default_hash_string", args); - } - lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_str); - } else { - i64 sz = type_size_of(t); - GB_ASSERT(sz <= 8); - if (sz != 0) { - auto args = array_make(permanent_allocator(), 2); - args[0] = lb_address_from_load_or_generate_local(p, key); - args[1] = lb_const_int(p->module, t_int, sz); - lbValue hash = lb_emit_runtime_call(p, "default_hash_ptr", args); - lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hash); - } - } - lbValue key_ptr = lb_address_from_load_or_generate_local(p, key); key_ptr = lb_emit_conv(p, key_ptr, t_rawptr); + + lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type); + + auto args = array_make(permanent_allocator(), 2); + args[0] = key_ptr; + args[1] = lb_const_int(p->module, t_uintptr, 0); + lbValue hashed_key = lb_emit_call(p, hasher, args); + + lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_key); lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr); return lb_addr_load(p, v); diff --git a/src/types.cpp b/src/types.cpp index 5c8db71e1..26f187a62 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1922,6 +1922,9 @@ bool is_type_comparable(Type *t) { return is_type_comparable(t->Opaque.elem); case Type_Struct: + if (type_size_of(t) == 0) { + return false; + } if (t->Struct.is_raw_union) { return is_type_simple_compare(t); } -- cgit v1.2.3 From 57f5976ac1b5416093ef25d725c30ae5ff270809 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 16:12:21 +0000 Subject: Support map keys for simple compare types --- core/runtime/dynamic_map_internal.odin | 4 +++- src/check_type.cpp | 5 ++++- src/ir.cpp | 10 ++++++++-- src/llvm_backend.cpp | 10 ++++++++-- src/types.cpp | 4 +++- 5 files changed, 26 insertions(+), 7 deletions(-) (limited to 'src/types.cpp') diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 8ae366db3..7d5ff017b 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -76,6 +76,7 @@ default_hash_ptr :: inline proc "contextless" (data: rawptr, size: int) -> uintp return default_hash(transmute([]byte)(s)); } +@(private) _default_hasher_const :: inline proc "contextless" (data: rawptr, seed: uintptr, $N: uint) -> uintptr { h := u64(seed) + 0xcbf29ce484222325; p := uintptr(data); @@ -86,7 +87,8 @@ _default_hasher_const :: inline proc "contextless" (data: rawptr, seed: uintptr, } return uintptr(h); } -_default_hasher_n :: inline proc "contextless" (data: rawptr, seed: uintptr, N: int) -> uintptr { + +default_hasher_n :: inline proc "contextless" (data: rawptr, seed: uintptr, N: int) -> uintptr { h := u64(seed) + 0xcbf29ce484222325; p := uintptr(data); for _ in 0..kind == Type_Struct) { type_set_offsets(type); - - GB_PANIC("Type_Struct"); + GB_ASSERT(is_type_simple_compare(type)); + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index a4cd32efa..4fe98bfcf 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9284,8 +9284,14 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { if (type->kind == Type_Struct) { type_set_offsets(type); - - GB_PANIC("Type_Struct"); + GB_ASSERT(is_type_simple_compare(type)); + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/types.cpp b/src/types.cpp index 26f187a62..f8f7dd66e 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -964,7 +964,6 @@ bool is_type_valid_for_keys(Type *t); Type *alloc_type_map(i64 count, Type *key, Type *value) { if (key != nullptr) { - GB_ASSERT(is_type_valid_for_keys(key)); GB_ASSERT(value != nullptr); } Type *t = alloc_type(Type_Map); @@ -1558,6 +1557,9 @@ bool is_type_valid_for_keys(Type *t) { if (is_type_typeid(t)) { return true; } + if (is_type_simple_compare(t)) { + return true; + } return false; } -- cgit v1.2.3 From 5ab7ec5b16b08584764b1a02441299e18328df1e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 16:37:19 +0000 Subject: Support any comparable type for map keys --- src/check_type.cpp | 42 ++++++++++++++++------ src/ir.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++----- src/llvm_backend.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++++++----- src/types.cpp | 6 ++++ 4 files changed, 214 insertions(+), 28 deletions(-) (limited to 'src/types.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 10ffe076c..9c8308757 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2849,26 +2849,48 @@ void init_map_internal_types(Type *type) { } void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { + key = core_type(key); + if (is_type_cstring(key)) { add_package_dependency(ctx, "runtime", "default_hasher_cstring"); } else if (is_type_string(key)) { add_package_dependency(ctx, "runtime", "default_hasher_string"); } else if (!is_type_polymorphic(key)) { - if (!is_type_simple_compare(key)) { + if (!is_type_comparable(key)) { return; } - if (is_type_struct(key)) { + if (key->kind == Type_Struct) { add_package_dependency(ctx, "runtime", "default_hasher_n"); - } + if (!is_type_simple_compare(key)) { + for_array(i, key->Struct.fields) { + Entity *field = key->Struct.fields[i]; + add_map_key_type_dependencies(ctx, field->type); + } + } + } else if (key->kind == Type_EnumeratedArray) { + add_package_dependency(ctx, "runtime", "default_hasher_n"); + if (!is_type_simple_compare(key->EnumeratedArray.elem)) { + add_map_key_type_dependencies(ctx, key->EnumeratedArray.elem); + } + } else if (key->kind == Type_Array) { + add_package_dependency(ctx, "runtime", "default_hasher_n"); + if (!is_type_simple_compare(key->Array.elem)) { + add_map_key_type_dependencies(ctx, key->Array.elem); + } + } else { + if (!is_type_simple_compare(key)) { + GB_PANIC("HERE"); + } - i64 sz = type_size_of(key); - switch (sz) { - case 1: add_package_dependency(ctx, "runtime", "default_hasher1"); break; - case 2: add_package_dependency(ctx, "runtime", "default_hasher2"); break; - case 4: add_package_dependency(ctx, "runtime", "default_hasher4"); break; - case 8: add_package_dependency(ctx, "runtime", "default_hasher8"); break; - case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break; + i64 sz = type_size_of(key); + switch (sz) { + case 1: add_package_dependency(ctx, "runtime", "default_hasher1"); break; + case 2: add_package_dependency(ctx, "runtime", "default_hasher2"); break; + case 4: add_package_dependency(ctx, "runtime", "default_hasher4"); break; + case 8: add_package_dependency(ctx, "runtime", "default_hasher8"); break; + case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break; + } } } } diff --git a/src/ir.cpp b/src/ir.cpp index 84f943eda..7e3050825 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4967,7 +4967,7 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { Type *original_type = type; - type = base_type(type); + type = core_type(type); Type *pt = alloc_type_pointer(type); GB_ASSERT(is_type_valid_for_keys(type)); @@ -5006,14 +5006,92 @@ irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { if (type->kind == Type_Struct) { type_set_offsets(type); - GB_ASSERT(is_type_simple_compare(type)); - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = ir_const_int(sz); - irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); - ir_emit(proc, ir_instr_return(proc, res)); + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + data = ir_emit_conv(proc, data, t_u8_ptr); + + auto args = array_make(permanent_allocator(), 2); + for_array(i, type->Struct.fields) { + i64 offset = type->Struct.offsets[i]; + Entity *field = type->Struct.fields[i]; + irValue *field_hasher = ir_get_hasher_proc_for_type(m, field->type); + irValue *ptr = ir_emit_ptr_offset(proc, data, ir_const_uintptr(offset)); + + args[0] = ptr; + args[1] = seed; + seed = ir_emit_call(proc, field_hasher, args); + } + ir_emit(proc, ir_instr_return(proc, seed)); + } + } else if (type->kind == Type_Array) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + irValue *pres = ir_add_local_generated(proc, t_uintptr, false); + ir_emit_store(proc, pres, seed); + + auto args = array_make(permanent_allocator(), 2); + irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem); + + auto loop_data = ir_loop_start(proc, type->Array.count, t_i32); + + data = ir_emit_conv(proc, data, pt); + + irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx); + args[0] = ptr; + args[1] = ir_emit_load(proc, pres); + irValue *new_seed = ir_emit_call(proc, elem_hasher, args); + ir_emit_store(proc, pres, new_seed); + + ir_loop_end(proc, loop_data); + + irValue *res = ir_emit_load(proc, pres); + ir_emit(proc, ir_instr_return(proc, res)); + } + } else if (type->kind == Type_EnumeratedArray) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + irValue *pres = ir_add_local_generated(proc, t_uintptr, false); + ir_emit_store(proc, pres, seed); + + auto args = array_make(permanent_allocator(), 2); + irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem); + + auto loop_data = ir_loop_start(proc, type->Array.count, t_i32); + + data = ir_emit_conv(proc, data, pt); + + irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx); + args[0] = ptr; + args[1] = ir_emit_load(proc, pres); + irValue *new_seed = ir_emit_call(proc, elem_hasher, args); + ir_emit_store(proc, pres, new_seed); + + ir_loop_end(proc, loop_data); + + irValue *res = ir_emit_load(proc, pres); + ir_emit(proc, ir_instr_return(proc, res)); + } } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 4fe98bfcf..140d01292 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9251,7 +9251,7 @@ lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) { lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { Type *original_type = type; - type = base_type(type); + type = core_type(type); GB_ASSERT(is_type_valid_for_keys(type)); Type *pt = alloc_type_pointer(type); @@ -9284,14 +9284,94 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { if (type->kind == Type_Struct) { type_set_offsets(type); - GB_ASSERT(is_type_simple_compare(type)); - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = lb_const_int(m, t_int, sz); - lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); - LLVMBuildRet(p->builder, res.value); + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); + } else { + data = lb_emit_conv(p, data, t_u8_ptr); + + auto args = array_make(permanent_allocator(), 2); + for_array(i, type->Struct.fields) { + i64 offset = type->Struct.offsets[i]; + Entity *field = type->Struct.fields[i]; + lbValue field_hasher = lb_get_hasher_proc_for_type(m, field->type); + lbValue ptr = lb_emit_ptr_offset(p, data, lb_const_int(m, t_uintptr, offset)); + + args[0] = ptr; + args[1] = seed; + seed = lb_emit_call(p, field_hasher, args); + } + LLVMBuildRet(p->builder, seed.value); + } + } else if (type->kind == Type_Array) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); + } else { + lbAddr pres = lb_add_local_generated(p, t_uintptr, false); + lb_addr_store(p, pres, seed); + + auto args = array_make(permanent_allocator(), 2); + lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->Array.elem); + + auto loop_data = lb_loop_start(p, type->Array.count, t_i32); + + data = lb_emit_conv(p, data, pt); + + lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); + args[0] = ptr; + args[1] = lb_addr_load(p, pres); + lbValue new_seed = lb_emit_call(p, elem_hasher, args); + lb_addr_store(p, pres, new_seed); + + lb_loop_end(p, loop_data); + + lbValue res = lb_addr_load(p, pres); + LLVMBuildRet(p->builder, res.value); + } + } else if (type->kind == Type_EnumeratedArray) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); + } else { + lbAddr res = lb_add_local_generated(p, t_uintptr, false); + lb_addr_store(p, res, seed); + + auto args = array_make(permanent_allocator(), 2); + lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->EnumeratedArray.elem); + + auto loop_data = lb_loop_start(p, type->EnumeratedArray.count, t_i32); + + data = lb_emit_conv(p, data, pt); + + lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); + args[0] = ptr; + args[1] = lb_addr_load(p, res); + lbValue new_seed = lb_emit_call(p, elem_hasher, args); + lb_addr_store(p, res, new_seed); + + lb_loop_end(p, loop_data); + + lbValue vres = lb_addr_load(p, res); + LLVMBuildRet(p->builder, vres.value); + } + + } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/types.cpp b/src/types.cpp index f8f7dd66e..df87cb645 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1542,6 +1542,8 @@ bool is_type_valid_for_keys(Type *t) { if (is_type_untyped(t)) { return false; } + return is_type_comparable(t); +#if 0 if (is_type_integer(t)) { return true; } @@ -1560,8 +1562,12 @@ bool is_type_valid_for_keys(Type *t) { if (is_type_simple_compare(t)) { return true; } + if (is_type_comparable(t)) { + return true; + } return false; +#endif } bool is_type_valid_bit_set_elem(Type *t) { -- cgit v1.2.3