Browse Source

Use `memcpy` for local constant slice arrays from a global constant

gingerBill 2 weeks ago
parent
commit
cbab97fbd7
3 changed files with 30 additions and 195 deletions
  1. 26 176
      src/llvm_backend_const.cpp
  2. 0 18
      src/llvm_backend_expr.cpp
  3. 4 1
      src/llvm_backend_general.cpp

+ 26 - 176
src/llvm_backend_const.cpp

@@ -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;
-				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);
-				}
+				// 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);
+				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));
 				}

+ 0 - 18
src/llvm_backend_expr.cpp

@@ -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);

+ 4 - 1
src/llvm_backend_general.cpp

@@ -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;
 }