Browse Source

Begin to support constant array of unions

gingerBill 2 weeks ago
parent
commit
ffdfbfe2c2

+ 8 - 20
src/check_expr.cpp

@@ -3505,24 +3505,6 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type
 	return false;
 }
 
-gb_internal bool is_type_union_constantable(Type *type) {
-	Type *bt = base_type(type);
-	GB_ASSERT(bt->kind == Type_Union);
-
-	if (bt->Union.variants.count == 0) {
-		return true;
-	} else if (bt->Union.variants.count == 1) {
-		return is_type_constant_type(bt->Union.variants[0]);
-	}
-
-	for (Type *v : bt->Union.variants) {
-		if (!is_type_constant_type(v)) {
-			return false;
-		}
-	}
-	return true;
-}
-
 gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) {
 	bool is_const_expr = x->mode == Addressing_Constant;
 
@@ -4880,7 +4862,10 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
 					break;
 				}
 				operand->type = new_type;
-				operand->mode = Addressing_Value;
+				if (operand->mode != Addressing_Constant ||
+				    !elem_type_can_be_constant(operand->type)) {
+					operand->mode = Addressing_Value;
+				}
 				break;
 			} else if (valid_count > 1) {
 				ERROR_BLOCK();
@@ -9895,7 +9880,10 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
 					Operand o = {};
 					check_expr_or_type(c, &o, elem, field->type);
 
-					if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
+					if (is_type_any(field->type) ||
+					    is_type_raw_union(field->type) ||
+					    (is_type_union(field->type) && !is_type_union_constantable(field->type)) ||
+					    is_type_typeid(field->type)) {
 						is_constant = false;
 					}
 					if (is_constant) {

+ 10 - 8
src/llvm_backend_const.cpp

@@ -96,10 +96,6 @@ gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
 	case LLVMPointerTypeKind:
 		return LLVMConstPointerCast(val, dst);
 	case LLVMStructTypeKind:
-		// GB_PANIC("%s -> %s", LLVMPrintValueToString(val), LLVMPrintTypeToString(dst));
-		// NOTE(bill): It's not possible to do a bit cast on a struct, why was this code even here in the first place?
-		// It seems mostly to exist to get around the "anonymous -> named" struct assignments
-		// return LLVMConstBitCast(val, dst);
 		return val;
 	default:
 		GB_PANIC("Unhandled const cast %s to %s", LLVMPrintTypeToString(src), LLVMPrintTypeToString(dst));
@@ -199,11 +195,17 @@ gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMVal
 	return LLVMConstNamedStruct(t, values, value_count);
 }
 
-gb_internal LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
+gb_internal LLVMValueRef llvm_const_array(lbModule *m, LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
 	unsigned value_count = cast(unsigned)value_count_;
 	for (unsigned i = 0; i < value_count; i++) {
 		values[i] = llvm_const_cast(values[i], elem_type);
 	}
+	for (unsigned i = 0; i < value_count; i++) {
+		if (elem_type != LLVMTypeOf(values[i])) {
+			return LLVMConstStructInContext(m->ctx, values, value_count, false);
+		}
+	}
+
 	return LLVMConstArray(elem_type, values, value_count);
 }
 
@@ -461,7 +463,7 @@ gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type,
 		return lb_addr_load(p, v).value;
 	}
 
-	return llvm_const_array(lb_type(m, elem_type), values, cast(unsigned int)count);
+	return llvm_const_array(m, lb_type(m, elem_type), values, cast(unsigned int)count);
 }
 
 gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) {
@@ -1016,7 +1018,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
 			}
 			GB_ASSERT(offset == s.len);
 
-			res.value = llvm_const_array(et, elems, cast(unsigned)count);
+			res.value = llvm_const_array(m, et, elems, cast(unsigned)count);
 			return res;
 		}
 		// NOTE(bill, 2021-10-07): Allow for array programming value constants
@@ -1046,7 +1048,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
 			elems[i] = single_elem.value;
 		}
 
-		res.value = llvm_const_array(lb_type(m, elem), elems, cast(unsigned)count);
+		res.value = llvm_const_array(m, lb_type(m, elem), elems, cast(unsigned)count);
 		return res;
 	} else if (is_type_matrix(type) &&
 		value.kind != ExactValue_Invalid &&

+ 10 - 1
src/llvm_backend_general.cpp

@@ -3253,11 +3253,18 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb
 	GB_ASSERT(type != nullptr);
 	type = default_type(type);
 
+	LLVMTypeRef actual_type = lb_type(m, type);
+	if (value.value != nullptr) {
+		LLVMTypeRef value_type = LLVMTypeOf(value.value);
+		GB_ASSERT(lb_sizeof(actual_type) == lb_sizeof(value_type));
+		actual_type = value_type;
+	}
+
 	Scope *scope = nullptr;
 	Entity *e = alloc_entity_variable(scope, make_token_ident(name), type);
 	lbValue g = {};
 	g.type = alloc_type_pointer(type);
-	g.value = LLVMAddGlobal(m->mod, lb_type(m, type), alloc_cstring(temporary_allocator(), name));
+	g.value = LLVMAddGlobal(m->mod, actual_type, alloc_cstring(temporary_allocator(), name));
 	if (value.value != nullptr) {
 		GB_ASSERT_MSG(LLVMIsConstant(value.value), LLVMPrintValueToString(value.value));
 		LLVMSetInitializer(g.value, value.value);
@@ -3265,6 +3272,8 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb
 		LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, type)));
 	}
 
