Refactoring codegen with Flat / Lowered types. Helpers for struct gep. type_get_indexed_type no longer returns the canonical type, fixes issues in #2534

This commit is contained in:
Christoffer Lerno
2025-10-21 16:53:38 +02:00
parent 5d8cad91b1
commit 9cf271f5fb
11 changed files with 72 additions and 84 deletions

View File

@@ -1,6 +1,6 @@
#include "compiler_internal.h"
enum IntrospectIndex
typedef enum IntrospectIndex
{
INTROSPECT_INDEX_KIND = 0,
INTROSPECT_INDEX_PARENTOF = 1,
@@ -10,14 +10,14 @@ enum IntrospectIndex
INTROSPECT_INDEX_LEN = 5,
INTROSPECT_INDEX_ADDITIONAL = 6,
INTROSPECT_INDEX_TOTAL,
};
} IntrospectIndex;
bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements);
static inline bool abi_type_is_type(AbiType type);
static inline bool abi_type_is_valid(AbiType type);
static inline Type *type_lowering(Type *type)
static inline LoweredType *type_lowering(Type *type)
{
while (1)
{

View File

@@ -95,6 +95,8 @@ typedef struct Expr_ Expr;
typedef struct Module_ Module;
typedef struct Type_ Type;
typedef Type CanonicalType;
typedef Type FlatType;
typedef Type LoweredType;
typedef struct Signature_ Signature;
typedef struct ConstInitializer_ ConstInitializer;
typedef struct CompilationUnit_ CompilationUnit;
@@ -2681,7 +2683,7 @@ INLINE BitSize type_bit_size(Type *type);
INLINE Type *type_vector_type(Type *type);
static inline CanonicalType *type_pointer_type(Type *type);
static inline CanonicalType *type_flatten(Type *type);
static inline FlatType *type_flatten(Type *type);
static inline Type *type_base(Type *type);
INLINE TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span);
@@ -3366,7 +3368,7 @@ static inline CanonicalType *type_distinct_inline(Type *type)
}
}
}
static inline CanonicalType *type_flatten(Type *type)
static inline FlatType *type_flatten(Type *type)
{
while (1)
{

View File

@@ -486,7 +486,7 @@ LLVMValueRef llvm_coerce_int_ptr(GenContext *c, LLVMValueRef value, LLVMTypeRef
return value;
}
LLVMValueRef llvm_emit_coerce(GenContext *c, LLVMTypeRef coerced, BEValue *value, Type *original_type)
LLVMValueRef llvm_emit_coerce(GenContext *c, LLVMTypeRef coerced, BEValue *value)
{
LLVMTypeRef llvm_source_type = llvm_get_type(c, value->type);
@@ -656,11 +656,11 @@ static inline void llvm_emit_subscript_addr_with_base(GenContext *c, BEValue *re
switch (type->type_kind)
{
case TYPE_POINTER:
llvm_value_set_address_abi_aligned(c, result, llvm_emit_pointer_inbounds_gep_raw(
c,
llvm_get_pointee_type(c, parent->type),
parent->value,
index->value), type->pointer);
llvm_value_set_address_abi_aligned(
c,
result,
llvm_emit_pointer_inbounds_gep_raw(c, llvm_get_pointee_type(c, parent->type), parent->value, index->value),
type->pointer);
return;
case TYPE_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
@@ -4957,11 +4957,11 @@ static void llvm_expand_struct_to_args(GenContext *context, Type *param_type, LL
Type *member_type = member->type;
AlignSize load_align;
LLVMValueRef member_ptr = llvm_emit_struct_gep_raw(context,
expand_ptr,
llvm_get_type(context, param_type),
i,
alignment,
&load_align);
expand_ptr,
llvm_get_type(context, param_type),
i,
alignment,
&load_align);
llvm_expand_type_to_args(context, member_type, member_ptr, args, arg_count_ref, load_align);
}
}
@@ -5002,16 +5002,23 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM
}
}
void llvm_emit_struct_gep_ref(GenContext *c, BEValue *ref, BEValue *member_ref, Type *element_type, unsigned member_id)
{
ASSERT(llvm_value_is_addr(ref));
llvm_value_fold_optional(c, ref);
AlignSize align;
LLVMValueRef ptr = llvm_emit_struct_gep_raw(c, ref->value, llvm_get_type(c, ref->type), member_id, ref->alignment, &align);
llvm_value_set_address(c, member_ref, ptr, element_type, align);
}
void llvm_emit_struct_member_ref(GenContext *c, BEValue *struct_ref, BEValue *member_ref, unsigned member_id)
{
ASSERT(llvm_value_is_addr(struct_ref));
llvm_value_fold_optional(c, struct_ref);
ASSERT(struct_ref->type->type_kind == TYPE_STRUCT);
AlignSize align;
LLVMValueRef ptr = llvm_emit_struct_gep_raw(c, struct_ref->value, llvm_get_type(c, struct_ref->type), member_id, struct_ref->alignment, &align);
llvm_value_set_address(c, member_ref, ptr, struct_ref->type->decl->strukt.members[member_id]->type, align);
llvm_emit_struct_gep_ref(c, struct_ref, member_ref, struct_ref->type->decl->strukt.members[member_id]->type, member_id);
}
LLVMValueRef llvm_emit_struct_gep_raw(GenContext *c, LLVMValueRef ptr, LLVMTypeRef struct_type, unsigned index,
unsigned struct_alignment, AlignSize *alignment)
{
@@ -5123,14 +5130,7 @@ void llvm_emit_slice_len(GenContext *c, BEValue *slice, BEValue *len)
llvm_value_set(len, llvm_emit_extract_value(c, slice->value, 1), type_usz);
return;
}
AlignSize alignment = 0;
LLVMValueRef len_addr = llvm_emit_struct_gep_raw(c,
slice->value,
llvm_get_type(c, slice->type),
1,
slice->alignment,
&alignment);
llvm_value_set_address(c, len, len_addr, type_usz, alignment);
llvm_emit_struct_gep_ref(c, slice, len, type_usz, 1);
}
void llvm_emit_slice_pointer(GenContext *c, BEValue *slice, BEValue *pointer)
@@ -5145,9 +5145,7 @@ void llvm_emit_slice_pointer(GenContext *c, BEValue *slice, BEValue *pointer)
llvm_value_set(slice, LLVMGetInitializer(slice->value), slice->type);
goto NEXT;
}
AlignSize alignment;
LLVMValueRef ptr = llvm_emit_struct_gep_raw(c, slice->value, llvm_get_type(c, slice->type), 0, slice->alignment, &alignment);
llvm_value_set_address(c, pointer, ptr, ptr_type, alignment);
llvm_emit_struct_gep_ref(c, slice, pointer, ptr_type, 0);
return;
}
NEXT:;
@@ -5160,9 +5158,7 @@ static void llvm_emit_any_pointer(GenContext *c, BEValue *value, BEValue *pointe
llvm_value_fold_optional(c, value);
if (value->kind == BE_ADDRESS)
{
AlignSize alignment;
LLVMValueRef ptr = llvm_emit_struct_gep_raw(c, value->value, llvm_get_type(c, value->type), 0, value->alignment, &alignment);
llvm_value_set_address(c, pointer, ptr, type_voidptr, alignment);
llvm_emit_struct_gep_ref(c, value, pointer, type_voidptr, 0);
return;
}
LLVMValueRef ptr = llvm_emit_extract_value(c, value->value, 0);
@@ -5173,7 +5169,7 @@ void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_poin
{
llvm_value_fold_optional(c, struct_pointer);
ArrayIndex actual_index = -1;
Decl *member;
Decl *member = NULL;
for (ArrayIndex i = 0; i <= index; i++)
{
member = struct_pointer->type->decl->strukt.members[i];
@@ -5183,15 +5179,8 @@ void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_poin
}
actual_index++;
}
AlignSize alignment;
LLVMValueRef ref = llvm_emit_struct_gep_raw(c,
struct_pointer->value,
llvm_get_type(c, struct_pointer->type),
(unsigned)actual_index,
struct_pointer->alignment,
&alignment);
llvm_value_set_address_abi_aligned(c, element, ref, member->type);
element->alignment = alignment;
assert(member);
llvm_emit_struct_gep_ref(c, struct_pointer, element, member->type, actual_index);
}
@@ -5247,7 +5236,7 @@ void llvm_emit_parameter(GenContext *c, LLVMValueRef *args, unsigned *arg_count_
args[(*arg_count_ref)++] = llvm_load_value_store(c, be_value);
return;
}
args[(*arg_count_ref)++] = llvm_emit_coerce(c, coerce_type, be_value, type);
args[(*arg_count_ref)++] = llvm_emit_coerce(c, coerce_type, be_value);
return;
}
case ABI_ARG_DIRECT_COERCE_INT:
@@ -5258,7 +5247,7 @@ void llvm_emit_parameter(GenContext *c, LLVMValueRef *args, unsigned *arg_count_
args[(*arg_count_ref)++] = llvm_load_value_store(c, be_value);
return;
}
args[(*arg_count_ref)++] = llvm_emit_coerce(c, coerce_type, be_value, type);
args[(*arg_count_ref)++] = llvm_emit_coerce(c, coerce_type, be_value);
return;
}
case ABI_ARG_DIRECT_PAIR:
@@ -6567,7 +6556,12 @@ void llvm_emit_catch_unwrap(GenContext *c, BEValue *value, Expr *expr)
llvm_value_set(value, addr.value, type_fault);
}
static inline LLVMValueRef llvm_load_introspect(GenContext *c, LLVMValueRef ref, AlignSize align, IntrospectIndex index, const char *name, LLVMTypeRef type)
{
AlignSize alignment;
LLVMValueRef parent = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, index, align, &alignment);
return llvm_load(c, type, parent, alignment, name);
}
static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_exprid(c, value, expr->typeid_info_expr.parent);
@@ -6580,8 +6574,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
TypeIdInfoKind info_kind = expr->typeid_info_expr.kind;
if (info_kind == TYPEID_INFO_PARENTOF)
{
LLVMValueRef parent = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_PARENTOF, align, &alignment);
LLVMValueRef parent_value = llvm_load(c, c->typeid_type, parent, alignment, "typeid.parent");
LLVMValueRef parent_value = llvm_load_introspect(c, ref, align, INTROSPECT_INDEX_PARENTOF, "typeid.parent", c->typeid_type);
LLVMValueRef is_zero = LLVMBuildICmp(c->builder, LLVMIntEQ, parent_value, LLVMConstNull(c->typeid_type), "");
parent_value = LLVMBuildSelect(c->builder, is_zero, llvm_get_typeid(c, type_void), parent_value, "");
llvm_value_set(value, parent_value, expr->type);
@@ -6590,8 +6583,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
bool safe_mode = safe_mode_enabled();
if (safe_mode || info_kind == TYPEID_INFO_KIND)
{
kind = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_KIND, align, &alignment);
kind = llvm_load(c, c->byte_type, kind, alignment, "typeid.kind");
kind = llvm_load_introspect(c, ref, align, INTROSPECT_INDEX_KIND, "typeid.kind", c->byte_type);
}
switch (info_kind)
{
@@ -6628,8 +6620,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
EMIT_EXPR_LOC(c, expr);
}
{
LLVMValueRef val = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_INNER, align, &alignment);
val = llvm_load(c, c->typeid_type, val, alignment, "typeid.inner");
LLVMValueRef val = llvm_load_introspect(c, ref, align, INTROSPECT_INDEX_INNER, "typeid.inner", c->typeid_type);
llvm_value_set(value, val, expr->type);
return;
}
@@ -6657,8 +6648,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
EMIT_EXPR_LOC(c, expr);
}
{
LLVMValueRef len = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_LEN, align, &alignment);
len = llvm_load(c, c->size_type, len, alignment, "namelen");
LLVMValueRef len = llvm_load_introspect(c, ref, align, INTROSPECT_INDEX_LEN, "namelen", c->size_type);
LLVMValueRef val = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_ADDITIONAL, align, &alignment);
Type *slice = type_get_slice(type_chars);
llvm_value_set(value, llvm_emit_aggregate_two(c, slice, val, len), slice);
@@ -6690,15 +6680,13 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
EMIT_EXPR_LOC(c, expr);
}
{
LLVMValueRef val = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_LEN, align, &alignment);
val = llvm_load(c, c->size_type, val, alignment, "typeid.len");
LLVMValueRef val = llvm_load_introspect(c, ref, align, INTROSPECT_INDEX_LEN, "typeid.len", c->size_type);
llvm_value_set(value, val, expr->type);
return;
}
case TYPEID_INFO_SIZEOF:
{
LLVMValueRef val = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_SIZEOF, align, &alignment);
val = llvm_load(c, c->size_type, val, alignment, "typeid.size");
LLVMValueRef val = llvm_load_introspect(c, ref, align, INTROSPECT_INDEX_SIZEOF, "typeid.size", c->size_type);
llvm_value_set(value, val, expr->type);
return;
}
@@ -6770,14 +6758,7 @@ static inline void llvm_emit_type_from_any(GenContext *c, BEValue *be_value)
{
if (llvm_value_is_addr(be_value))
{
AlignSize alignment = 0;
LLVMValueRef pointer_addr = llvm_emit_struct_gep_raw(c,
be_value->value,
llvm_get_type(c, type_any),
1,
be_value->alignment,
&alignment);
llvm_value_set_address(c, be_value, pointer_addr, type_typeid, alignment);
llvm_emit_struct_gep_ref(c, be_value, be_value, type_typeid, 1);
}
else
{
@@ -7025,9 +7006,7 @@ static void llvm_emit_ptr_access(GenContext *c, BEValue *value, Expr *expr)
llvm_value_fold_optional(c, value);
if (value->kind == BE_ADDRESS)
{
AlignSize alignment;
LLVMValueRef ptr = llvm_emit_struct_gep_raw(c, value->value, llvm_get_type(c, value->type), 0, value->alignment, &alignment);
llvm_value_set_address(c, value, ptr, expr->type, alignment);
llvm_emit_struct_gep_ref(c, value, value, expr->type, 0);
return;
}
LLVMValueRef ptr = llvm_emit_extract_value(c, value->value, 0);

View File

@@ -365,21 +365,21 @@ DIRECT_RETURN:
{
LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info);
if (coerce_type == llvm_get_type(c, call_return_type)) goto DIRECT_RETURN;
llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value, call_return_type));
llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value));
return;
}
case ABI_ARG_DIRECT_COERCE_INT:
{
LLVMTypeRef coerce_type = LLVMIntTypeInContext(c->context, type_size(call_return_type) * 8);
if (coerce_type == llvm_get_type(c, call_return_type)) goto DIRECT_RETURN;
llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value, call_return_type));
llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value));
return;
}
case ABI_ARG_DIRECT_COERCE:
{
LLVMTypeRef coerce_type = llvm_abi_type(c, info->direct_coerce_type);
if (coerce_type == llvm_get_type(c, call_return_type)) goto DIRECT_RETURN;
llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value, call_return_type));
llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value));
return;
}
}

