diff options
Diffstat (limited to 'src/llvm_backend_general.cpp')
| -rw-r--r-- | src/llvm_backend_general.cpp | 422 |
1 files changed, 293 insertions, 129 deletions
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b61439238..6f98458fa 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -56,6 +56,7 @@ void lb_init_module(lbModule *m, Checker *c) { gbAllocator a = heap_allocator(); map_init(&m->types, a); + map_init(&m->func_raw_types, a); map_init(&m->struct_field_remapping, a); map_init(&m->values, a); map_init(&m->soa_values, a); @@ -174,7 +175,8 @@ struct lbLoopData { struct lbCompoundLitElemTempData { Ast * expr; lbValue value; - i32 elem_index; + i64 elem_index; + i64 elem_length; lbValue gep; }; @@ -211,6 +213,45 @@ void lb_loop_end(lbProcedure *p, lbLoopData const &data) { } +// This emits a GEP at 0, index +lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index) { + GB_ASSERT(is_type_pointer(value.type)); + Type *type = type_deref(value.type); + + LLVMValueRef indices[2] = { + LLVMConstInt(lb_type(p->module, t_int), 0, false), + LLVMConstInt(lb_type(p->module, t_int), cast(unsigned long long)index, false), + }; + LLVMTypeRef llvm_type = lb_type(p->module, type); + lbValue res = {}; + Type *ptr = base_array_type(type); + res.type = alloc_type_pointer(ptr); + if (LLVMIsConstant(value.value)) { + res.value = LLVMConstGEP2(llvm_type, value.value, indices, gb_count_of(indices)); + } else { + res.value = LLVMBuildGEP2(p->builder, llvm_type, value.value, indices, gb_count_of(indices), ""); + } + return res; +} +// This emits a GEP at 0, index +lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index) { + GB_ASSERT(is_type_pointer(value.type)); + GB_ASSERT(LLVMIsConstant(value.value)); + Type *type = type_deref(value.type); + + LLVMValueRef indices[2] = { + LLVMConstInt(lb_type(m, t_int), 0, false), + LLVMConstInt(lb_type(m, t_int), cast(unsigned long long)index, false), + }; + lbValue res = {}; + Type *ptr = base_array_type(type); + res.type = alloc_type_pointer(ptr); + res.value = LLVMConstGEP2(lb_type(m, type), value.value, indices, gb_count_of(indices)); + return res; +} + + + LLVMValueRef llvm_zero(lbModule *m) { return LLVMConstInt(lb_type(m, t_int), 0, false); } @@ -341,9 +382,6 @@ Type *lb_addr_type(lbAddr const &addr) { } return type_deref(addr.addr.type); } -LLVMTypeRef lb_addr_lb_type(lbAddr const &addr) { - return LLVMGetElementType(LLVMTypeOf(addr.addr.value)); -} lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { if (addr.addr.value == nullptr) { @@ -530,6 +568,13 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu } } +unsigned lb_try_get_alignment(LLVMValueRef addr_ptr, unsigned default_alignment) { + if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) { + return LLVMGetAlignment(addr_ptr); + } + return default_alignment; +} + bool lb_try_update_alignment(LLVMValueRef addr_ptr, unsigned alignment) { if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) { if (LLVMGetAlignment(addr_ptr) < alignment) { @@ -546,6 +591,9 @@ bool lb_try_update_alignment(lbValue ptr, unsigned alignment) { return lb_try_update_alignment(ptr.value, alignment); } +bool lb_can_try_to_inline_array_arith(Type *t) { + return type_size_of(t) <= build_context.max_simd_align; +} bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) { Type *array_type = base_type(type_deref(ptr.type)); @@ -554,7 +602,7 @@ bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) { Type *elem_type = base_array_type(array_type); // TODO(bill): Determine what is the correct limit for doing vector arithmetic - if (type_size_of(array_type) <= build_context.max_align && + if (lb_can_try_to_inline_array_arith(array_type) && is_type_valid_vector_elem(elem_type)) { // Try to treat it like a vector if possible bool possible = false; @@ -854,8 +902,12 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { Type *a = type_deref(ptr.type); if (LLVMIsNull(value.value)) { - LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value)); - if (lb_sizeof(src_t) <= lb_max_zero_init_size()) { + LLVMTypeRef src_t = llvm_addr_type(p->module, ptr); + if (is_type_proc(a)) { + LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr); + LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0); + LLVMBuildStore(p->builder, LLVMConstNull(rawptr_type), LLVMBuildBitCast(p->builder, ptr.value, rawptr_ptr_type, "")); + } else if (lb_sizeof(src_t) <= lb_max_zero_init_size()) { LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value); } else { lb_mem_zero_ptr(p, ptr.value, a, 1); @@ -873,25 +925,46 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { enum {MAX_STORE_SIZE = 64}; - if (LLVMIsALoadInst(value.value) && lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) { - LLVMValueRef dst_ptr = ptr.value; - LLVMValueRef src_ptr = LLVMGetOperand(value.value, 0); - src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), ""); - - LLVMBuildMemMove(p->builder, - dst_ptr, 1, - src_ptr, 1, - LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false)); - return; + if (lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) { + if (LLVMIsALoadInst(value.value)) { + LLVMValueRef dst_ptr = ptr.value; + LLVMValueRef src_ptr_original = LLVMGetOperand(value.value, 0); + LLVMValueRef src_ptr = LLVMBuildPointerCast(p->builder, src_ptr_original, LLVMTypeOf(dst_ptr), ""); + + LLVMBuildMemMove(p->builder, + dst_ptr, lb_try_get_alignment(dst_ptr, 1), + src_ptr, lb_try_get_alignment(src_ptr_original, 1), + LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false)); + return; + } else if (LLVMIsConstant(value.value)) { + lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr); + LLVMValueRef global_data = addr.addr.value; + // make it truly private data + LLVMSetLinkage(global_data, LLVMPrivateLinkage); + LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); + LLVMSetGlobalConstant(global_data, true); + + LLVMValueRef dst_ptr = ptr.value; + LLVMValueRef src_ptr = global_data; + src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), ""); + + LLVMBuildMemMove(p->builder, + dst_ptr, lb_try_get_alignment(dst_ptr, 1), + src_ptr, lb_try_get_alignment(global_data, 1), + LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false)); + return; + } } if (lb_is_type_proc_recursive(a)) { // NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be // stored as regular pointer with no procedure information - LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value)); - LLVMValueRef v = LLVMBuildPointerCast(p->builder, value.value, src_t, ""); - LLVMBuildStore(p->builder, v, ptr.value); + LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr); + LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0); + LLVMBuildStore(p->builder, + LLVMBuildPointerCast(p->builder, value.value, rawptr_type, ""), + LLVMBuildPointerCast(p->builder, ptr.value, rawptr_ptr_type, "")); } else { Type *ca = core_type(a); if (ca->kind == Type_Basic || ca->kind == Type_Proc) { @@ -904,8 +977,8 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { } } -LLVMTypeRef llvm_addr_type(lbValue addr_val) { - return LLVMGetElementType(LLVMTypeOf(addr_val.value)); +LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val) { + return lb_type(module, type_deref(addr_val.type)); } lbValue lb_emit_load(lbProcedure *p, lbValue value) { @@ -914,12 +987,18 @@ lbValue lb_emit_load(lbProcedure *p, lbValue value) { Type *vt = base_type(value.type); GB_ASSERT(vt->kind == Type_MultiPointer); Type *t = vt->MultiPointer.elem; - LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); + LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, ""); return lbValue{v, t}; + } else if (is_type_soa_pointer(value.type)) { + lbValue ptr = lb_emit_struct_ev(p, value, 0); + lbValue idx = lb_emit_struct_ev(p, value, 1); + lbAddr addr = lb_addr_soa_variable(ptr, idx, nullptr); + return lb_addr_load(p, addr); } + GB_ASSERT(is_type_pointer(value.type)); Type *t = type_deref(value.type); - LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); + LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, ""); return lbValue{v, t}; } @@ -1184,12 +1263,12 @@ lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { Type *tag_type = union_tag_type(ut); - LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value)); + LLVMTypeRef uvt = llvm_addr_type(p->module, u); unsigned element_count = LLVMCountStructElementTypes(uvt); GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); lbValue tag_ptr = {}; - tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 1, ""); + tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, ""); tag_ptr.type = alloc_type_pointer(tag_type); return tag_ptr; } @@ -1413,6 +1492,116 @@ String lb_get_entity_name(lbModule *m, Entity *e, String default_name) { } +LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) { + Type *original_type = type; + type = base_type(original_type); + GB_ASSERT(type->kind == Type_Proc); + + LLVMTypeRef *found = map_get(&m->func_raw_types, type); + if (found) { + return *found; + } + + unsigned param_count = 0; + if (type->Proc.calling_convention == ProcCC_Odin) { + param_count += 1; + } + + if (type->Proc.param_count != 0) { + GB_ASSERT(type->Proc.params->kind == Type_Tuple); + for_array(i, type->Proc.params->Tuple.variables) { + Entity *e = type->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + if (e->flags & EntityFlag_CVarArg) { + continue; + } + param_count += 1; + } + } + m->internal_type_level += 1; + defer (m->internal_type_level -= 1); + + LLVMTypeRef ret = nullptr; + LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count); + if (type->Proc.result_count != 0) { + Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); + ret = lb_type(m, single_ret); + if (ret != nullptr) { + if (is_type_boolean(single_ret) && + is_calling_convention_none(type->Proc.calling_convention) && + type_size_of(single_ret) <= 1) { + ret = LLVMInt1TypeInContext(m->ctx); + } + } + } + + unsigned param_index = 0; + if (type->Proc.param_count != 0) { + GB_ASSERT(type->Proc.params->kind == Type_Tuple); + for_array(i, type->Proc.params->Tuple.variables) { + Entity *e = type->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + if (e->flags & EntityFlag_CVarArg) { + continue; + } + Type *e_type = reduce_tuple_to_single_type(e->type); + + LLVMTypeRef param_type = nullptr; + if (e->flags & EntityFlag_ByPtr) { + param_type = lb_type(m, alloc_type_pointer(e_type)); + } else if (is_type_boolean(e_type) && + type_size_of(e_type) <= 1) { + param_type = LLVMInt1TypeInContext(m->ctx); + } else { + if (is_type_proc(e_type)) { + param_type = lb_type(m, t_rawptr); + } else { + param_type = lb_type(m, e_type); + } + } + + params[param_index++] = param_type; + } + } + if (param_index < param_count) { + params[param_index++] = lb_type(m, t_rawptr); + } + GB_ASSERT(param_index == param_count); + + lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention); + { + for_array(j, ft->args) { + auto arg = ft->args[j]; + GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx, + "\n\t%s %td/%td" + "\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", + LLVMPrintTypeToString(arg.type), + j, ft->args.count, + LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext()); + } + GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx, + "\n\t%s" + "\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", + LLVMPrintTypeToString(ft->ret.type), + LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext()); + } + + map_set(&m->function_type_map, type, ft); + LLVMTypeRef new_abi_fn_type = lb_function_type_to_llvm_raw(ft, type->Proc.c_vararg); + + GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx, + "\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", + LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext()); + + map_set(&m->func_raw_types, type, new_abi_fn_type); + + return new_abi_fn_type; + +} LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { LLVMContextRef ctx = m->ctx; i64 size = type_size_of(type); // Check size @@ -1916,103 +2105,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough? return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0); } else { - unsigned param_count = 0; - if (type->Proc.calling_convention == ProcCC_Odin) { - param_count += 1; - } - - if (type->Proc.param_count != 0) { - GB_ASSERT(type->Proc.params->kind == Type_Tuple); - for_array(i, type->Proc.params->Tuple.variables) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - if (e->flags & EntityFlag_CVarArg) { - continue; - } - param_count += 1; - } - } - m->internal_type_level += 1; - defer (m->internal_type_level -= 1); - - LLVMTypeRef ret = nullptr; - LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count); - if (type->Proc.result_count != 0) { - Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); - ret = lb_type(m, single_ret); - if (ret != nullptr) { - if (is_type_boolean(single_ret) && - is_calling_convention_none(type->Proc.calling_convention) && - type_size_of(single_ret) <= 1) { - ret = LLVMInt1TypeInContext(m->ctx); - } - } - } - - unsigned param_index = 0; - if (type->Proc.param_count != 0) { - GB_ASSERT(type->Proc.params->kind == Type_Tuple); - for_array(i, type->Proc.params->Tuple.variables) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - if (e->flags & EntityFlag_CVarArg) { - continue; - } - Type *e_type = reduce_tuple_to_single_type(e->type); - - LLVMTypeRef param_type = nullptr; - if (e->flags & EntityFlag_ByPtr) { - param_type = lb_type(m, alloc_type_pointer(e_type)); - } else if (is_type_boolean(e_type) && - type_size_of(e_type) <= 1) { - param_type = LLVMInt1TypeInContext(m->ctx); - } else { - if (is_type_proc(e_type)) { - param_type = lb_type(m, t_rawptr); - } else { - param_type = lb_type(m, e_type); - } - } - - params[param_index++] = param_type; - } - } - if (param_index < param_count) { - params[param_index++] = lb_type(m, t_rawptr); - } - GB_ASSERT(param_index == param_count); - - lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention); - { - for_array(j, ft->args) { - auto arg = ft->args[j]; - GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx, - "\n\t%s %td/%td" - "\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", - LLVMPrintTypeToString(arg.type), - j, ft->args.count, - LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext()); - } - GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx, - "\n\t%s" - "\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", - LLVMPrintTypeToString(ft->ret.type), - LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext()); - } - - map_set(&m->function_type_map, type, ft); - LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg); - LLVMTypeRef new_abi_fn_type = LLVMGetElementType(new_abi_fn_ptr_type); - - GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx, - "\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", - LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext()); - - return new_abi_fn_ptr_type; + LLVMTypeRef proc_raw_type = lb_type_internal_for_procedures_raw(m, type); + return LLVMPointerType(proc_raw_type, 0); } break; @@ -2055,6 +2149,15 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { m->internal_type_level += 1; return t; } + + case Type_SoaPointer: + { + unsigned field_count = 2; + LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count); + fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0); + fields[1] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size); + return LLVMStructTypeInContext(ctx, fields, field_count, false); + } } @@ -2259,6 +2362,17 @@ void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *fals } +gb_inline LLVMTypeRef OdinLLVMGetInternalElementType(LLVMTypeRef type) { + return LLVMGetElementType(type); +} +LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type) { + GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind)); + return OdinLLVMGetInternalElementType(type); +} +LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type) { + GB_ASSERT(lb_is_type_kind(type, LLVMVectorTypeKind)); + return OdinLLVMGetInternalElementType(type); +} LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) { @@ -2329,7 +2443,7 @@ general_end:; if (LLVMIsALoadInst(val) && (src_size >= dst_size && src_align >= dst_align)) { LLVMValueRef val_ptr = LLVMGetOperand(val, 0); val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), ""); - LLVMValueRef loaded_val = LLVMBuildLoad(p->builder, val_ptr, ""); + LLVMValueRef loaded_val = LLVMBuildLoad2(p->builder, dst_type, val_ptr, ""); // LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align)); @@ -2345,7 +2459,7 @@ general_end:; LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), ""); LLVMBuildStore(p->builder, val, nptr); - return LLVMBuildLoad(p->builder, ptr, ""); + return LLVMBuildLoad2(p->builder, dst_type, ptr, ""); } } @@ -2371,14 +2485,15 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { isize len = gb_snprintf(name, max_len, "csbs$%x", id); len -= 1; - LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); + LLVMTypeRef type = LLVMTypeOf(data); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); LLVMSetInitializer(global_data, data); LLVMSetLinkage(global_data, LLVMPrivateLinkage); LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); LLVMSetAlignment(global_data, 1); LLVMSetGlobalConstant(global_data, true); - LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2); + LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); string_map_set(&m->const_strings, key, ptr); return ptr; } @@ -2416,7 +2531,8 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) isize len = gb_snprintf(name, max_len, "csbs$%x", id); len -= 1; } - LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); + LLVMTypeRef type = LLVMTypeOf(data); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); LLVMSetInitializer(global_data, data); LLVMSetLinkage(global_data, LLVMPrivateLinkage); LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); @@ -2425,7 +2541,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) LLVMValueRef ptr = nullptr; if (str.len != 0) { - ptr = LLVMConstInBoundsGEP(global_data, indices, 2); + ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); } else { ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); } @@ -2437,7 +2553,55 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) res.type = t_u8_slice; return res; } +lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String const &str, Type *slice_type) { + GB_ASSERT(is_type_slice(slice_type)); + LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; + LLVMValueRef data = LLVMConstStringInContext(m->ctx, + cast(char const *)str.text, + cast(unsigned)str.len, + false); + + + char *name = nullptr; + { + isize max_len = 7+8+1; + name = gb_alloc_array(permanent_allocator(), char, max_len); + u32 id = m->gen->global_array_index.fetch_add(1); + isize len = gb_snprintf(name, max_len, "csbs$%x", id); + len -= 1; + } + LLVMTypeRef type = LLVMTypeOf(data); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); + LLVMSetInitializer(global_data, data); + LLVMSetLinkage(global_data, LLVMPrivateLinkage); + LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); + LLVMSetAlignment(global_data, 1); + LLVMSetGlobalConstant(global_data, true); + + i64 data_len = str.len; + LLVMValueRef ptr = nullptr; + if (data_len != 0) { + ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); + } else { + ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); + } + if (!is_type_u8_slice(slice_type)) { + Type *bt = base_type(slice_type); + Type *elem = bt->Slice.elem; + i64 sz = type_size_of(elem); + GB_ASSERT(sz > 0); + ptr = LLVMConstPointerCast(ptr, lb_type(m, alloc_type_pointer(elem))); + data_len /= sz; + } + + LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), data_len, true); + LLVMValueRef values[2] = {ptr, len}; + lbValue res = {}; + res.value = llvm_const_named_struct(m, slice_type, values, 2); + res.type = slice_type; + return res; +} |