IR: function call porting progress

also implemented container init
generics is still todo
This commit is contained in:
Andrew Kelley 2016-11-28 02:40:01 -05:00
parent 9e7c475979
commit eb5693d91f
8 changed files with 914 additions and 1561 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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