+	g.value = LLVMConstPointerCast(g.value, lb_type(m, g.type));
+
 	lb_add_entity(m, e, g);
 	lb_add_member(m, name, g);
 

+ 1 - 1
src/llvm_backend_proc.cpp

@@ -2237,7 +2237,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
 				elements[i] = element;
 			}
 
-			LLVMValueRef backing_array = llvm_const_array(lb_type(m, t_load_directory_file), elements, count);
+			LLVMValueRef backing_array = llvm_const_array(m, lb_type(m, t_load_directory_file), elements, count);
 
 			Type *array_type = alloc_type_array(t_load_directory_file, count);
 			lbAddr backing_array_addr = lb_add_global_generated_from_procedure(p, array_type, {backing_array, array_type});

+ 3 - 3
src/llvm_backend_type.cpp

@@ -302,7 +302,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
 					(name##_values)[i] = LLVMConstNull(elem);                                                      \
 				}                                                                                                      \
 			}                                                                                                              \
-			LLVMSetInitializer(name.addr.value, llvm_const_array(elem, name##_values, at->Array.count));                   \
+			LLVMSetInitializer(name.addr.value, llvm_const_array(m, elem, name##_values, at->Array.count));                   \
 		})
 
 	type_info_allocate_values(lb_global_type_info_member_types);
@@ -752,8 +752,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
 						value_values[i] = lb_const_value(m, t_i64, fields[i]->Constant.value).value;
 					}
 
-					LLVMValueRef name_init  = llvm_const_array(lb_type(m, t_string),               name_values,  cast(unsigned)fields.count);
-					LLVMValueRef value_init = llvm_const_array(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count);
+					LLVMValueRef name_init  = llvm_const_array(m, lb_type(m, t_string),               name_values,  cast(unsigned)fields.count);
+					LLVMValueRef value_init = llvm_const_array(m, lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count);
 					LLVMSetInitializer(name_array.value,  name_init);
 					LLVMSetInitializer(value_array.value, value_init);
 					LLVMSetGlobalConstant(name_array.value, true);

+ 18 - 0
src/parser.hpp

@@ -27,6 +27,24 @@ enum AddressingMode : u8 {
 	Addressing_SwizzleVariable = 14, // Swizzle indexed variable
 };
 
+gb_global String const addressing_mode_strings[] = {
+	str_lit("Invalid"),
+	str_lit("NoValue"),
+	str_lit("Value"),
+	str_lit("Context"),
+	str_lit("Variable"),
+	str_lit("Constant"),
+	str_lit("Type"),
+	str_lit("Builtin"),
+	str_lit("ProcGroup"),
+	str_lit("MapIndex"),
+	str_lit("OptionalOk"),
+	str_lit("OptionalOkPtr"),
+	str_lit("SoaVariable"),
+	str_lit("SwizzleValue"),
+	str_lit("SwizzleVariable"),
+};
+
 struct TypeAndValue {
 	Type *         type;
 	AddressingMode mode;

+ 21 - 1
src/types.cpp

@@ -2507,15 +2507,35 @@ gb_internal bool type_has_nil(Type *t) {
 	return false;
 }
 
+gb_internal bool is_type_union_constantable(Type *type) {
+	Type *bt = base_type(type);
+	GB_ASSERT(bt->kind == Type_Union);
+
+	if (bt->Union.variants.count == 0) {
+		return true;
+	} else if (bt->Union.variants.count == 1) {
+		return is_type_constant_type(bt->Union.variants[0]);
+	}
+
+	for (Type *v : bt->Union.variants) {
+		if (!is_type_constant_type(v)) {
+			return false;
+		}
+	}
+	return true;
+}
 
 gb_internal bool elem_type_can_be_constant(Type *t) {
 	t = base_type(t);
 	if (t == t_invalid) {
 		return false;
 	}
-	if (is_type_any(t) || is_type_union(t) || is_type_raw_union(t)) {
+	if (is_type_any(t) || is_type_raw_union(t)) {
 		return false;
 	}
+	if (is_type_union(t)) {
+		return is_type_union_constantable(t);
+	}
 	return true;
 }