aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp450
1 files changed, 301 insertions, 149 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index 96bf78bdf5..84c0332c9b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -189,6 +189,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnTest *) {
return IrInstructionIdSetFnTest;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
+ return IrInstructionIdArrayType;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
+ return IrInstructionIdSliceType;
+}
+
template<typename T>
static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -716,19 +724,30 @@ static IrInstruction *ir_build_set_fn_test(IrBuilder *irb, AstNode *source_node,
return &instruction->base;
}
-//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
-// size_t result = 0;
-// while (inner_block != outer_block) {
-// if (inner_block->node->type == NodeTypeDefer &&
-// (inner_block->node->data.defer.kind == ReturnKindError ||
-// inner_block->node->data.defer.kind == ReturnKindMaybe))
-// {
-// result += 1;
-// }
-// inner_block = inner_block->parent;
-// }
-// return result;
-//}
+static IrInstruction *ir_build_array_type(IrBuilder *irb, AstNode *source_node, IrInstruction *size,
+ IrInstruction *child_type)
+{
+ IrInstructionArrayType *instruction = ir_build_instruction<IrInstructionArrayType>(irb, source_node);
+ instruction->size = size;
+ instruction->child_type = child_type;
+
+ ir_ref_instruction(size);
+ ir_ref_instruction(child_type);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_slice_type(IrBuilder *irb, AstNode *source_node, bool is_const,
+ IrInstruction *child_type)
+{
+ IrInstructionSliceType *instruction = ir_build_instruction<IrInstructionSliceType>(irb, source_node);
+ instruction->is_const = is_const;
+ instruction->child_type = child_type;
+
+ ir_ref_instruction(child_type);
+
+ return &instruction->base;
+}
static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
bool gen_error_defers, bool gen_maybe_defers)
@@ -777,23 +796,6 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *node) {
zig_unreachable();
}
-//static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) {
-// BlockContext *defer_inner_block = source_node->block_context;
-// BlockContext *defer_outer_block = irb->node->block_context;
-// if (rk == ReturnKnowledgeUnknown) {
-// if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) {
-// // generate branching code that checks the return value and generates defers
-// // if the return value is error
-// zig_panic("TODO");
-// }
-// } else if (rk != ReturnKnowledgeSkipDefers) {
-// ir_gen_defers_for_block(irb, defer_inner_block, defer_outer_block,
-// rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull);
-// }
-//
-// return ir_build_return(irb, source_node, value);
-//}
-
static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {
assert(basic_block);
@@ -1588,6 +1590,38 @@ static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, AstNode *node) {
return ir_build_const_bool(irb, node, node->data.bool_literal.value);
}
+static IrInstruction *ir_gen_array_type(IrBuilder *irb, AstNode *node) {
+ assert(node->type == NodeTypeArrayType);
+
+ AstNode *size_node = node->data.array_type.size;
+ AstNode *child_type_node = node->data.array_type.child_type;
+ bool is_const = node->data.array_type.is_const;
+
+ if (size_node) {
+ if (is_const) {
+ add_node_error(irb->codegen, node, buf_create_from_str("const qualifier invalid on array type"));
+ return irb->codegen->invalid_instruction;
+ }
+
+ IrInstruction *size_value = ir_gen_node(irb, size_node, node->block_context);
+ if (size_value == irb->codegen->invalid_instruction)
+ return size_value;
+
+ IrInstruction *child_type = ir_gen_node(irb, child_type_node, node->block_context);
+ if (child_type == irb->codegen->invalid_instruction)
+ return child_type;
+
+ return ir_build_array_type(irb, node, size_value, child_type);
+ } else {
+ IrInstruction *child_type = ir_gen_node_extra(irb, child_type_node,
+ node->block_context, LValPurposeAddressOf);
+ if (child_type == irb->codegen->invalid_instruction)
+ return child_type;
+
+ return ir_build_slice_type(irb, node, is_const, child_type);
+ }
+}
+
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
LValPurpose lval)
{
@@ -1627,6 +1661,8 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
return ir_gen_this_literal(irb, node);
case NodeTypeBoolLiteral:
return ir_gen_bool_literal(irb, node);
+ case NodeTypeArrayType:
+ return ir_gen_array_type(irb, node);
case NodeTypeUnwrapErrorExpr:
case NodeTypeDefer:
case NodeTypeSliceExpr:
@@ -1644,7 +1680,6 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
case NodeTypeZeroesLiteral:
case NodeTypeErrorType:
case NodeTypeTypeLiteral:
- case NodeTypeArrayType:
case NodeTypeVarLiteral:
case NodeTypeRoot:
case NodeTypeFnProto:
@@ -1703,51 +1738,6 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) {
return ir_gen(codegn, body_node, scope, ir_executable);
}
-/*
-static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) {
- assert(node->type == NodeTypeGoto);
- Buf *label_name = node->data.goto_expr.name;
- BlockContext *context = node->block_context;
- assert(context);
- LabelTableEntry *label = find_label(g, context, label_name);
-
- if (!label) {
- add_node_error(g, node, buf_sprintf("no label in scope named '%s'", buf_ptr(label_name)));
- return;
- }
-
- label->used = true;
- node->data.goto_expr.label_entry = label;
-}
-
- for (size_t i = 0; i < fn_table_entry->goto_list.length; i += 1) {
- AstNode *goto_node = fn_table_entry->goto_list.at(i);
- assert(goto_node->type == NodeTypeGoto);
- analyze_goto_pass2(g, import, goto_node);
- }
-
- for (size_t i = 0; i < fn_table_entry->all_labels.length; i += 1) {
- LabelTableEntry *label = fn_table_entry->all_labels.at(i);
- if (!label->used) {
- add_node_error(g, label->decl_node,
- buf_sprintf("label '%s' defined but not used",
- buf_ptr(label->decl_node->data.label.name)));
- }
- }
-*/
-
-//static LabelTableEntry *find_label(CodeGen *g, BlockContext *orig_context, Buf *name) {
-// BlockContext *context = orig_context;
-// while (context && context->fn_entry) {
-// auto entry = context->label_table.maybe_get(name);
-// if (entry) {
-// return entry->value;
-// }
-// context = context->parent;
-// }
-// return nullptr;
-//}
-
static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type) {
TypeTableEntry *other_type_underlying = get_underlying_type(other_type);
@@ -2970,6 +2960,59 @@ static TypeTableEntry *ir_analyze_unary_bool_not(IrAnalyze *ira, IrInstructionUn
return bool_type;
}
+static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
+ assert(un_op_instruction->op_id == IrUnOpError);
+ IrInstruction *value = un_op_instruction->value->other;
+
+ TypeTableEntry *type_entry = value->type_entry;
+ if (type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ TypeTableEntry *meta_type = ir_resolve_type(ira, value);
+ TypeTableEntry *underlying_meta_type = get_underlying_type(meta_type);
+ switch (underlying_meta_type->id) {
+ case TypeTableEntryIdTypeDecl:
+ zig_unreachable();
+ case TypeTableEntryIdInvalid:
+ return ira->codegen->builtin_types.entry_invalid;
+ case TypeTableEntryIdVoid:
+ case TypeTableEntryIdBool:
+ case TypeTableEntryIdInt:
+ case TypeTableEntryIdFloat:
+ case TypeTableEntryIdPointer:
+ case TypeTableEntryIdArray:
+ case TypeTableEntryIdStruct:
+ case TypeTableEntryIdMaybe:
+ case TypeTableEntryIdErrorUnion:
+ case TypeTableEntryIdPureError:
+ case TypeTableEntryIdEnum:
+ case TypeTableEntryIdUnion:
+ case TypeTableEntryIdFn:
+ case TypeTableEntryIdGenericFn:
+ {
+ ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,
+ value->static_value.depends_on_compile_var);
+ TypeTableEntry *result_type = get_error_type(ira->codegen, meta_type);
+ out_val->data.x_type = result_type;
+ return ira->codegen->builtin_types.entry_type;
+ }
+ case TypeTableEntryIdMetaType:
+ case TypeTableEntryIdNumLitFloat:
+ case TypeTableEntryIdNumLitInt:
+ case TypeTableEntryIdUndefLit:
+ case TypeTableEntryIdNullLit:
+ case TypeTableEntryIdNamespace:
+ case TypeTableEntryIdBlock:
+ case TypeTableEntryIdUnreachable:
+ case TypeTableEntryIdVar:
+ add_node_error(ira->codegen, un_op_instruction->base.source_node,
+ buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name)));
+ // TODO if meta_type is type decl, add note pointing to type decl declaration
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ zig_unreachable();
+}
+
static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
IrUnOp op_id = un_op_instruction->op_id;
switch (op_id) {
@@ -2977,7 +3020,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
zig_unreachable();
case IrUnOpBoolNot:
return ir_analyze_unary_bool_not(ira, un_op_instruction);
- zig_panic("TODO analyze PrefixOpBoolNot");
case IrUnOpBinNot:
zig_panic("TODO analyze PrefixOpBinNot");
//{
@@ -3106,31 +3148,7 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
// }
//}
case IrUnOpError:
- zig_panic("TODO analyze PrefixOpError");
- //{
- // TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, *expr_node);
-
- // if (type_entry->id == TypeTableEntryIdInvalid) {
- // return type_entry;
- // } else if (type_entry->id == TypeTableEntryIdMetaType) {
- // TypeTableEntry *meta_type = resolve_type(g, *expr_node);
- // if (meta_type->id == TypeTableEntryIdInvalid) {
- // return meta_type;
- // } else if (meta_type->id == TypeTableEntryIdUnreachable) {
- // add_node_error(g, node, buf_create_from_str("unable to wrap unreachable in error type"));
- // return g->builtin_types.entry_invalid;
- // } else {
- // return resolve_expr_const_val_as_type(g, node, get_error_type(g, meta_type), false);
- // }
- // } else if (type_entry->id == TypeTableEntryIdUnreachable) {
- // add_node_error(g, *expr_node, buf_sprintf("unable to wrap unreachable in error type"));
- // return g->builtin_types.entry_invalid;
- // } else {
- // // TODO eval const expr
- // return get_error_type(g, type_entry);
- // }
-
- //}
+ return ir_analyze_unary_prefix_op_err(ira, un_op_instruction);
case IrUnOpUnwrapError:
zig_panic("TODO analyze PrefixOpUnwrapError");
//{
@@ -3691,6 +3709,59 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_test(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_void;
}
+static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
+ IrInstructionSliceType *slice_type_instruction)
+{
+ IrInstruction *child_type = slice_type_instruction->child_type->other;
+ if (child_type->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+ bool is_const = slice_type_instruction->is_const;
+
+ TypeTableEntry *resolved_child_type = ir_resolve_type(ira, child_type);
+ TypeTableEntry *canon_child_type = get_underlying_type(resolved_child_type);
+ switch (canon_child_type->id) {
+ case TypeTableEntryIdTypeDecl:
+ zig_unreachable();
+ case TypeTableEntryIdInvalid:
+ return ira->codegen->builtin_types.entry_invalid;
+ case TypeTableEntryIdVar:
+ case TypeTableEntryIdUnreachable:
+ case TypeTableEntryIdUndefLit:
+ case TypeTableEntryIdNullLit:
+ case TypeTableEntryIdBlock:
+ add_node_error(ira->codegen, slice_type_instruction->base.source_node,
+ buf_sprintf("slice of type '%s' not allowed", buf_ptr(&resolved_child_type->name)));
+ // TODO if this is a typedecl, add error note showing the declaration of the type decl
+ return ira->codegen->builtin_types.entry_invalid;
+ case TypeTableEntryIdMetaType:
+ case TypeTableEntryIdVoid:
+ case TypeTableEntryIdBool:
+ case TypeTableEntryIdInt:
+ case TypeTableEntryIdFloat:
+ case TypeTableEntryIdPointer:
+ case TypeTableEntryIdArray:
+ case TypeTableEntryIdStruct:
+ case TypeTableEntryIdNumLitFloat:
+ case TypeTableEntryIdNumLitInt:
+ case TypeTableEntryIdMaybe:
+ case TypeTableEntryIdErrorUnion:
+ case TypeTableEntryIdPureError:
+ case TypeTableEntryIdEnum:
+ case TypeTableEntryIdUnion:
+ case TypeTableEntryIdFn:
+ case TypeTableEntryIdNamespace:
+ case TypeTableEntryIdGenericFn:
+ {
+ TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const);
+ ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base,
+ child_type->static_value.depends_on_compile_var);
+ out_val->data.x_type = result_type;
+ return ira->codegen->builtin_types.entry_type;
+ }
+ }
+ zig_unreachable();
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -3735,11 +3806,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction);
case IrInstructionIdSetFnTest:
return ir_analyze_instruction_set_fn_test(ira, (IrInstructionSetFnTest *)instruction);
+ case IrInstructionIdSliceType:
+ return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
case IrInstructionIdSwitchBr:
case IrInstructionIdCast:
case IrInstructionIdContainerInitList:
case IrInstructionIdContainerInitFields:
case IrInstructionIdStructFieldPtr:
+ case IrInstructionIdArrayType:
zig_panic("TODO analyze more instructions");
}
zig_unreachable();
@@ -3836,6 +3910,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdPtrTypeChild:
case IrInstructionIdReadField:
case IrInstructionIdStructFieldPtr:
+ case IrInstructionIdArrayType:
+ case IrInstructionIdSliceType:
return false;
}
zig_unreachable();
@@ -6782,53 +6858,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// false, nullptr, false);
//}
//
-//static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// TypeTableEntry *expected_type, AstNode *node)
-//{
-// AstNode *size_node = node->data.array_type.size;
-//
-// TypeTableEntry *child_type = analyze_type_expr_pointer_only(g, import, context,
-// node->data.array_type.child_type, true);
-//
-// if (child_type->id == TypeTableEntryIdUnreachable) {
-// add_node_error(g, node, buf_create_from_str("array of unreachable not allowed"));
-// return g->builtin_types.entry_invalid;
-// } else if (child_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (size_node) {
-// child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type);
-// TypeTableEntry *size_type = analyze_expression(g, import, context,
-// g->builtin_types.entry_usize, size_node);
-// if (size_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
-// if (const_val->ok) {
-// if (const_val->data.x_bignum.is_negative) {
-// add_node_error(g, size_node,
-// buf_sprintf("array size %s is negative",
-// buf_ptr(bignum_to_buf(&const_val->data.x_bignum))));
-// return g->builtin_types.entry_invalid;
-// } else {
-// return resolve_expr_const_val_as_type(g, node,
-// get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint), false);
-// }
-// } else if (context->fn_entry) {
-// return resolve_expr_const_val_as_type(g, node,
-// get_slice_type(g, child_type, node->data.array_type.is_const), false);
-// } else {
-// add_node_error(g, first_executing_node(size_node),
-// buf_sprintf("unable to evaluate constant expression"));
-// return g->builtin_types.entry_invalid;
-// }
-// } else {
-// TypeTableEntry *slice_type = get_slice_type(g, child_type, node->data.array_type.is_const);
-// return resolve_expr_const_val_as_type(g, node, slice_type, false);
-// }
-//}
//
//static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
// TypeTableEntry *expected_type, AstNode *node)
@@ -7218,3 +7247,126 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// }
//}
//
+//static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+// TypeTableEntry *expected_type, AstNode *node)
+//{
+// AstNode *size_node = node->data.array_type.size;
+//
+// TypeTableEntry *child_type = analyze_type_expr_pointer_only(g, import, context,
+// node->data.array_type.child_type, true);
+//
+// if (child_type->id == TypeTableEntryIdUnreachable) {
+// add_node_error(g, node, buf_create_from_str("array of unreachable not allowed"));
+// return g->builtin_types.entry_invalid;
+// } else if (child_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (size_node) {
+// child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type);
+// TypeTableEntry *size_type = analyze_expression(g, import, context,
+// g->builtin_types.entry_usize, size_node);
+// if (size_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
+// if (const_val->ok) {
+// if (const_val->data.x_bignum.is_negative) {
+// add_node_error(g, size_node,
+// buf_sprintf("array size %s is negative",
+// buf_ptr(bignum_to_buf(&const_val->data.x_bignum))));
+// return g->builtin_types.entry_invalid;
+// } else {
+// return resolve_expr_const_val_as_type(g, node,
+// get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint), false);
+// }
+// } else if (context->fn_entry) {
+// return resolve_expr_const_val_as_type(g, node,
+// get_slice_type(g, child_type, node->data.array_type.is_const), false);
+// } else {
+// add_node_error(g, first_executing_node(size_node),
+// buf_sprintf("unable to evaluate constant expression"));
+// return g->builtin_types.entry_invalid;
+// }
+// } else {
+// TypeTableEntry *slice_type = get_slice_type(g, child_type, node->data.array_type.is_const);
+// return resolve_expr_const_val_as_type(g, node, slice_type, false);
+// }
+//}
+//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
+// size_t result = 0;
+// while (inner_block != outer_block) {
+// if (inner_block->node->type == NodeTypeDefer &&
+// (inner_block->node->data.defer.kind == ReturnKindError ||
+// inner_block->node->data.defer.kind == ReturnKindMaybe))
+// {
+// result += 1;
+// }
+// inner_block = inner_block->parent;
+// }
+// return result;
+//}
+
+
+//static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) {
+// BlockContext *defer_inner_block = source_node->block_context;
+// BlockContext *defer_outer_block = irb->node->block_context;
+// if (rk == ReturnKnowledgeUnknown) {
+// if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) {
+// // generate branching code that checks the return value and generates defers
+// // if the return value is error
+// zig_panic("TODO");
+// }
+// } else if (rk != ReturnKnowledgeSkipDefers) {
+// ir_gen_defers_for_block(irb, defer_inner_block, defer_outer_block,
+// rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull);
+// }
+//
+// return ir_build_return(irb, source_node, value);
+//}
+/*
+static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+ assert(node->type == NodeTypeGoto);
+ Buf *label_name = node->data.goto_expr.name;
+ BlockContext *context = node->block_context;
+ assert(context);
+ LabelTableEntry *label = find_label(g, context, label_name);
+
+ if (!label) {
+ add_node_error(g, node, buf_sprintf("no label in scope named '%s'", buf_ptr(label_name)));
+ return;
+ }
+
+ label->used = true;
+ node->data.goto_expr.label_entry = label;
+}
+
+ for (size_t i = 0; i < fn_table_entry->goto_list.length; i += 1) {
+ AstNode *goto_node = fn_table_entry->goto_list.at(i);
+ assert(goto_node->type == NodeTypeGoto);
+ analyze_goto_pass2(g, import, goto_node);
+ }
+
+ for (size_t i = 0; i < fn_table_entry->all_labels.length; i += 1) {
+ LabelTableEntry *label = fn_table_entry->all_labels.at(i);
+ if (!label->used) {
+ add_node_error(g, label->decl_node,
+ buf_sprintf("label '%s' defined but not used",
+ buf_ptr(label->decl_node->data.label.name)));
+ }
+ }
+*/
+
+//static LabelTableEntry *find_label(CodeGen *g, BlockContext *orig_context, Buf *name) {
+// BlockContext *context = orig_context;
+// while (context && context->fn_entry) {
+// auto entry = context->label_table.maybe_get(name);
+// if (entry) {
+// return entry->value;
+// }
+// context = context->parent;
+// }
+// return nullptr;
+//}
+