aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend_general.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm_backend_general.cpp')
-rw-r--r--src/llvm_backend_general.cpp422
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;
+}