View File

@@ -30,7 +30,7 @@ typedef struct
{
BackendValueKind kind : 5;
AlignSize alignment;
Type *type; // Should never be a distinct or canonical type.
LoweredType *type; // Should never be a distinct or canonical type.
LLVMValueRef value;
LLVMValueRef optional;
} BEValue;
@@ -486,6 +486,7 @@ LLVMValueRef llvm_emit_pointer_inbounds_gep_raw(GenContext *c, LLVMTypeRef point
LLVMTypeRef llvm_coerce_expand_hi_offset(GenContext *c, LLVMValueRef *addr, ABIArgInfo *info, AlignSize *align);
void llvm_emit_ptr_from_array(GenContext *c, BEValue *value);
void llvm_emit_struct_member_ref(GenContext *c, BEValue *struct_ref, BEValue *member_ref, unsigned member_id);
void llvm_emit_struct_gep_ref(GenContext *c, BEValue *ref, BEValue *member_ref, Type *element_type, unsigned member_id);
INLINE LLVMValueRef llvm_emit_extract_value(GenContext *c, LLVMValueRef agg, unsigned index);
// -- Int operations ---
@@ -510,7 +511,7 @@ LLVMTypeRef llvm_get_coerce_type(GenContext *c, ABIArgInfo *arg_info);
LLVMValueRef llvm_get_next_param(GenContext *c, unsigned *index);
void llvm_emit_convert_value_from_coerced(GenContext *c, BEValue *result, LLVMTypeRef coerced, LLVMValueRef value, Type *original_type);
void llvm_emit_coerce_store(GenContext *c, LLVMValueRef addr, AlignSize alignment, LLVMTypeRef coerced, LLVMValueRef value, LLVMTypeRef target_type);
LLVMValueRef llvm_emit_coerce(GenContext *c, LLVMTypeRef coerced, BEValue *value, Type *original_type);
LLVMValueRef llvm_emit_coerce(GenContext *c, LLVMTypeRef coerced, BEValue *value);
static inline LLVMCallConv llvm_call_convention_from_call(CallABI abi);
void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype *prototype, LLVMTypeRef func_type, LLVMValueRef func, LLVMValueRef *args, unsigned arg_count, int inline_flag, LLVMValueRef error_var, bool sret_return, BEValue *synthetic_return_param, bool no_return);

