Begin to support constant array of unions

This commit is contained in:
gingerBill
2025-09-28 20:20:26 +01:00
parent a974c51d57
commit ffdfbfe2c2
7 changed files with 71 additions and 34 deletions

View File

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

View File

@@ -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 &&

View File

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

View File

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

View File

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

View File

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

View File

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