mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
IR: function call porting progress
also implemented container init generics is still todo
This commit is contained in:
parent
9e7c475979
commit
eb5693d91f
@ -41,6 +41,7 @@ struct IrExecutable {
|
||||
bool invalid;
|
||||
ZigList<LabelTableEntry *> all_labels;
|
||||
ZigList<AstNode *> goto_list;
|
||||
bool is_inline;
|
||||
};
|
||||
|
||||
enum OutType {
|
||||
@ -82,6 +83,11 @@ struct ConstErrValue {
|
||||
ConstExprValue *payload;
|
||||
};
|
||||
|
||||
struct ConstBoundFnValue {
|
||||
FnTableEntry *fn;
|
||||
IrInstruction *first_arg;
|
||||
};
|
||||
|
||||
enum ConstValSpecial {
|
||||
ConstValSpecialRuntime,
|
||||
ConstValSpecialStatic,
|
||||
@ -100,6 +106,7 @@ struct ConstExprValue {
|
||||
BigNum x_bignum;
|
||||
bool x_bool;
|
||||
FnTableEntry *x_fn;
|
||||
ConstBoundFnValue x_bound_fn;
|
||||
TypeTableEntry *x_type;
|
||||
ConstExprValue *x_maybe;
|
||||
ConstErrValue x_err;
|
||||
@ -494,6 +501,7 @@ struct AstNodeIfBoolExpr {
|
||||
AstNode *condition;
|
||||
AstNode *then_block;
|
||||
AstNode *else_node; // null, block node, or other if expr node
|
||||
bool is_inline; // TODO
|
||||
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
@ -503,6 +511,7 @@ struct AstNodeIfVarExpr {
|
||||
AstNode *then_block;
|
||||
AstNode *else_node; // null, block node, or other if expr node
|
||||
bool var_is_ptr;
|
||||
bool is_inline; // TODO
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeTableEntry *type;
|
||||
@ -941,12 +950,18 @@ struct TypeTableEntryFn {
|
||||
|
||||
LLVMTypeRef raw_type_ref;
|
||||
LLVMCallConv calling_convention;
|
||||
|
||||
TypeTableEntry *bound_fn_parent;
|
||||
};
|
||||
|
||||
struct TypeTableEntryGenericFn {
|
||||
AstNode *decl_node;
|
||||
};
|
||||
|
||||
struct TypeTableEntryBoundFn {
|
||||
TypeTableEntry *fn_type;
|
||||
};
|
||||
|
||||
struct TypeTableEntryTypeDecl {
|
||||
TypeTableEntry *child_type;
|
||||
TypeTableEntry *canonical_type;
|
||||
@ -978,6 +993,7 @@ enum TypeTableEntryId {
|
||||
TypeTableEntryIdNamespace,
|
||||
TypeTableEntryIdBlock,
|
||||
TypeTableEntryIdGenericFn,
|
||||
TypeTableEntryIdBoundFn,
|
||||
};
|
||||
|
||||
struct TypeTableEntry {
|
||||
@ -988,7 +1004,6 @@ struct TypeTableEntry {
|
||||
ZigLLVMDIType *di_type;
|
||||
|
||||
bool zero_bits;
|
||||
bool deep_const;
|
||||
|
||||
union {
|
||||
TypeTableEntryPointer pointer;
|
||||
@ -1003,6 +1018,7 @@ struct TypeTableEntry {
|
||||
TypeTableEntryFn fn;
|
||||
TypeTableEntryTypeDecl type_decl;
|
||||
TypeTableEntryGenericFn generic_fn;
|
||||
TypeTableEntryBoundFn bound_fn;
|
||||
} data;
|
||||
|
||||
// use these fields to make sure we don't duplicate type table entries for the same type
|
||||
@ -1043,12 +1059,6 @@ enum FnAnalState {
|
||||
};
|
||||
|
||||
|
||||
enum WantPure {
|
||||
WantPureAuto,
|
||||
WantPureFalse,
|
||||
WantPureTrue,
|
||||
};
|
||||
|
||||
enum FnInline {
|
||||
FnInlineAuto,
|
||||
FnInlineAlways,
|
||||
@ -1067,10 +1077,6 @@ struct FnTableEntry {
|
||||
bool internal_linkage;
|
||||
bool is_extern;
|
||||
bool is_test;
|
||||
bool is_pure;
|
||||
WantPure want_pure;
|
||||
AstNode *want_pure_attr_node;
|
||||
AstNode *want_pure_return_type;
|
||||
FnInline fn_inline;
|
||||
FnAnalState anal_state;
|
||||
IrExecutable ir_executable;
|
||||
@ -1085,6 +1091,9 @@ struct FnTableEntry {
|
||||
ZigList<VariableTableEntry *> variable_list;
|
||||
};
|
||||
|
||||
uint32_t fn_table_entry_hash(FnTableEntry*);
|
||||
bool fn_table_entry_eql(FnTableEntry *a, FnTableEntry *b);
|
||||
|
||||
enum BuiltinFnId {
|
||||
BuiltinFnIdInvalid,
|
||||
BuiltinFnIdMemcpy,
|
||||
@ -1122,7 +1131,6 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdUnreachable,
|
||||
BuiltinFnIdSetFnTest,
|
||||
BuiltinFnIdSetFnVisible,
|
||||
BuiltinFnIdSetFnStaticEval,
|
||||
BuiltinFnIdSetFnNoInline,
|
||||
BuiltinFnIdSetDebugSafety,
|
||||
};
|
||||
@ -1385,6 +1393,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdStorePtr,
|
||||
IrInstructionIdFieldPtr,
|
||||
IrInstructionIdStructFieldPtr,
|
||||
IrInstructionIdEnumFieldPtr,
|
||||
IrInstructionIdElemPtr,
|
||||
IrInstructionIdVarPtr,
|
||||
IrInstructionIdCall,
|
||||
@ -1393,6 +1402,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdCast,
|
||||
IrInstructionIdContainerInitList,
|
||||
IrInstructionIdContainerInitFields,
|
||||
IrInstructionIdStructInit,
|
||||
IrInstructionIdUnreachable,
|
||||
IrInstructionIdTypeOf,
|
||||
IrInstructionIdToPtrType,
|
||||
@ -1578,6 +1588,14 @@ struct IrInstructionStructFieldPtr {
|
||||
bool is_const;
|
||||
};
|
||||
|
||||
struct IrInstructionEnumFieldPtr {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *enum_ptr;
|
||||
TypeEnumField *field;
|
||||
bool is_const;
|
||||
};
|
||||
|
||||
struct IrInstructionElemPtr {
|
||||
IrInstruction base;
|
||||
|
||||
@ -1597,9 +1615,12 @@ struct IrInstructionVarPtr {
|
||||
struct IrInstructionCall {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *fn;
|
||||
IrInstruction *fn_ref;
|
||||
FnTableEntry *fn_entry;
|
||||
size_t arg_count;
|
||||
IrInstruction **args;
|
||||
bool is_inline;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionConst {
|
||||
@ -1615,11 +1636,12 @@ struct IrInstructionReturn {
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
// TODO get rid of this instruction, replace with instructions for each op code
|
||||
struct IrInstructionCast {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
IrInstruction *dest_type;
|
||||
TypeTableEntry *dest_type;
|
||||
CastOp cast_op;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
@ -1630,6 +1652,14 @@ struct IrInstructionContainerInitList {
|
||||
IrInstruction *container_type;
|
||||
size_t item_count;
|
||||
IrInstruction **items;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionContainerInitFieldsField {
|
||||
Buf *name;
|
||||
IrInstruction *value;
|
||||
AstNode *source_node;
|
||||
TypeStructField *type_struct_field;
|
||||
};
|
||||
|
||||
struct IrInstructionContainerInitFields {
|
||||
@ -1637,8 +1667,21 @@ struct IrInstructionContainerInitFields {
|
||||
|
||||
IrInstruction *container_type;
|
||||
size_t field_count;
|
||||
Buf **field_names;
|
||||
IrInstruction **field_values;
|
||||
IrInstructionContainerInitFieldsField *fields;
|
||||
};
|
||||
|
||||
struct IrInstructionStructInitField {
|
||||
IrInstruction *value;
|
||||
TypeStructField *type_struct_field;
|
||||
};
|
||||
|
||||
struct IrInstructionStructInit {
|
||||
IrInstruction base;
|
||||
|
||||
TypeTableEntry *struct_type;
|
||||
size_t field_count;
|
||||
IrInstructionStructInitField *fields;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionUnreachable {
|
||||
@ -1790,4 +1833,7 @@ static const size_t slice_len_index = 1;
|
||||
static const size_t maybe_child_index = 0;
|
||||
static const size_t maybe_null_index = 1;
|
||||
|
||||
static const size_t enum_gen_tag_index = 0;
|
||||
static const size_t enum_gen_union_index = 1;
|
||||
|
||||
#endif
|
||||
|
||||
111
src/analyze.cpp
111
src/analyze.cpp
@ -84,46 +84,11 @@ AstNode *first_executing_node(AstNode *node) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node) {
|
||||
if (!context->fn_entry) return;
|
||||
if (!context->fn_entry->is_pure) return;
|
||||
|
||||
context->fn_entry->is_pure = false;
|
||||
if (context->fn_entry->want_pure == WantPureTrue) {
|
||||
context->fn_entry->proto_node->data.fn_proto.skip = true;
|
||||
|
||||
ErrorMsg *msg = add_node_error(g, context->fn_entry->proto_node,
|
||||
buf_sprintf("failed to evaluate function at compile time"));
|
||||
|
||||
add_error_note(g, msg, node,
|
||||
buf_sprintf("unable to evaluate this expression at compile time"));
|
||||
|
||||
if (context->fn_entry->want_pure_attr_node) {
|
||||
add_error_note(g, msg, context->fn_entry->want_pure_attr_node,
|
||||
buf_sprintf("required to be compile-time function here"));
|
||||
}
|
||||
|
||||
if (context->fn_entry->want_pure_return_type) {
|
||||
add_error_note(g, msg, context->fn_entry->want_pure_return_type,
|
||||
buf_sprintf("required to be compile-time function because of return type '%s'",
|
||||
buf_ptr(&context->fn_entry->type_entry->data.fn.fn_type_id.return_type->name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
|
||||
// if this assert fails, then parseh generated code that
|
||||
// failed semantic analysis, which isn't supposed to happen
|
||||
assert(!node->owner->c_import_node);
|
||||
|
||||
// if an error occurs in a function then it becomes impure
|
||||
if (node->block_context) {
|
||||
FnTableEntry *fn_entry = node->block_context->fn_entry;
|
||||
if (fn_entry) {
|
||||
fn_entry->is_pure = false;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
|
||||
node->owner->source_code, node->owner->line_offsets, msg);
|
||||
|
||||
@ -217,6 +182,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
return true;
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -241,7 +207,6 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
|
||||
static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) {
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdGenericFn);
|
||||
buf_init_from_str(&entry->name, "(generic function)");
|
||||
entry->deep_const = true;
|
||||
entry->zero_bits = true;
|
||||
entry->data.generic_fn.decl_node = decl_node;
|
||||
return entry;
|
||||
@ -255,8 +220,6 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
|
||||
} else {
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
|
||||
|
||||
entry->deep_const = is_const && child_type->deep_const;
|
||||
|
||||
const char *const_str = is_const ? "const " : "";
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
|
||||
@ -298,8 +261,6 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
|
||||
assert(child_type->type_ref);
|
||||
assert(child_type->di_type);
|
||||
|
||||
entry->deep_const = child_type->deep_const;
|
||||
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
|
||||
|
||||
@ -383,8 +344,6 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
|
||||
|
||||
entry->data.error.child_type = child_type;
|
||||
|
||||
entry->deep_const = child_type->deep_const;
|
||||
|
||||
if (!type_has_bits(child_type)) {
|
||||
entry->type_ref = g->err_tag_type->type_ref;
|
||||
entry->di_type = g->err_tag_type->di_type;
|
||||
@ -456,7 +415,6 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
|
||||
entry->type_ref = child_type->type_ref ? LLVMArrayType(child_type->type_ref, array_size) : nullptr;
|
||||
entry->zero_bits = (array_size == 0) || child_type->zero_bits;
|
||||
entry->deep_const = child_type->deep_const;
|
||||
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name));
|
||||
@ -507,8 +465,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c
|
||||
TypeTableEntry *var_peer = get_slice_type(g, child_type, false);
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
|
||||
|
||||
entry->deep_const = child_type->deep_const;
|
||||
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name));
|
||||
|
||||
@ -657,7 +613,6 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
|
||||
|
||||
buf_init_from_str(&entry->name, name);
|
||||
|
||||
entry->deep_const = child_type->deep_const;
|
||||
entry->type_ref = child_type->type_ref;
|
||||
entry->di_type = child_type->di_type;
|
||||
entry->zero_bits = child_type->zero_bits;
|
||||
@ -673,6 +628,23 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
|
||||
return entry;
|
||||
}
|
||||
|
||||
TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry) {
|
||||
TypeTableEntry *fn_type = fn_entry->type_entry;
|
||||
assert(fn_type->id == TypeTableEntryIdFn);
|
||||
if (fn_type->data.fn.bound_fn_parent)
|
||||
return fn_type->data.fn.bound_fn_parent;
|
||||
|
||||
TypeTableEntry *bound_fn_type = new_type_table_entry(TypeTableEntryIdBoundFn);
|
||||
bound_fn_type->data.bound_fn.fn_type = fn_type;
|
||||
bound_fn_type->zero_bits = true;
|
||||
|
||||
buf_resize(&bound_fn_type->name, 0);
|
||||
buf_appendf(&bound_fn_type->name, "(bound %s)", buf_ptr(&fn_type->name));
|
||||
|
||||
fn_type->data.fn.bound_fn_parent = bound_fn_type;
|
||||
return bound_fn_type;
|
||||
}
|
||||
|
||||
// accepts ownership of fn_type_id memory
|
||||
TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_info) {
|
||||
auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
|
||||
@ -681,7 +653,6 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_inf
|
||||
}
|
||||
|
||||
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
|
||||
fn_type->deep_const = true;
|
||||
fn_type->data.fn.fn_type_id = *fn_type_id;
|
||||
|
||||
if (fn_type_id->is_cold) {
|
||||
@ -838,6 +809,7 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo
|
||||
TypeTableEntry *expected_type)
|
||||
{
|
||||
IrExecutable ir_executable = {0};
|
||||
ir_executable.is_inline = true;
|
||||
ir_gen(g, node, scope, &ir_executable);
|
||||
|
||||
if (ir_executable.invalid)
|
||||
@ -851,6 +823,7 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo
|
||||
fprintf(stderr, "}\n");
|
||||
}
|
||||
IrExecutable analyzed_executable = {0};
|
||||
analyzed_executable.is_inline = true;
|
||||
analyzed_executable.backward_branch_quota = default_backward_branch_quota;
|
||||
TypeTableEntry *result_type = ir_analyze(g, &ir_executable, &analyzed_executable, expected_type, node);
|
||||
if (result_type->id == TypeTableEntryIdInvalid)
|
||||
@ -884,8 +857,7 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B
|
||||
|
||||
static bool fn_wants_full_static_eval(FnTableEntry *fn_table_entry) {
|
||||
assert(fn_table_entry);
|
||||
AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;
|
||||
return fn_proto->inline_arg_count == fn_proto->params.length && fn_table_entry->want_pure == WantPureTrue;
|
||||
return false;
|
||||
}
|
||||
|
||||
// fn_table_entry is populated if and only if there is a function definition for this prototype
|
||||
@ -931,6 +903,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
if (!fn_proto->skip) {
|
||||
fn_proto->skip = true;
|
||||
add_node_error(g, child->data.param_decl.type,
|
||||
@ -991,6 +964,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdVar:
|
||||
if (!fn_proto->skip) {
|
||||
fn_proto->skip = true;
|
||||
@ -1023,9 +997,6 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
|
||||
}
|
||||
|
||||
if (fn_table_entry && fn_type_id.return_type->id == TypeTableEntryIdMetaType) {
|
||||
fn_table_entry->want_pure = WantPureTrue;
|
||||
fn_table_entry->want_pure_return_type = fn_proto->return_type;
|
||||
|
||||
ErrorMsg *err_msg = nullptr;
|
||||
for (size_t i = 0; i < fn_proto->params.length; i += 1) {
|
||||
AstNode *param_decl_node = fn_proto->params.at(i);
|
||||
@ -1046,8 +1017,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool gen_debug_info = !(fn_table_entry && fn_wants_full_static_eval(fn_table_entry));
|
||||
bool gen_debug_info = fn_table_entry && !fn_wants_full_static_eval(fn_table_entry);
|
||||
return get_fn_type(g, &fn_type_id, gen_debug_info);
|
||||
}
|
||||
|
||||
@ -1167,8 +1137,6 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
|
||||
assert(decl_node->type == NodeTypeContainerDecl);
|
||||
assert(enum_type->di_type);
|
||||
|
||||
enum_type->deep_const = true;
|
||||
|
||||
uint32_t field_count = decl_node->data.struct_decl.fields.length;
|
||||
|
||||
enum_type->data.enumeration.src_field_count = field_count;
|
||||
@ -1198,11 +1166,6 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
|
||||
type_enum_field->type_entry = field_type;
|
||||
type_enum_field->value = i;
|
||||
|
||||
if (!field_type->deep_const) {
|
||||
enum_type->deep_const = false;
|
||||
}
|
||||
|
||||
|
||||
di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);
|
||||
|
||||
if (field_type->id == TypeTableEntryIdStruct) {
|
||||
@ -1362,8 +1325,6 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
|
||||
assert(decl_node->type == NodeTypeContainerDecl);
|
||||
assert(struct_type->di_type);
|
||||
|
||||
struct_type->deep_const = true;
|
||||
|
||||
size_t field_count = decl_node->data.struct_decl.fields.length;
|
||||
|
||||
struct_type->data.structure.src_field_count = field_count;
|
||||
@ -1389,10 +1350,6 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
|
||||
type_struct_field->src_index = i;
|
||||
type_struct_field->gen_index = SIZE_MAX;
|
||||
|
||||
if (!field_type->deep_const) {
|
||||
struct_type->deep_const = false;
|
||||
}
|
||||
|
||||
if (field_type->id == TypeTableEntryIdStruct) {
|
||||
resolve_struct_type(g, import, field_type);
|
||||
} else if (field_type->id == TypeTableEntryIdEnum) {
|
||||
@ -1537,7 +1494,6 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
|
||||
fn_table_entry->proto_node = proto_node;
|
||||
fn_table_entry->fn_def_node = fn_def_node;
|
||||
fn_table_entry->is_extern = is_extern;
|
||||
fn_table_entry->is_pure = fn_def_node != nullptr;
|
||||
|
||||
get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');
|
||||
|
||||
@ -1852,6 +1808,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
return type_entry;
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -2100,6 +2057,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
return false;
|
||||
|
||||
case TypeTableEntryIdBool:
|
||||
@ -2314,6 +2272,7 @@ static bool is_container(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
return false;
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -2361,6 +2320,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
@ -2429,10 +2389,6 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
if (fn_type->data.fn.gen_param_info) {
|
||||
var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
|
||||
}
|
||||
|
||||
if (!type->deep_const) {
|
||||
fn_table_entry->is_pure = false;
|
||||
}
|
||||
}
|
||||
|
||||
TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type;
|
||||
@ -2768,6 +2724,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdUnreachable:
|
||||
@ -2820,6 +2777,14 @@ static uint32_t hash_size(size_t x) {
|
||||
return x % UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t fn_table_entry_hash(FnTableEntry* value) {
|
||||
return ptr_hash(value);
|
||||
}
|
||||
|
||||
bool fn_table_entry_eql(FnTableEntry *a, FnTableEntry *b) {
|
||||
return ptr_eq(a, b);
|
||||
}
|
||||
|
||||
uint32_t fn_type_id_hash(FnTypeId *id) {
|
||||
uint32_t result = 0;
|
||||
result += id->is_extern ? 3349388391 : 0;
|
||||
@ -2912,6 +2877,7 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
|
||||
case TypeTableEntryIdBlock:
|
||||
return hash_ptr(const_val->data.x_block);
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVar:
|
||||
@ -2990,6 +2956,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry)
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdArray:
|
||||
|
||||
@ -31,6 +31,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,
|
||||
ContainerKind kind, AstNode *decl_node, const char *name);
|
||||
TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
|
||||
TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type);
|
||||
TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry);
|
||||
bool handle_is_ptr(TypeTableEntry *type_entry);
|
||||
void find_libc_include_path(CodeGen *g);
|
||||
void find_libc_lib_path(CodeGen *g);
|
||||
@ -52,7 +53,6 @@ VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context, Buf *n
|
||||
AstNode *find_decl(BlockContext *context, Buf *name);
|
||||
void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only);
|
||||
TopLevelDecl *get_as_top_level_decl(AstNode *node);
|
||||
void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node);
|
||||
bool type_is_codegen_pointer(TypeTableEntry *type);
|
||||
TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry);
|
||||
TypeTableEntry *container_ref_type(TypeTableEntry *type_entry);
|
||||
|
||||
@ -1368,27 +1368,34 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
|
||||
LLVMValueRef fn_val = ir_llvm_value(g, instruction->fn);
|
||||
TypeTableEntry *fn_type = instruction->fn->type_entry;
|
||||
LLVMValueRef fn_val;
|
||||
TypeTableEntry *fn_type;
|
||||
if (instruction->fn_entry) {
|
||||
fn_val = instruction->fn_entry->fn_value;
|
||||
fn_type = instruction->fn_entry->type_entry;
|
||||
} else {
|
||||
assert(instruction->fn_ref);
|
||||
fn_val = ir_llvm_value(g, instruction->fn_ref);
|
||||
fn_type = instruction->fn_ref->type_entry;
|
||||
}
|
||||
|
||||
TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type;
|
||||
bool ret_has_bits = type_has_bits(src_return_type);
|
||||
size_t fn_call_param_count = instruction->arg_count;
|
||||
bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
|
||||
size_t actual_param_count = fn_call_param_count + (first_arg_ret ? 1 : 0);
|
||||
size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0);
|
||||
bool is_var_args = fn_type->data.fn.fn_type_id.is_var_args;
|
||||
LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
|
||||
size_t gen_param_index = 0;
|
||||
if (first_arg_ret) {
|
||||
zig_panic("TODO");
|
||||
//gen_param_values[gen_param_index] = node->data.fn_call_expr.tmp_ptr;
|
||||
//gen_param_index += 1;
|
||||
gen_param_values[gen_param_index] = instruction->tmp_ptr;
|
||||
gen_param_index += 1;
|
||||
}
|
||||
for (size_t call_i = 0; call_i < fn_call_param_count; call_i += 1) {
|
||||
for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
|
||||
IrInstruction *param_instruction = instruction->args[call_i];
|
||||
LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
|
||||
assert(param_value);
|
||||
TypeTableEntry *param_type = param_instruction->type_entry;
|
||||
if (is_var_args || type_has_bits(param_type)) {
|
||||
LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
|
||||
assert(param_value);
|
||||
gen_param_values[gen_param_index] = param_value;
|
||||
gen_param_index += 1;
|
||||
}
|
||||
@ -1402,8 +1409,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
} else if (!ret_has_bits) {
|
||||
return nullptr;
|
||||
} else if (first_arg_ret) {
|
||||
zig_panic("TODO");
|
||||
//return node->data.fn_call_expr.tmp_ptr;
|
||||
return instruction->tmp_ptr;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
@ -1422,6 +1428,22 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
|
||||
return LLVMBuildStructGEP(g->builder, struct_ptr, field->gen_index, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionEnumFieldPtr *instruction)
|
||||
{
|
||||
LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
|
||||
TypeEnumField *field = instruction->field;
|
||||
|
||||
if (!type_has_bits(field->type_entry))
|
||||
return nullptr;
|
||||
|
||||
LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
|
||||
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_gen_union_index, "");
|
||||
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
|
||||
|
||||
return bitcasted_union_field_ptr;
|
||||
}
|
||||
|
||||
static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
|
||||
const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;
|
||||
size_t len = tok->end - tok->start - 2;
|
||||
@ -1691,6 +1713,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdSwitchTarget:
|
||||
case IrInstructionIdStaticEval:
|
||||
case IrInstructionIdImport:
|
||||
case IrInstructionIdContainerInitFields:
|
||||
zig_unreachable();
|
||||
case IrInstructionIdReturn:
|
||||
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
|
||||
@ -1720,6 +1743,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
return ir_render_call(g, executable, (IrInstructionCall *)instruction);
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
|
||||
case IrInstructionIdEnumFieldPtr:
|
||||
return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);
|
||||
case IrInstructionIdAsm:
|
||||
return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
|
||||
case IrInstructionIdTestNull:
|
||||
@ -1738,7 +1763,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
return ir_render_ref(g, executable, (IrInstructionRef *)instruction);
|
||||
case IrInstructionIdSwitchVar:
|
||||
case IrInstructionIdContainerInitList:
|
||||
case IrInstructionIdContainerInitFields:
|
||||
case IrInstructionIdStructInit:
|
||||
case IrInstructionIdEnumTag:
|
||||
case IrInstructionIdArrayLen:
|
||||
zig_panic("TODO render more IR instructions to LLVM");
|
||||
@ -1960,6 +1985,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
|
||||
@ -2197,7 +2223,6 @@ static void do_code_gen(CodeGen *g) {
|
||||
|
||||
TypeTableEntry *fn_type = fn_table_entry->type_entry;
|
||||
|
||||
bool is_sret = false;
|
||||
if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {
|
||||
// nothing to do
|
||||
} else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) {
|
||||
@ -2208,10 +2233,6 @@ static void do_code_gen(CodeGen *g) {
|
||||
LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);
|
||||
LLVMAddAttribute(first_arg, LLVMStructRetAttribute);
|
||||
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 1);
|
||||
is_sret = true;
|
||||
}
|
||||
if (fn_table_entry->is_pure && !is_sret && g->is_release_build) {
|
||||
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMReadOnlyAttribute);
|
||||
}
|
||||
|
||||
|
||||
@ -2234,9 +2255,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
if (param_is_noalias) {
|
||||
LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
|
||||
}
|
||||
if ((param_type->id == TypeTableEntryIdPointer && (param_type->data.pointer.is_const || fn_table_entry->is_pure)) ||
|
||||
is_byval)
|
||||
{
|
||||
if ((param_type->id == TypeTableEntryIdPointer && param_type->data.pointer.is_const) || is_byval) {
|
||||
LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);
|
||||
}
|
||||
if (param_type->id == TypeTableEntryIdPointer) {
|
||||
@ -2339,6 +2358,15 @@ static void do_code_gen(CodeGen *g) {
|
||||
} else if (instruction->id == IrInstructionIdRef) {
|
||||
IrInstructionRef *ref_instruction = (IrInstructionRef *)instruction;
|
||||
slot = &ref_instruction->tmp_ptr;
|
||||
} else if (instruction->id == IrInstructionIdContainerInitList) {
|
||||
IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction;
|
||||
slot = &container_init_list_instruction->tmp_ptr;
|
||||
} else if (instruction->id == IrInstructionIdStructInit) {
|
||||
IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction;
|
||||
slot = &struct_init_instruction->tmp_ptr;
|
||||
} else if (instruction->id == IrInstructionIdCall) {
|
||||
IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
|
||||
slot = &call_instruction->tmp_ptr;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -2464,46 +2492,39 @@ static void define_builtin_types(CodeGen *g) {
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNamespace);
|
||||
buf_init_from_str(&entry->name, "(namespace)");
|
||||
entry->zero_bits = true;
|
||||
entry->deep_const = true;
|
||||
g->builtin_types.entry_namespace = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBlock);
|
||||
buf_init_from_str(&entry->name, "(block)");
|
||||
entry->zero_bits = true;
|
||||
entry->deep_const = true;
|
||||
g->builtin_types.entry_block = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat);
|
||||
buf_init_from_str(&entry->name, "(float literal)");
|
||||
entry->zero_bits = true;
|
||||
entry->deep_const = true;
|
||||
g->builtin_types.entry_num_lit_float = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt);
|
||||
buf_init_from_str(&entry->name, "(integer literal)");
|
||||
entry->zero_bits = true;
|
||||
entry->deep_const = true;
|
||||
g->builtin_types.entry_num_lit_int = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit);
|
||||
buf_init_from_str(&entry->name, "(undefined)");
|
||||
entry->deep_const = true;
|
||||
g->builtin_types.entry_undef = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNullLit);
|
||||
buf_init_from_str(&entry->name, "(null)");
|
||||
entry->deep_const = true;
|
||||
g->builtin_types.entry_null = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVar);
|
||||
buf_init_from_str(&entry->name, "(var)");
|
||||
entry->deep_const = true;
|
||||
g->builtin_types.entry_var = entry;
|
||||
}
|
||||
|
||||
@ -2514,7 +2535,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
|
||||
entry->type_ref = LLVMIntType(size_in_bits);
|
||||
entry->deep_const = true;
|
||||
|
||||
const char u_or_i = is_signed ? 'i' : 'u';
|
||||
buf_resize(&entry->name, 0);
|
||||
@ -2554,7 +2574,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
|
||||
entry->type_ref = LLVMIntType(size_in_bits);
|
||||
entry->deep_const = true;
|
||||
|
||||
buf_init_from_str(&entry->name, info->name);
|
||||
|
||||
@ -2574,7 +2593,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
|
||||
entry->type_ref = LLVMInt1Type();
|
||||
entry->deep_const = true;
|
||||
buf_init_from_str(&entry->name, "bool");
|
||||
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
|
||||
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
|
||||
@ -2590,7 +2608,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
bool is_signed = is_signed_list[sign_i];
|
||||
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
|
||||
entry->deep_const = true;
|
||||
entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
|
||||
|
||||
const char u_or_i = is_signed ? 'i' : 'u';
|
||||
@ -2616,7 +2633,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
|
||||
entry->deep_const = true;
|
||||
entry->type_ref = LLVMFloatType();
|
||||
buf_init_from_str(&entry->name, "f32");
|
||||
entry->data.floating.bit_count = 32;
|
||||
@ -2632,7 +2648,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
|
||||
entry->deep_const = true;
|
||||
entry->type_ref = LLVMDoubleType();
|
||||
buf_init_from_str(&entry->name, "f64");
|
||||
entry->data.floating.bit_count = 64;
|
||||
@ -2648,7 +2663,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
|
||||
entry->deep_const = true;
|
||||
entry->type_ref = LLVMX86FP80Type();
|
||||
buf_init_from_str(&entry->name, "c_long_double");
|
||||
entry->data.floating.bit_count = 80;
|
||||
@ -2664,7 +2678,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
|
||||
entry->deep_const = true;
|
||||
entry->type_ref = LLVMVoidType();
|
||||
entry->zero_bits = true;
|
||||
buf_init_from_str(&entry->name, "void");
|
||||
@ -2677,7 +2690,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable);
|
||||
entry->deep_const = true;
|
||||
entry->type_ref = LLVMVoidType();
|
||||
entry->zero_bits = true;
|
||||
buf_init_from_str(&entry->name, "unreachable");
|
||||
@ -2687,7 +2699,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType);
|
||||
entry->deep_const = true;
|
||||
buf_init_from_str(&entry->name, "type");
|
||||
entry->zero_bits = true;
|
||||
g->builtin_types.entry_type = entry;
|
||||
@ -2710,7 +2721,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);
|
||||
entry->deep_const = true;
|
||||
buf_init_from_str(&entry->name, "error");
|
||||
|
||||
// TODO allow overriding this type and keep track of max value and emit an
|
||||
@ -2726,7 +2736,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->deep_const = true;
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@OS");
|
||||
uint32_t field_count = target_os_count();
|
||||
@ -2752,7 +2761,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->deep_const = true;
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@Arch");
|
||||
uint32_t field_count = target_arch_count();
|
||||
@ -2784,7 +2792,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->deep_const = true;
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@Environ");
|
||||
uint32_t field_count = target_environ_count();
|
||||
@ -2811,7 +2818,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->deep_const = true;
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@ObjectFormat");
|
||||
uint32_t field_count = target_oformat_count();
|
||||
@ -2838,7 +2844,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->deep_const = true;
|
||||
buf_init_from_str(&entry->name, "AtomicOrder");
|
||||
uint32_t field_count = 6;
|
||||
entry->data.enumeration.src_field_count = field_count;
|
||||
@ -2998,7 +3003,6 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdUnreachable, "unreachable", 0);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnTest, "setFnTest", 2);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnVisible, "setFnVisible", 2);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnStaticEval, "setFnStaticEval", 2);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnNoInline, "setFnNoInline", 2);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
|
||||
}
|
||||
@ -3287,6 +3291,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
|
||||
@ -56,6 +56,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty
|
||||
case TypeTableEntryIdBlock:
|
||||
zig_panic("TODO");
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVar:
|
||||
|
||||
2029
src/ir.cpp
2029
src/ir.cpp
File diff suppressed because it is too large
Load Diff
146
src/ir_print.cpp
146
src/ir_print.cpp
@ -7,6 +7,8 @@ struct IrPrint {
|
||||
int indent_size;
|
||||
};
|
||||
|
||||
static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction);
|
||||
|
||||
static void ir_print_indent(IrPrint *irp) {
|
||||
for (int i = 0; i < irp->indent; i += 1) {
|
||||
fprintf(irp->f, " ");
|
||||
@ -35,25 +37,30 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
|
||||
break;
|
||||
}
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdTypeDecl:
|
||||
return ir_print_const_value(irp, type_entry->data.type_decl.canonical_type, const_val);
|
||||
case TypeTableEntryIdInvalid:
|
||||
fprintf(irp->f, "(invalid)");
|
||||
break;
|
||||
return;
|
||||
case TypeTableEntryIdVar:
|
||||
fprintf(irp->f, "(var)");
|
||||
return;
|
||||
case TypeTableEntryIdVoid:
|
||||
fprintf(irp->f, "{}");
|
||||
break;
|
||||
return;
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
fprintf(irp->f, "%f", const_val->data.x_bignum.data.x_float);
|
||||
break;
|
||||
return;
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
{
|
||||
BigNum *bignum = &const_val->data.x_bignum;
|
||||
const char *negative_str = bignum->is_negative ? "-" : "";
|
||||
fprintf(irp->f, "%s%llu", negative_str, bignum->data.x_uint);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdMetaType:
|
||||
fprintf(irp->f, "%s", buf_ptr(&const_val->data.x_type->name));
|
||||
break;
|
||||
return;
|
||||
case TypeTableEntryIdInt:
|
||||
{
|
||||
BigNum *bignum = &const_val->data.x_bignum;
|
||||
@ -61,31 +68,38 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
|
||||
const char *negative_str = bignum->is_negative ? "-" : "";
|
||||
fprintf(irp->f, "%s%llu", negative_str, bignum->data.x_uint);
|
||||
}
|
||||
break;
|
||||
return;
|
||||
case TypeTableEntryIdFloat:
|
||||
{
|
||||
BigNum *bignum = &const_val->data.x_bignum;
|
||||
assert(bignum->kind == BigNumKindFloat);
|
||||
fprintf(irp->f, "%f", bignum->data.x_float);
|
||||
}
|
||||
return;
|
||||
case TypeTableEntryIdUnreachable:
|
||||
fprintf(irp->f, "@unreachable()");
|
||||
break;
|
||||
return;
|
||||
case TypeTableEntryIdBool:
|
||||
{
|
||||
const char *value = const_val->data.x_bool ? "true" : "false";
|
||||
fprintf(irp->f, "%s", value);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdPointer:
|
||||
fprintf(irp->f, "&");
|
||||
ir_print_const_value(irp, type_entry->data.pointer.child_type, const_ptr_pointee(const_val));
|
||||
break;
|
||||
return;
|
||||
case TypeTableEntryIdFn:
|
||||
{
|
||||
FnTableEntry *fn_entry = const_val->data.x_fn;
|
||||
fprintf(irp->f, "%s", buf_ptr(&fn_entry->symbol_name));
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdBlock:
|
||||
{
|
||||
AstNode *node = const_val->data.x_block->node;
|
||||
fprintf(irp->f, "(scope:%zu:%zu)", node->line + 1, node->column + 1);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdArray:
|
||||
{
|
||||
@ -99,12 +113,17 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
|
||||
ir_print_const_value(irp, child_type, child_value);
|
||||
}
|
||||
fprintf(irp->f, "}");
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdNullLit:
|
||||
{
|
||||
fprintf(irp->f, "null");
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdUndefLit:
|
||||
{
|
||||
fprintf(irp->f, "undefined");
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdMaybe:
|
||||
{
|
||||
@ -113,26 +132,56 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
|
||||
} else {
|
||||
fprintf(irp->f, "null");
|
||||
}
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdNamespace:
|
||||
{
|
||||
ImportTableEntry *import = const_val->data.x_import;
|
||||
fprintf(irp->f, "(namespace: %s)", buf_ptr(import->path));
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdFloat:
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdTypeDecl:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
zig_panic("TODO render more constant types in IR printer");
|
||||
{
|
||||
TypeTableEntry *type_entry = const_val->data.x_type;
|
||||
AstNode *decl_node = type_entry->data.generic_fn.decl_node;
|
||||
assert(decl_node->type == NodeTypeFnProto);
|
||||
fprintf(irp->f, "%s", buf_ptr(decl_node->data.fn_proto.name));
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdBoundFn:
|
||||
{
|
||||
FnTableEntry *fn_entry = const_val->data.x_bound_fn.fn;
|
||||
fprintf(irp->f, "bound %s to ", buf_ptr(&fn_entry->symbol_name));
|
||||
ir_print_other_instruction(irp, const_val->data.x_bound_fn.first_arg);
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdStruct:
|
||||
{
|
||||
fprintf(irp->f, "(struct %s constant)", buf_ptr(&type_entry->name));
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdEnum:
|
||||
{
|
||||
fprintf(irp->f, "(enum %s constant)", buf_ptr(&type_entry->name));
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
{
|
||||
fprintf(irp->f, "(error union %s constant)", buf_ptr(&type_entry->name));
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdUnion:
|
||||
{
|
||||
fprintf(irp->f, "(union %s constant)", buf_ptr(&type_entry->name));
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdPureError:
|
||||
{
|
||||
fprintf(irp->f, "(pure error constant)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
@ -285,12 +334,16 @@ static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instr
|
||||
static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
|
||||
fprintf(irp->f, "cast ");
|
||||
ir_print_other_instruction(irp, cast_instruction->value);
|
||||
fprintf(irp->f, " to ");
|
||||
ir_print_other_instruction(irp, cast_instruction->dest_type);
|
||||
fprintf(irp->f, " to %s", buf_ptr(&cast_instruction->dest_type->name));
|
||||
}
|
||||
|
||||
static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
|
||||
ir_print_other_instruction(irp, call_instruction->fn);
|
||||
if (call_instruction->fn_entry) {
|
||||
fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
|
||||
} else {
|
||||
assert(call_instruction->fn_ref);
|
||||
ir_print_other_instruction(irp, call_instruction->fn_ref);
|
||||
}
|
||||
fprintf(irp->f, "(");
|
||||
for (size_t i = 0; i < call_instruction->arg_count; i += 1) {
|
||||
IrInstruction *arg = call_instruction->args[i];
|
||||
@ -347,13 +400,24 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI
|
||||
ir_print_other_instruction(irp, instruction->container_type);
|
||||
fprintf(irp->f, "{");
|
||||
for (size_t i = 0; i < instruction->field_count; i += 1) {
|
||||
Buf *name = instruction->field_names[i];
|
||||
IrInstruction *field_value = instruction->field_values[i];
|
||||
IrInstructionContainerInitFieldsField *field = &instruction->fields[i];
|
||||
const char *comma = (i == 0) ? "" : ", ";
|
||||
fprintf(irp->f, "%s.%s = ", comma, buf_ptr(name));
|
||||
ir_print_other_instruction(irp, field_value);
|
||||
fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field->name));
|
||||
ir_print_other_instruction(irp, field->value);
|
||||
}
|
||||
fprintf(irp->f, "}");
|
||||
fprintf(irp->f, "} // container init");
|
||||
}
|
||||
|
||||
static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruction) {
|
||||
fprintf(irp->f, "%s {", buf_ptr(&instruction->struct_type->name));
|
||||
for (size_t i = 0; i < instruction->field_count; i += 1) {
|
||||
IrInstructionStructInitField *field = &instruction->fields[i];
|
||||
Buf *field_name = field->type_struct_field->name;
|
||||
const char *comma = (i == 0) ? "" : ", ";
|
||||
fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field_name));
|
||||
ir_print_other_instruction(irp, field->value);
|
||||
}
|
||||
fprintf(irp->f, "} // struct init");
|
||||
}
|
||||
|
||||
static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {
|
||||
@ -406,10 +470,9 @@ static void ir_print_ptr_type_child(IrPrint *irp, IrInstructionPtrTypeChild *ins
|
||||
}
|
||||
|
||||
static void ir_print_field_ptr(IrPrint *irp, IrInstructionFieldPtr *instruction) {
|
||||
fprintf(irp->f, "@FieldPtr(&");
|
||||
fprintf(irp->f, "fieldptr ");
|
||||
ir_print_other_instruction(irp, instruction->container_ptr);
|
||||
fprintf(irp->f, ".%s", buf_ptr(instruction->field_name));
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr *instruction) {
|
||||
@ -419,6 +482,13 @@ static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *instruction) {
|
||||
fprintf(irp->f, "@EnumFieldPtr(&");
|
||||
ir_print_other_instruction(irp, instruction->enum_ptr);
|
||||
fprintf(irp->f, ".%s", buf_ptr(instruction->field->name));
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_set_fn_test(IrPrint *irp, IrInstructionSetFnTest *instruction) {
|
||||
fprintf(irp->f, "@setFnTest(");
|
||||
ir_print_other_instruction(irp, instruction->fn_value);
|
||||
@ -632,6 +702,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdContainerInitFields:
|
||||
ir_print_container_init_fields(irp, (IrInstructionContainerInitFields *)instruction);
|
||||
break;
|
||||
case IrInstructionIdStructInit:
|
||||
ir_print_struct_init(irp, (IrInstructionStructInit *)instruction);
|
||||
break;
|
||||
case IrInstructionIdUnreachable:
|
||||
ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction);
|
||||
break;
|
||||
@ -662,6 +735,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
ir_print_struct_field_ptr(irp, (IrInstructionStructFieldPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdEnumFieldPtr:
|
||||
ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSetFnTest:
|
||||
ir_print_set_fn_test(irp, (IrInstructionSetFnTest *)instruction);
|
||||
break;
|
||||
|
||||
@ -84,6 +84,18 @@ end:
|
||||
}
|
||||
var goto_counter: i32 = 0;
|
||||
|
||||
|
||||
|
||||
struct FooA {
|
||||
fn add(a: i32, b: i32) -> i32 { a + b }
|
||||
}
|
||||
const foo_a = FooA {};
|
||||
|
||||
fn testStructStatic() {
|
||||
const result = FooA.add(3, 4);
|
||||
assert(result == 7);
|
||||
}
|
||||
|
||||
fn assert(ok: bool) {
|
||||
if (!ok)
|
||||
@unreachable();
|
||||
@ -98,6 +110,7 @@ fn runAllTests() {
|
||||
testInlineSwitch();
|
||||
testNamespaceFnCall();
|
||||
gotoAndLabels();
|
||||
testStructStatic();
|
||||
}
|
||||
|
||||
export nakedcc fn _start() -> unreachable {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user