View File

@@ -124,8 +124,7 @@ INLINE LLVMValueRef llvm_store_to_ptr_raw(GenContext *c, LLVMValueRef pointer, L
INLINE void llvm_value_bitcast(GenContext *c UNUSED, BEValue *value, Type *type)
{
ASSERT(llvm_value_is_addr(value));
type = type_lowering(type);
value->type = type;
value->type = type_lowering(type);
}
INLINE LLVMValueRef llvm_emit_shl(GenContext *c, LLVMValueRef value, LLVMValueRef shift)

View File

@@ -302,7 +302,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
ASSERT(LLVMGetTypeContext(any_type->backend_type) == c->context && "Should have been purged");
return any_type->backend_type;
}
Type *type = type_lowering(any_type);
LoweredType *type = type_lowering(any_type);
if (type != any_type)
{
return any_type->backend_type = llvm_get_type(c, type);
@@ -436,7 +436,7 @@ static inline LLVMValueRef llvm_generate_temp_introspection_global(GenContext *c
}
static inline LLVMValueRef llvm_generate_introspection_global(GenContext *c, LLVMValueRef original_global, Type *type, IntrospectType introspect_type,
Type *inner, size_t len, LLVMValueRef additional, bool is_external)
Type *inner, size_t len, LLVMValueRef additional, bool is_external)
{
// Push the builder
void *builder = c->builder;

View File

@@ -57,7 +57,7 @@ void llvm_value_set_address(GenContext *c, BEValue *value, LLVMValueRef llvm_val
void llvm_value_set_address_abi_aligned(GenContext *c, BEValue *value, LLVMValueRef llvm_value, Type *type)
{
llvm_value_set_address(c, value, llvm_value, type_lowering(type), type_abi_alignment(type));
llvm_value_set_address(c, value, llvm_value, type, type_abi_alignment(type));
}
void llvm_value_addr(GenContext *c, BEValue *value)

View File

@@ -3896,7 +3896,7 @@ static inline bool sema_expr_resolve_subscript_index(SemaContext *context, Expr
ArrayIndex size;
bool check_len = !context->call_env.in_no_eval || current_type == type_untypedlist;
Expr *len_expr = current_expr->expr_kind == EXPR_CT_IDENT ? current_expr->ct_ident_expr.decl->var.init_expr : current_expr;
if (sema_cast_const(index)&& expr_is_const_int(index) && (size = sema_len_from_expr(len_expr)) >= 0)
if (sema_cast_const(index) && expr_is_const_int(index) && (size = sema_len_from_expr(len_expr)) >= 0)
{
// 4c. And that it's in range.
if (int_is_neg(index->const_expr.ixx))

View File

@@ -1173,14 +1173,14 @@ Type *type_get_indexed_type(Type *type)
switch (type->type_kind)
{
case TYPE_POINTER:
return type->pointer->canonical;
return type->pointer;
case TYPE_ARRAY:
case TYPE_SLICE:
case TYPE_INFERRED_ARRAY:
case TYPE_INFERRED_VECTOR:
case TYPE_FLEXIBLE_ARRAY:
case TYPE_VECTOR:
return type->array.base->canonical;
return type->array.base;
case TYPE_TYPEDEF:
type = type->decl->distinct->type;
goto RETRY;

View File

@@ -0,0 +1,7 @@
alias MyChar = char;
fn void main()
{
MyChar[<2>] my = { '1', '2' };
my[0].ok(); // #error: There is no member or method 'ok' on 'MyChar' (char)
}