mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-28 17:04:34 +00:00
Use memcpy for local constant slice arrays from a global constant
This commit is contained in:
@@ -641,161 +641,6 @@ gb_internal Slice<LLVMValueRef> lb_construct_const_union_flatten_values(lbModule
|
||||
return {};
|
||||
}
|
||||
|
||||
gb_internal LLVMValueRef lb_construct_const_union(lbModule *m, LLVMValueRef variant_value, Type *variant_type, Type *union_type) {
|
||||
#if 1
|
||||
return nullptr;
|
||||
#else
|
||||
Type *bt = base_type(union_type);
|
||||
GB_ASSERT(bt->kind == Type_Union);
|
||||
GB_ASSERT(lb_type(m, variant_type) == LLVMTypeOf(variant_value));
|
||||
|
||||
LLVMTypeRef llvm_type = lb_type(m, union_type);
|
||||
|
||||
if (LLVMIsNull(variant_value)) {
|
||||
return LLVMConstNull(llvm_type);
|
||||
}
|
||||
|
||||
if (bt->Union.variants.count == 0) {
|
||||
GB_ASSERT(LLVMIsNull(variant_value));
|
||||
return variant_value;
|
||||
}
|
||||
|
||||
i64 block_size = bt->Union.variant_block_size;
|
||||
i64 variant_size = type_size_of(variant_type);
|
||||
|
||||
LLVMTypeRef llvm_variant_type = lb_type(m, variant_type);
|
||||
|
||||
if (is_type_union_maybe_pointer(bt)) {
|
||||
GB_ASSERT(lb_sizeof(LLVMTypeOf(variant_value)) == lb_sizeof(llvm_type));
|
||||
return LLVMConstBitCast(variant_value, llvm_type);
|
||||
}
|
||||
|
||||
if (bt->Union.variants.count == 1) {
|
||||
unsigned long long the_tag = cast(unsigned long long)union_variant_index(union_type, variant_type);
|
||||
LLVMTypeRef tag_type = lb_type(m, union_tag_type(bt));
|
||||
|
||||
LLVMValueRef values[3] = {};
|
||||
unsigned i = 0;
|
||||
values[i++] = variant_value;
|
||||
values[i++] = LLVMConstInt(tag_type, the_tag, false);
|
||||
|
||||
i64 used_size = block_size + lb_sizeof(tag_type);
|
||||
i64 padding = type_size_of(union_type) - used_size;
|
||||
i64 align = type_align_of(union_type);
|
||||
if (padding > 0) {
|
||||
LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, align);
|
||||
values[i++] = LLVMConstNull(padding_type);
|
||||
}
|
||||
|
||||
return LLVMConstNamedStruct(llvm_type, values, i);
|
||||
} else if (true) {
|
||||
// TODO(bill): ignore this for the time being
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LLVMTypeRef block_type = LLVMStructGetTypeAtIndex(llvm_type, 0);
|
||||
|
||||
LLVMTypeRef tag_type = lb_type(m, union_tag_type(bt));
|
||||
|
||||
i64 used_size = block_size + lb_sizeof(tag_type);
|
||||
i64 padding = type_size_of(union_type) - used_size;
|
||||
i64 align = type_align_of(union_type);
|
||||
LLVMTypeRef padding_type = nullptr;
|
||||
if (padding > 0) {
|
||||
padding_type = lb_type_padding_filler(m, padding, align);
|
||||
}
|
||||
|
||||
|
||||
unsigned i = 0;
|
||||
LLVMValueRef values[3] = {};
|
||||
|
||||
LLVMValueRef block_value = variant_value;
|
||||
|
||||
if (block_size == 0) {
|
||||
block_value = LLVMConstNull(block_type);
|
||||
} else if (lb_sizeof(llvm_variant_type) == 0) {
|
||||
block_value = LLVMConstNull(block_type);
|
||||
} else if (block_type != llvm_variant_type) {
|
||||
|
||||
LLVMTypeKind block_kind = LLVMGetTypeKind(block_type);
|
||||
LLVMTypeKind variant_kind = LLVMGetTypeKind(llvm_variant_type);
|
||||
|
||||
|
||||
if (block_kind == LLVMArrayTypeKind) {
|
||||
LLVMTypeRef elem = LLVMGetElementType(block_type);
|
||||
unsigned count = LLVMGetArrayLength(block_type);
|
||||
|
||||
Slice<LLVMValueRef> partial_elems = lb_construct_const_union_flatten_values(m, variant_value, variant_type, elem);
|
||||
if (partial_elems.count == count) {
|
||||
block_value = LLVMConstArray(elem, partial_elems.data, count);
|
||||
goto assign_value_wrapped;
|
||||
}
|
||||
|
||||
Slice<LLVMValueRef> full_elems = temporary_slice_make<LLVMValueRef>(count);
|
||||
slice_copy(&full_elems, partial_elems);
|
||||
for (isize j = partial_elems.count; j < count; j++) {
|
||||
full_elems[j] = LLVMConstNull(elem);
|
||||
}
|
||||
block_value = LLVMConstArray(elem, full_elems.data, count);
|
||||
goto assign_value_wrapped;
|
||||
|
||||
} else if (block_size != variant_size) {
|
||||
if (block_kind == LLVMIntegerTypeKind && !is_type_different_to_arch_endianness(variant_type)) {
|
||||
Slice<LLVMValueRef> partial_elems = lb_construct_const_union_flatten_values(m, variant_value, variant_type, block_type);
|
||||
if (partial_elems.count == 1) {
|
||||
block_value = partial_elems[0];
|
||||
goto assign_value_wrapped;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
if (block_kind == LLVMIntegerTypeKind) {
|
||||
GB_ASSERT(block_size == variant_size);
|
||||
|
||||
switch (variant_kind) {
|
||||
case LLVMHalfTypeKind:
|
||||
case LLVMFloatTypeKind:
|
||||
case LLVMDoubleTypeKind:
|
||||
block_value = LLVMConstBitCast(block_value, block_type);
|
||||
goto assign_value_wrapped;
|
||||
case LLVMPointerTypeKind:
|
||||
block_value = LLVMConstPtrToInt(block_value, block_type);
|
||||
goto assign_value_wrapped;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
} else {
|
||||
// TODO(bill): ignore this for the time being
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assign_value_wrapped:;
|
||||
values[i++] = block_value;
|
||||
|
||||
unsigned long long the_tag = cast(unsigned long long)union_variant_index(union_type, variant_type);
|
||||
values[i++] = LLVMConstInt(tag_type, the_tag, false);
|
||||
if (padding > 0) {
|
||||
values[i++] = LLVMConstNull(padding_type);
|
||||
}
|
||||
return LLVMConstNamedStruct(llvm_type, values, i);
|
||||
#endif
|
||||
}
|
||||
|
||||
gb_internal bool lb_try_construct_const_union(lbModule *m, lbValue *value, Type *variant_type, Type *union_type) {
|
||||
if (lb_is_const(*value)) {
|
||||
LLVMValueRef res = lb_construct_const_union(m, value->value, variant_type, union_type);
|
||||
if (res != nullptr) {
|
||||
*value = {res, union_type};
|
||||
return true;
|
||||
}
|
||||
// gb_printf_err("%s -> %s\n", LLVMPrintValueToString(value->value), LLVMPrintTypeToString(lb_type(m, union_type)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc, Type *value_type) {
|
||||
if (cc.allow_local) {
|
||||
cc.is_rodata = false;
|
||||
@@ -888,6 +733,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
Type *tag_type = union_tag_type(bt);
|
||||
LLVMTypeRef llvm_tag_type = lb_type(m, tag_type);
|
||||
i64 tag_index = union_variant_index(bt, variant_type);
|
||||
GB_ASSERT(tag_index >= 0);
|
||||
values[value_count++] = LLVMConstInt(llvm_tag_type, tag_index, false);
|
||||
i64 used_size = block_size + type_size_of(tag_type);
|
||||
i64 union_size = type_size_of(bt);
|
||||
@@ -946,27 +792,42 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
count = gb_max(cast(isize)cl->max_count, count);
|
||||
Type *elem = base_type(type)->Slice.elem;
|
||||
Type *t = alloc_type_array(elem, count);
|
||||
lbValue backing_array = lb_const_value(m, t, value, cc);
|
||||
lbValue backing_array = lb_const_value(m, t, value, cc, nullptr);
|
||||
|
||||
LLVMValueRef array_data = nullptr;
|
||||
|
||||
u32 id = m->global_array_index.fetch_add(1);
|
||||
gbString str = gb_string_make(temporary_allocator(), "csba$");
|
||||
str = gb_string_appendc(str, m->module_name);
|
||||
str = gb_string_append_fmt(str, "$%x", id);
|
||||
|
||||
String name = make_string(cast(u8 const *)str, gb_string_length(str));
|
||||
|
||||
Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
|
||||
array_data = LLVMAddGlobal(m->mod, LLVMTypeOf(backing_array.value), str);
|
||||
LLVMSetInitializer(array_data, backing_array.value);
|
||||
|
||||
|
||||
|
||||
if (is_local) {
|
||||
LLVMSetGlobalConstant(array_data, true);
|
||||
|
||||
// NOTE(bill, 2020-06-08): This is a bit of a hack but a "constant" slice needs
|
||||
// its backing data on the stack
|
||||
lbProcedure *p = m->curr_procedure;
|
||||
|
||||
// NOTE(bill, 2025-09-28): make the array data global BUT memcpy it
|
||||
// to make a local copy
|
||||
LLVMTypeRef llvm_type = lb_type(m, t);
|
||||
|
||||
array_data = llvm_alloca(p, llvm_type, 16);
|
||||
|
||||
{
|
||||
LLVMValueRef ptr = array_data;
|
||||
ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(LLVMTypeOf(backing_array.value), 0), "");
|
||||
LLVMBuildStore(p->builder, backing_array.value, ptr);
|
||||
}
|
||||
LLVMValueRef local_copy = llvm_alloca(p, llvm_type, 16);
|
||||
LLVMBuildMemCpy(p->builder,
|
||||
local_copy, 16,
|
||||
array_data, 1,
|
||||
LLVMConstInt(lb_type(m, t_int), type_size_of(t), false));
|
||||
|
||||
{
|
||||
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
|
||||
LLVMValueRef ptr = LLVMBuildInBoundsGEP2(p->builder, llvm_type, array_data, indices, 2, "");
|
||||
LLVMValueRef ptr = LLVMBuildInBoundsGEP2(p->builder, llvm_type, local_copy, indices, 2, "");
|
||||
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
|
||||
|
||||
lbAddr slice = lb_add_local_generated(p, original_type, false);
|
||||
@@ -976,17 +837,6 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
return lb_addr_load(p, slice);
|
||||
}
|
||||
} else {
|
||||
u32 id = m->global_array_index.fetch_add(1);
|
||||
gbString str = gb_string_make(temporary_allocator(), "csba$");
|
||||
str = gb_string_appendc(str, m->module_name);
|
||||
str = gb_string_append_fmt(str, "$%x", id);
|
||||
|
||||
String name = make_string(cast(u8 const *)str, gb_string_length(str));
|
||||
|
||||
Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
|
||||
array_data = LLVMAddGlobal(m->mod, LLVMTypeOf(backing_array.value), str);
|
||||
LLVMSetInitializer(array_data, backing_array.value);
|
||||
|
||||
if (cc.link_section.len > 0) {
|
||||
LLVMSetSection(array_data, alloc_cstring(permanent_allocator(), cc.link_section));
|
||||
}
|
||||
|
||||
@@ -2495,13 +2495,6 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
Type *vt = dst->Union.variants[0];
|
||||
if (internal_check_is_assignable_to(src_type, vt)) {
|
||||
value = lb_emit_conv(p, value, vt);
|
||||
if (lb_is_const(value)) {
|
||||
LLVMValueRef res = lb_construct_const_union(m, value.value, vt, t);
|
||||
if (res != nullptr) {
|
||||
return {res, t};
|
||||
}
|
||||
}
|
||||
|
||||
lbAddr parent = lb_add_local_generated(p, t, true);
|
||||
lb_emit_store_union_variant(p, parent.addr, value, vt);
|
||||
return lb_addr_load(p, parent);
|
||||
@@ -2509,19 +2502,11 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
}
|
||||
for (Type *vt : dst->Union.variants) {
|
||||
if (src_type == t_llvm_bool && is_type_boolean(vt)) {
|
||||
value = lb_emit_conv(p, value, vt);
|
||||
if (lb_try_construct_const_union(m, &value, vt, t)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
lbAddr parent = lb_add_local_generated(p, t, true);
|
||||
lb_emit_store_union_variant(p, parent.addr, value, vt);
|
||||
return lb_addr_load(p, parent);
|
||||
}
|
||||
if (are_types_identical(src_type, vt)) {
|
||||
if (lb_try_construct_const_union(m, &value, vt, t)) {
|
||||
return value;
|
||||
}
|
||||
lbAddr parent = lb_add_local_generated(p, t, true);
|
||||
lb_emit_store_union_variant(p, parent.addr, value, vt);
|
||||
return lb_addr_load(p, parent);
|
||||
@@ -2559,9 +2544,6 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
if (valid_count == 1) {
|
||||
Type *vt = dst->Union.variants[first_success_index];
|
||||
value = lb_emit_conv(p, value, vt);
|
||||
if (lb_try_construct_const_union(m, &value, vt, t)) {
|
||||
return value;
|
||||
}
|
||||
lbAddr parent = lb_add_local_generated(p, t, true);
|
||||
lb_emit_store_union_variant(p, parent.addr, value, vt);
|
||||
return lb_addr_load(p, parent);
|
||||
|
||||
@@ -1493,8 +1493,11 @@ gb_internal lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue 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));
|
||||
|
||||
LLVMValueRef ptr = u.value;
|
||||
ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(uvt, 0), "");
|
||||
|
||||
lbValue tag_ptr = {};
|
||||
tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, "");
|
||||
tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, ptr, 1, "");
|
||||
tag_ptr.type = alloc_type_pointer(tag_type);
|
||||
return tag_ptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user