aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp1992
1 files changed, 1991 insertions, 1 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index d76513e9c4..932fa837da 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1693,7 +1693,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
case NodeTypeSwitchRange:
case NodeTypeErrorValueDecl:
case NodeTypeTypeDecl:
- zig_panic("TODO more IR gen");
+ zig_panic("TODO more IR gen for node types");
}
zig_unreachable();
}
@@ -3966,6 +3966,8 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
return value;
}
+// TODO port over all this commented out code into new IR way of doing things
+
//static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
// AstNode *node, const char *err_format, bool is_max)
//{
@@ -7401,3 +7403,1991 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
// return nullptr;
//}
+//
+//static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeFnCallExpr);
+// assert(g->generate_error_name_table);
+//
+// if (g->error_decls.length == 1) {
+// LLVMBuildUnreachable(g->builder);
+// return nullptr;
+// }
+//
+//
+// AstNode *err_val_node = node->data.fn_call_expr.params.at(0);
+// LLVMValueRef err_val = gen_expr(g, err_val_node);
+//
+// if (want_debug_safety(g, node)) {
+// LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val));
+// LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->error_decls.length, false);
+// add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val);
+// }
+//
+// LLVMValueRef indices[] = {
+// LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+// err_val,
+// };
+// return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, "");
+//}
+//
+//static LLVMValueRef gen_cmp_exchange(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// AstNode *ptr_arg = node->data.fn_call_expr.params.at(0);
+// AstNode *cmp_arg = node->data.fn_call_expr.params.at(1);
+// AstNode *new_arg = node->data.fn_call_expr.params.at(2);
+// AstNode *success_order_arg = node->data.fn_call_expr.params.at(3);
+// AstNode *failure_order_arg = node->data.fn_call_expr.params.at(4);
+//
+// LLVMValueRef ptr_val = gen_expr(g, ptr_arg);
+// LLVMValueRef cmp_val = gen_expr(g, cmp_arg);
+// LLVMValueRef new_val = gen_expr(g, new_arg);
+//
+// ConstExprValue *success_order_val = &get_resolved_expr(success_order_arg)->const_val;
+// ConstExprValue *failure_order_val = &get_resolved_expr(failure_order_arg)->const_val;
+//
+// assert(success_order_val->ok);
+// assert(failure_order_val->ok);
+//
+// LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering((AtomicOrder)success_order_val->data.x_enum.tag);
+// LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering((AtomicOrder)failure_order_val->data.x_enum.tag);
+//
+// LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
+// success_order, failure_order);
+//
+// return LLVMBuildExtractValue(g->builder, result_val, 1, "");
+//}
+//
+//static LLVMValueRef gen_div_exact(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// AstNode *op1_node = node->data.fn_call_expr.params.at(0);
+// AstNode *op2_node = node->data.fn_call_expr.params.at(1);
+//
+// LLVMValueRef op1_val = gen_expr(g, op1_node);
+// LLVMValueRef op2_val = gen_expr(g, op2_node);
+//
+// return gen_div(g, node, op1_val, op2_val, get_expr_type(op1_node), true);
+//}
+//
+//static LLVMValueRef gen_truncate(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// TypeTableEntry *dest_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));
+// AstNode *src_node = node->data.fn_call_expr.params.at(1);
+//
+// LLVMValueRef src_val = gen_expr(g, src_node);
+//
+// return LLVMBuildTrunc(g->builder, src_val, dest_type->type_ref, "");
+//}
+//
+//static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// size_t fn_call_param_count = node->data.fn_call_expr.params.length;
+// assert(fn_call_param_count == 4);
+//
+// TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));
+// assert(int_type->id == TypeTableEntryIdInt);
+//
+// LLVMValueRef val1 = gen_expr(g, node->data.fn_call_expr.params.at(1));
+// LLVMValueRef val2 = gen_expr(g, node->data.fn_call_expr.params.at(2));
+// LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(3));
+//
+// LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
+// LLVMValueRef orig_val;
+// if (int_type->data.integral.is_signed) {
+// orig_val = LLVMBuildAShr(g->builder, result, val2, "");
+// } else {
+// orig_val = LLVMBuildLShr(g->builder, result, val2, "");
+// }
+// LLVMValueRef overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, val1, orig_val, "");
+//
+// LLVMBuildStore(g->builder, result, ptr_result);
+//
+// return overflow_bit;
+//}
+//
+//static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeFnCallExpr);
+// AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
+// assert(fn_ref_expr->type == NodeTypeSymbol);
+// BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn;
+//
+// switch (builtin_fn->id) {
+// case BuiltinFnIdInvalid:
+// case BuiltinFnIdTypeof:
+// case BuiltinFnIdCInclude:
+// case BuiltinFnIdCDefine:
+// case BuiltinFnIdCUndef:
+// case BuiltinFnIdImport:
+// case BuiltinFnIdCImport:
+// case BuiltinFnIdCompileErr:
+// case BuiltinFnIdIntType:
+// zig_unreachable();
+// case BuiltinFnIdCtz:
+// case BuiltinFnIdClz:
+// {
+// size_t fn_call_param_count = node->data.fn_call_expr.params.length;
+// assert(fn_call_param_count == 2);
+// TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));
+// assert(int_type->id == TypeTableEntryIdInt);
+// LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, builtin_fn->id);
+// LLVMValueRef operand = gen_expr(g, node->data.fn_call_expr.params.at(1));
+// LLVMValueRef params[] {
+// operand,
+// LLVMConstNull(LLVMInt1Type()),
+// };
+// return LLVMBuildCall(g->builder, fn_val, params, 2, "");
+// }
+// case BuiltinFnIdAddWithOverflow:
+// case BuiltinFnIdSubWithOverflow:
+// case BuiltinFnIdMulWithOverflow:
+// {
+// size_t fn_call_param_count = node->data.fn_call_expr.params.length;
+// assert(fn_call_param_count == 4);
+//
+// TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));
+// AddSubMul add_sub_mul;
+// if (builtin_fn->id == BuiltinFnIdAddWithOverflow) {
+// add_sub_mul = AddSubMulAdd;
+// } else if (builtin_fn->id == BuiltinFnIdSubWithOverflow) {
+// add_sub_mul = AddSubMulSub;
+// } else if (builtin_fn->id == BuiltinFnIdMulWithOverflow) {
+// add_sub_mul = AddSubMulMul;
+// } else {
+// zig_unreachable();
+// }
+// LLVMValueRef fn_val = get_int_overflow_fn(g, int_type, add_sub_mul);
+//
+// LLVMValueRef op1 = gen_expr(g, node->data.fn_call_expr.params.at(1));
+// LLVMValueRef op2 = gen_expr(g, node->data.fn_call_expr.params.at(2));
+// LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(3));
+//
+// LLVMValueRef params[] = {
+// op1,
+// op2,
+// };
+//
+// LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
+// LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
+// LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
+// LLVMBuildStore(g->builder, result, ptr_result);
+//
+// return overflow_bit;
+// }
+// case BuiltinFnIdShlWithOverflow:
+// return gen_shl_with_overflow(g, node);
+// case BuiltinFnIdMemcpy:
+// {
+// size_t fn_call_param_count = node->data.fn_call_expr.params.length;
+// assert(fn_call_param_count == 3);
+//
+// AstNode *dest_node = node->data.fn_call_expr.params.at(0);
+// TypeTableEntry *dest_type = get_expr_type(dest_node);
+//
+// LLVMValueRef dest_ptr = gen_expr(g, dest_node);
+// LLVMValueRef src_ptr = gen_expr(g, node->data.fn_call_expr.params.at(1));
+// LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2));
+//
+// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
+//
+// LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
+// LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, "");
+//
+// uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type);
+//
+// LLVMValueRef params[] = {
+// dest_ptr_casted, // dest pointer
+// src_ptr_casted, // source pointer
+// len_val, // byte count
+// LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes
+// LLVMConstNull(LLVMInt1Type()), // is volatile
+// };
+//
+// LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, "");
+// return nullptr;
+// }
+// case BuiltinFnIdMemset:
+// {
+// size_t fn_call_param_count = node->data.fn_call_expr.params.length;
+// assert(fn_call_param_count == 3);
+//
+// AstNode *dest_node = node->data.fn_call_expr.params.at(0);
+// TypeTableEntry *dest_type = get_expr_type(dest_node);
+//
+// LLVMValueRef dest_ptr = gen_expr(g, dest_node);
+// LLVMValueRef char_val = gen_expr(g, node->data.fn_call_expr.params.at(1));
+// LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2));
+//
+// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
+//
+// LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
+//
+// uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type);
+//
+// LLVMValueRef params[] = {
+// dest_ptr_casted, // dest pointer
+// char_val, // source pointer
+// len_val, // byte count
+// LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes
+// LLVMConstNull(LLVMInt1Type()), // is volatile
+// };
+//
+// LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, "");
+// return nullptr;
+// }
+// case BuiltinFnIdSizeof:
+// case BuiltinFnIdAlignof:
+// case BuiltinFnIdMinValue:
+// case BuiltinFnIdMaxValue:
+// case BuiltinFnIdMemberCount:
+// case BuiltinFnIdConstEval:
+// case BuiltinFnIdEmbedFile:
+// // caught by constant expression eval codegen
+// zig_unreachable();
+// case BuiltinFnIdCompileVar:
+// return nullptr;
+// case BuiltinFnIdErrName:
+// return gen_err_name(g, node);
+// case BuiltinFnIdBreakpoint:
+// return LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, "");
+// case BuiltinFnIdFrameAddress:
+// case BuiltinFnIdReturnAddress:
+// {
+// LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
+// return LLVMBuildCall(g->builder, builtin_fn->fn_val, &zero, 1, "");
+// }
+// case BuiltinFnIdCmpExchange:
+// return gen_cmp_exchange(g, node);
+// case BuiltinFnIdFence:
+// return gen_fence(g, node);
+// case BuiltinFnIdDivExact:
+// return gen_div_exact(g, node);
+// case BuiltinFnIdTruncate:
+// return gen_truncate(g, node);
+// case BuiltinFnIdUnreachable:
+// zig_panic("moved to ir render");
+// case BuiltinFnIdSetFnTest:
+// case BuiltinFnIdSetFnVisible:
+// case BuiltinFnIdSetFnStaticEval:
+// case BuiltinFnIdSetFnNoInline:
+// case BuiltinFnIdSetDebugSafety:
+// // do nothing
+// return nullptr;
+// }
+// zig_unreachable();
+//}
+//
+//static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntry *enum_type,
+// AstNode *arg_node)
+//{
+// assert(node->type == NodeTypeFieldAccessExpr);
+//
+// uint64_t value = node->data.field_access_expr.type_enum_field->value;
+// LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref;
+// LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, value, false);
+//
+// if (enum_type->data.enumeration.gen_field_count == 0) {
+// return tag_value;
+// } else {
+// TypeTableEntry *arg_node_type = nullptr;
+// LLVMValueRef new_union_val = gen_expr(g, arg_node);
+// if (arg_node) {
+// arg_node_type = get_expr_type(arg_node);
+// } else {
+// arg_node_type = g->builtin_types.entry_void;
+// }
+//
+// LLVMValueRef tmp_struct_ptr = node->data.field_access_expr.resolved_struct_val_expr.ptr;
+//
+// // populate the new tag value
+// LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, "");
+// LLVMBuildStore(g->builder, tag_value, tag_field_ptr);
+//
+// if (arg_node_type->id != TypeTableEntryIdVoid) {
+// // populate the union value
+// TypeTableEntry *union_val_type = get_expr_type(arg_node);
+// LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
+// LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
+// LLVMPointerType(union_val_type->type_ref, 0), "");
+//
+// gen_assign_raw(g, arg_node, BinOpTypeAssign, bitcasted_union_field_ptr, new_union_val,
+// union_val_type, union_val_type);
+//
+// }
+//
+// return tmp_struct_ptr;
+// }
+//}
+//
+//static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// if (node->data.fn_call_expr.is_builtin) {
+// return gen_builtin_fn_call_expr(g, node);
+// }
+//
+// FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
+// TypeTableEntry *struct_type = nullptr;
+// AstNode *first_param_expr = nullptr;
+//
+// AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
+// if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
+// fn_ref_expr->data.field_access_expr.is_member_fn)
+// {
+// first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr;
+// struct_type = get_expr_type(first_param_expr);
+// }
+//
+// TypeTableEntry *fn_type;
+// LLVMValueRef fn_val;
+// AstNode *generic_proto_node;
+// if (fn_table_entry) {
+// fn_val = fn_table_entry->fn_value;
+// fn_type = fn_table_entry->type_entry;
+// generic_proto_node = fn_table_entry->proto_node->data.fn_proto.generic_proto_node;
+// } else {
+// fn_val = gen_expr(g, fn_ref_expr);
+// fn_type = get_expr_type(fn_ref_expr);
+// generic_proto_node = nullptr;
+// }
+//
+// 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 = node->data.fn_call_expr.params.length;
+// bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
+// size_t actual_param_count = fn_call_param_count + (struct_type ? 1 : 0) + (first_arg_ret ? 1 : 0);
+// bool is_var_args = fn_type->data.fn.fn_type_id.is_var_args;
+//
+// // don't really include void values
+// LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
+//
+// size_t gen_param_index = 0;
+// if (first_arg_ret) {
+// gen_param_values[gen_param_index] = node->data.fn_call_expr.tmp_ptr;
+// gen_param_index += 1;
+// }
+// if (struct_type && type_has_bits(struct_type)) {
+// gen_param_values[gen_param_index] = gen_expr(g, first_param_expr);
+// assert(gen_param_values[gen_param_index]);
+// gen_param_index += 1;
+// }
+//
+// for (size_t call_i = 0; call_i < fn_call_param_count; call_i += 1) {
+// size_t proto_i = call_i + (struct_type ? 1 : 0);
+// if (generic_proto_node &&
+// generic_proto_node->data.fn_proto.params.at(proto_i)->data.param_decl.is_inline)
+// {
+// continue;
+// }
+// AstNode *expr_node = node->data.fn_call_expr.params.at(call_i);
+// LLVMValueRef param_value = gen_expr(g, expr_node);
+// assert(param_value);
+// TypeTableEntry *param_type = get_expr_type(expr_node);
+// if (is_var_args || type_has_bits(param_type)) {
+// gen_param_values[gen_param_index] = param_value;
+// gen_param_index += 1;
+// }
+// }
+//
+// LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
+// gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");
+//
+// if (src_return_type->id == TypeTableEntryIdUnreachable) {
+// return LLVMBuildUnreachable(g->builder);
+// } else if (!ret_has_bits) {
+// return nullptr;
+// } else if (first_arg_ret) {
+// return node->data.fn_call_expr.tmp_ptr;
+// } else {
+// return result;
+// }
+//}
+//
+//static LLVMValueRef gen_array_base_ptr(CodeGen *g, AstNode *node) {
+// TypeTableEntry *type_entry = get_expr_type(node);
+//
+// LLVMValueRef array_ptr;
+// if (node->type == NodeTypeFieldAccessExpr) {
+// array_ptr = gen_field_access_expr(g, node, true);
+// if (type_entry->id == TypeTableEntryIdPointer) {
+// // we have a double pointer so we must dereference it once
+// array_ptr = LLVMBuildLoad(g->builder, array_ptr, "");
+// }
+// } else {
+// array_ptr = gen_expr(g, node);
+// }
+//
+// assert(!array_ptr || LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
+//
+// return array_ptr;
+//}
+//
+//static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeArrayAccessExpr);
+//
+// AstNode *array_expr_node = node->data.array_access_expr.array_ref_expr;
+// TypeTableEntry *array_type = get_expr_type(array_expr_node);
+//
+// LLVMValueRef array_ptr = gen_array_base_ptr(g, array_expr_node);
+//
+// LLVMValueRef subscript_value = gen_expr(g, node->data.array_access_expr.subscript);
+// return gen_array_elem_ptr(g, node, array_ptr, array_type, subscript_value);
+//}
+//
+//static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {
+// assert(node->type == NodeTypeFieldAccessExpr);
+//
+// AstNode *struct_expr_node = node->data.field_access_expr.struct_expr;
+//
+// *out_type_entry = node->data.field_access_expr.type_struct_field->type_entry;
+// if (!type_has_bits(*out_type_entry)) {
+// return nullptr;
+// }
+//
+// LLVMValueRef struct_ptr;
+// if (struct_expr_node->type == NodeTypeSymbol) {
+// VariableTableEntry *var = get_resolved_expr(struct_expr_node)->variable;
+// assert(var);
+//
+// if (var->type->id == TypeTableEntryIdPointer) {
+// struct_ptr = LLVMBuildLoad(g->builder, var->value_ref, "");
+// } else {
+// struct_ptr = var->value_ref;
+// }
+// } else if (struct_expr_node->type == NodeTypeFieldAccessExpr) {
+// struct_ptr = gen_field_access_expr(g, struct_expr_node, true);
+// TypeTableEntry *field_type = get_expr_type(struct_expr_node);
+// if (field_type->id == TypeTableEntryIdPointer) {
+// // we have a double pointer so we must dereference it once
+// struct_ptr = LLVMBuildLoad(g->builder, struct_ptr, "");
+// }
+// } else {
+// struct_ptr = gen_expr(g, struct_expr_node);
+// }
+//
+// assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind);
+// assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind);
+//
+// size_t gen_field_index = node->data.field_access_expr.type_struct_field->gen_index;
+// assert(gen_field_index != SIZE_MAX);
+//
+// return LLVMBuildStructGEP(g->builder, struct_ptr, gen_field_index, "");
+//}
+//
+//static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeSliceExpr);
+//
+// AstNode *array_ref_node = node->data.slice_expr.array_ref_expr;
+// TypeTableEntry *array_type = get_expr_type(array_ref_node);
+//
+// LLVMValueRef tmp_struct_ptr = node->data.slice_expr.resolved_struct_val_expr.ptr;
+// LLVMValueRef array_ptr = gen_array_base_ptr(g, array_ref_node);
+//
+// if (array_type->id == TypeTableEntryIdArray) {
+// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start);
+// LLVMValueRef end_val;
+// if (node->data.slice_expr.end) {
+// end_val = gen_expr(g, node->data.slice_expr.end);
+// } else {
+// end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
+// }
+//
+// if (want_debug_safety(g, node)) {
+// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
+// if (node->data.slice_expr.end) {
+// LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
+// array_type->data.array.len, false);
+// add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end);
+// }
+// }
+//
+// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, "");
+// LLVMValueRef indices[] = {
+// LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+// start_val,
+// };
+// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
+// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
+//
+// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
+// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
+// LLVMBuildStore(g->builder, len_value, len_field_ptr);
+//
+// return tmp_struct_ptr;
+// } else if (array_type->id == TypeTableEntryIdPointer) {
+// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start);
+// LLVMValueRef end_val = gen_expr(g, node->data.slice_expr.end);
+//
+// if (want_debug_safety(g, node)) {
+// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
+// }
+//
+// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, "");
+// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
+// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
+//
+// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
+// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
+// LLVMBuildStore(g->builder, len_value, len_field_ptr);
+//
+// return tmp_struct_ptr;
+// } else if (array_type->id == TypeTableEntryIdStruct) {
+// assert(array_type->data.structure.is_slice);
+// assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
+// assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
+//
+// size_t ptr_index = array_type->data.structure.fields[0].gen_index;
+// assert(ptr_index != SIZE_MAX);
+// size_t len_index = array_type->data.structure.fields[1].gen_index;
+// assert(len_index != SIZE_MAX);
+//
+// LLVMValueRef prev_end = nullptr;
+// if (!node->data.slice_expr.end || want_debug_safety(g, node)) {
+// LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, "");
+// prev_end = LLVMBuildLoad(g->builder, src_len_ptr, "");
+// }
+//
+// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start);
+// LLVMValueRef end_val;
+// if (node->data.slice_expr.end) {
+// end_val = gen_expr(g, node->data.slice_expr.end);
+// } else {
+// end_val = prev_end;
+// }
+//
+// if (want_debug_safety(g, node)) {
+// assert(prev_end);
+// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
+// if (node->data.slice_expr.end) {
+// add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end);
+// }
+// }
+//
+// LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, "");
+// LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, "");
+// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, ptr_index, "");
+// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, len_index, "");
+// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
+//
+// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, len_index, "");
+// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
+// LLVMBuildStore(g->builder, len_value, len_field_ptr);
+//
+// return tmp_struct_ptr;
+// } else {
+// zig_unreachable();
+// }
+//}
+//
+//
+//static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
+// TypeTableEntry **out_type_entry)
+//{
+// LLVMValueRef target_ref;
+//
+// if (node->type == NodeTypeSymbol) {
+// VariableTableEntry *var = get_resolved_expr(node)->variable;
+// assert(var);
+//
+// *out_type_entry = var->type;
+// target_ref = var->value_ref;
+// } else if (node->type == NodeTypeArrayAccessExpr) {
+// TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr);
+// if (array_type->id == TypeTableEntryIdArray) {
+// *out_type_entry = array_type->data.array.child_type;
+// target_ref = gen_array_ptr(g, node);
+// } else if (array_type->id == TypeTableEntryIdPointer) {
+// *out_type_entry = array_type->data.pointer.child_type;
+// target_ref = gen_array_ptr(g, node);
+// } else if (array_type->id == TypeTableEntryIdStruct) {
+// assert(array_type->data.structure.is_slice);
+// *out_type_entry = array_type->data.structure.fields[0].type_entry->data.pointer.child_type;
+// target_ref = gen_array_ptr(g, node);
+// } else {
+// zig_unreachable();
+// }
+// } else if (node->type == NodeTypeFieldAccessExpr) {
+// AstNode *struct_expr_node = node->data.field_access_expr.struct_expr;
+// TypeTableEntry *struct_type = get_expr_type(struct_expr_node);
+// if (struct_type->id == TypeTableEntryIdNamespace) {
+// target_ref = gen_field_access_expr(g, node, true);
+// *out_type_entry = get_expr_type(node);
+// } else {
+// target_ref = gen_field_ptr(g, node, out_type_entry);
+// }
+// } else if (node->type == NodeTypePrefixOpExpr) {
+// assert(node->data.prefix_op_expr.prefix_op == PrefixOpDereference);
+// AstNode *target_expr = node->data.prefix_op_expr.primary_expr;
+// TypeTableEntry *type_entry = get_expr_type(target_expr);
+// assert(type_entry->id == TypeTableEntryIdPointer);
+// *out_type_entry = type_entry->data.pointer.child_type;
+// return gen_expr(g, target_expr);
+// } else {
+// zig_panic("bad assign target");
+// }
+//
+// return target_ref;
+//}
+//
+//static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeBinOpExpr);
+//
+// LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
+// LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
+//
+// TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1);
+// TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
+// return gen_arithmetic_bin_op(g, node, val1, val2, op1_type, op2_type, node->data.bin_op_expr.bin_op);
+//
+//}
+//
+//static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeBinOpExpr);
+//
+// LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
+// LLVMBasicBlockRef post_val1_block = LLVMGetInsertBlock(g->builder);
+//
+// // block for when val1 == true
+// LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndTrue");
+// // block for when val1 == false (don't even evaluate the second part)
+// LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndFalse");
+//
+// LLVMBuildCondBr(g->builder, val1, true_block, false_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, true_block);
+// LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
+// LLVMBasicBlockRef post_val2_block = LLVMGetInsertBlock(g->builder);
+//
+// LLVMBuildBr(g->builder, false_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, false_block);
+// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
+// LLVMValueRef incoming_values[2] = {val1, val2};
+// LLVMBasicBlockRef incoming_blocks[2] = {post_val1_block, post_val2_block};
+// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
+//
+// return phi;
+//}
+//
+//static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
+// assert(expr_node->type == NodeTypeBinOpExpr);
+//
+// LLVMValueRef val1 = gen_expr(g, expr_node->data.bin_op_expr.op1);
+// LLVMBasicBlockRef post_val1_block = LLVMGetInsertBlock(g->builder);
+//
+// // block for when val1 == false
+// LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrFalse");
+// // block for when val1 == true (don't even evaluate the second part)
+// LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrTrue");
+//
+// LLVMBuildCondBr(g->builder, val1, true_block, false_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, false_block);
+// LLVMValueRef val2 = gen_expr(g, expr_node->data.bin_op_expr.op2);
+//
+// LLVMBasicBlockRef post_val2_block = LLVMGetInsertBlock(g->builder);
+//
+// LLVMBuildBr(g->builder, true_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, true_block);
+// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
+// LLVMValueRef incoming_values[2] = {val1, val2};
+// LLVMBasicBlockRef incoming_blocks[2] = {post_val1_block, post_val2_block};
+// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
+//
+// return phi;
+//}
+//
+//static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeBinOpExpr);
+//
+// AstNode *lhs_node = node->data.bin_op_expr.op1;
+//
+// TypeTableEntry *op1_type;
+//
+// LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type);
+//
+// TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
+//
+// LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
+//
+// gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type);
+// return nullptr;
+//}
+//
+//static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeBinOpExpr);
+// assert(node->data.bin_op_expr.bin_op == BinOpTypeUnwrapMaybe);
+//
+// AstNode *op1_node = node->data.bin_op_expr.op1;
+// AstNode *op2_node = node->data.bin_op_expr.op2;
+//
+// LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node);
+//
+// TypeTableEntry *maybe_type = get_expr_type(op1_node);
+// assert(maybe_type->id == TypeTableEntryIdMaybe);
+// TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
+//
+// LLVMValueRef cond_value;
+// if (child_type->id == TypeTableEntryIdPointer ||
+// child_type->id == TypeTableEntryIdFn)
+// {
+// cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref,
+// LLVMConstNull(child_type->type_ref), "");
+// } else {
+// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, "");
+// cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
+// }
+//
+// LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull");
+// LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull");
+// LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd");
+//
+// bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable;
+//
+// LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, non_null_block);
+// LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref);
+// LLVMBuildBr(g->builder, end_block);
+// LLVMBasicBlockRef post_non_null_result_block = LLVMGetInsertBlock(g->builder);
+//
+// LLVMPositionBuilderAtEnd(g->builder, null_block);
+// LLVMValueRef null_result = gen_expr(g, op2_node);
+// if (null_reachable) {
+// LLVMBuildBr(g->builder, end_block);
+// }
+// LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder);
+//
+// LLVMPositionBuilderAtEnd(g->builder, end_block);
+// if (null_reachable) {
+// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), "");
+// LLVMValueRef incoming_values[2] = {non_null_result, null_result};
+// LLVMBasicBlockRef incoming_blocks[2] = {post_non_null_result_block, post_null_result_block};
+// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
+// return phi;
+// } else {
+// return non_null_result;
+// }
+//
+// return nullptr;
+//}
+//
+//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeUnwrapErrorExpr);
+//
+// AstNode *op1 = node->data.unwrap_err_expr.op1;
+// AstNode *op2 = node->data.unwrap_err_expr.op2;
+// VariableTableEntry *var = node->data.unwrap_err_expr.var;
+//
+// LLVMValueRef expr_val = gen_expr(g, op1);
+// TypeTableEntry *expr_type = get_expr_type(op1);
+// TypeTableEntry *op2_type = get_expr_type(op2);
+// assert(expr_type->id == TypeTableEntryIdErrorUnion);
+// TypeTableEntry *child_type = expr_type->data.error.child_type;
+// LLVMValueRef err_val;
+// if (handle_is_ptr(expr_type)) {
+// LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, "");
+// err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
+// } else {
+// err_val = expr_val;
+// }
+// LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
+// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
+//
+// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrOk");
+// LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError");
+// LLVMBasicBlockRef end_block;
+// bool err_reachable = op2_type->id != TypeTableEntryIdUnreachable;
+// bool have_end_block = err_reachable && type_has_bits(child_type);
+// if (have_end_block) {
+// end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrEnd");
+// }
+//
+// LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, err_block);
+// if (var) {
+// LLVMBuildStore(g->builder, err_val, var->value_ref);
+// }
+// LLVMValueRef err_result = gen_expr(g, op2);
+// if (have_end_block) {
+// LLVMBuildBr(g->builder, end_block);
+// } else if (err_reachable) {
+// LLVMBuildBr(g->builder, ok_block);
+// }
+//
+// LLVMPositionBuilderAtEnd(g->builder, ok_block);
+// if (!type_has_bits(child_type)) {
+// return nullptr;
+// }
+// LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, "");
+// LLVMValueRef child_val = get_handle_value(g, child_val_ptr, child_type);
+//
+// if (!have_end_block) {
+// return child_val;
+// }
+//
+// LLVMBuildBr(g->builder, end_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, end_block);
+// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(err_result), "");
+// LLVMValueRef incoming_values[2] = {child_val, err_result};
+// LLVMBasicBlockRef incoming_blocks[2] = {ok_block, err_block};
+// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
+// return phi;
+//}
+//
+//static void gen_defers_for_block(CodeGen *g, BlockContext *inner_block, BlockContext *outer_block,
+// bool gen_error_defers, bool gen_maybe_defers)
+//{
+// while (inner_block != outer_block) {
+// if (inner_block->node->type == NodeTypeDefer &&
+// ((inner_block->node->data.defer.kind == ReturnKindUnconditional) ||
+// (gen_error_defers && inner_block->node->data.defer.kind == ReturnKindError) ||
+// (gen_maybe_defers && inner_block->node->data.defer.kind == ReturnKindMaybe)))
+// {
+// gen_expr(g, inner_block->node->data.defer.expr);
+// }
+// inner_block = inner_block->parent;
+// }
+//}
+//
+//static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeReturnExpr);
+// AstNode *param_node = node->data.return_expr.expr;
+// assert(param_node);
+// LLVMValueRef value = gen_expr(g, param_node);
+// TypeTableEntry *value_type = get_expr_type(param_node);
+//
+// switch (node->data.return_expr.kind) {
+// case ReturnKindUnconditional:
+// {
+// Expr *expr = get_resolved_expr(param_node);
+// if (expr->const_val.ok) {
+// if (value_type->id == TypeTableEntryIdErrorUnion) {
+// if (expr->const_val.data.x_err.err) {
+// expr->return_knowledge = ReturnKnowledgeKnownError;
+// } else {
+// expr->return_knowledge = ReturnKnowledgeKnownNonError;
+// }
+// } else if (value_type->id == TypeTableEntryIdMaybe) {
+// if (expr->const_val.data.x_maybe) {
+// expr->return_knowledge = ReturnKnowledgeKnownNonNull;
+// } else {
+// expr->return_knowledge = ReturnKnowledgeKnownNull;
+// }
+// }
+// }
+// return gen_return(g, node, value, expr->return_knowledge);
+// }
+// case ReturnKindError:
+// {
+// assert(value_type->id == TypeTableEntryIdErrorUnion);
+// TypeTableEntry *child_type = value_type->data.error.child_type;
+//
+// LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrRetReturn");
+// LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrRetContinue");
+//
+// LLVMValueRef err_val;
+// if (type_has_bits(child_type)) {
+// LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, value, 0, "");
+// err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
+// } else {
+// err_val = value;
+// }
+// LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
+// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
+// LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, return_block);
+// TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
+// if (return_type->id == TypeTableEntryIdPureError) {
+// gen_return(g, node, err_val, ReturnKnowledgeKnownError);
+// } else if (return_type->id == TypeTableEntryIdErrorUnion) {
+// if (type_has_bits(return_type->data.error.child_type)) {
+// assert(g->cur_ret_ptr);
+//
+// LLVMValueRef tag_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 0, "");
+// LLVMBuildStore(g->builder, err_val, tag_ptr);
+// LLVMBuildRetVoid(g->builder);
+// } else {
+// gen_return(g, node, err_val, ReturnKnowledgeKnownError);
+// }
+// } else {
+// zig_unreachable();
+// }
+//
+// LLVMPositionBuilderAtEnd(g->builder, continue_block);
+// if (type_has_bits(child_type)) {
+// LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, "");
+// return get_handle_value(g, val_ptr, child_type);
+// } else {
+// return nullptr;
+// }
+// }
+// case ReturnKindMaybe:
+// {
+// assert(value_type->id == TypeTableEntryIdMaybe);
+// TypeTableEntry *child_type = value_type->data.maybe.child_type;
+//
+// LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetReturn");
+// LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetContinue");
+//
+// LLVMValueRef maybe_val_ptr = LLVMBuildStructGEP(g->builder, value, 1, "");
+// LLVMValueRef is_non_null = LLVMBuildLoad(g->builder, maybe_val_ptr, "");
+//
+// LLVMValueRef zero = LLVMConstNull(LLVMInt1Type());
+// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntNE, is_non_null, zero, "");
+// LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, return_block);
+// TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
+// assert(return_type->id == TypeTableEntryIdMaybe);
+// if (handle_is_ptr(return_type)) {
+// assert(g->cur_ret_ptr);
+//
+// LLVMValueRef maybe_bit_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 1, "");
+// LLVMBuildStore(g->builder, zero, maybe_bit_ptr);
+// LLVMBuildRetVoid(g->builder);
+// } else {
+// LLVMValueRef ret_zero_value = LLVMConstNull(return_type->type_ref);
+// gen_return(g, node, ret_zero_value, ReturnKnowledgeKnownNull);
+// }
+//
+// LLVMPositionBuilderAtEnd(g->builder, continue_block);
+// if (type_has_bits(child_type)) {
+// LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 0, "");
+// return get_handle_value(g, val_ptr, child_type);
+// } else {
+// return nullptr;
+// }
+// }
+// }
+// zig_unreachable();
+//}
+//
+//static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMValueRef cond_value,
+// AstNode *then_node, AstNode *else_node)
+//{
+// assert(then_node);
+// assert(else_node);
+//
+// TypeTableEntry *then_type = get_expr_type(then_node);
+// TypeTableEntry *else_type = get_expr_type(else_node);
+//
+// bool use_then_value = type_has_bits(then_type);
+// bool use_else_value = type_has_bits(else_type);
+//
+// LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
+// LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
+//
+// LLVMBasicBlockRef endif_block = nullptr;
+// bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable;
+// bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable;
+// if (then_endif_reachable || else_endif_reachable) {
+// endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
+// }
+//
+// LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, then_block);
+// LLVMValueRef then_expr_result = gen_expr(g, then_node);
+// if (then_endif_reachable) {
+// clear_debug_source_node(g);
+// LLVMBuildBr(g->builder, endif_block);
+// }
+// LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
+//
+// LLVMPositionBuilderAtEnd(g->builder, else_block);
+// LLVMValueRef else_expr_result = gen_expr(g, else_node);
+// if (else_endif_reachable) {
+// clear_debug_source_node(g);
+// LLVMBuildBr(g->builder, endif_block);
+// }
+// LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder);
+//
+// if (then_endif_reachable || else_endif_reachable) {
+// LLVMPositionBuilderAtEnd(g->builder, endif_block);
+// if (use_then_value && use_else_value) {
+// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
+// LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
+// LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block};
+// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
+// return phi;
+// } else if (use_then_value) {
+// return then_expr_result;
+// } else if (use_else_value) {
+// return else_expr_result;
+// }
+// }
+//
+// return nullptr;
+//}
+//
+//static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeIfBoolExpr);
+// assert(node->data.if_bool_expr.condition);
+// assert(node->data.if_bool_expr.then_block);
+//
+// ConstExprValue *const_val = &get_resolved_expr(node->data.if_bool_expr.condition)->const_val;
+// if (const_val->ok) {
+// if (const_val->data.x_bool) {
+// return gen_expr(g, node->data.if_bool_expr.then_block);
+// } else if (node->data.if_bool_expr.else_node) {
+// return gen_expr(g, node->data.if_bool_expr.else_node);
+// } else {
+// return nullptr;
+// }
+// } else {
+// LLVMValueRef cond_value = gen_expr(g, node->data.if_bool_expr.condition);
+//
+// return gen_if_bool_expr_raw(g, node, cond_value,
+// node->data.if_bool_expr.then_block,
+// node->data.if_bool_expr.else_node);
+// }
+//}
+//
+//static LLVMValueRef gen_if_var_then_block(CodeGen *g, AstNode *node, VariableTableEntry *variable, bool maybe_is_ptr,
+// LLVMValueRef init_val, TypeTableEntry *child_type, AstNode *then_node)
+//{
+// if (node->data.if_var_expr.var_is_ptr) {
+// LLVMValueRef payload_ptr;
+// if (maybe_is_ptr) {
+// zig_panic("TODO");
+// } else {
+// payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, "");
+// }
+// LLVMBuildStore(g->builder, payload_ptr, variable->value_ref);
+// } else {
+// LLVMValueRef payload_val;
+// if (maybe_is_ptr) {
+// payload_val = init_val;
+// } else {
+// LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, "");
+// payload_val = get_handle_value(g, payload_ptr, child_type);
+// }
+// gen_assign_raw(g, node, BinOpTypeAssign, variable->value_ref, payload_val,
+// variable->type, child_type);
+// }
+// gen_var_debug_decl(g, variable);
+//
+// return gen_expr(g, then_node);
+//}
+//
+//static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeIfVarExpr);
+// assert(node->data.if_var_expr.var_decl.expr);
+//
+// AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl;
+// VariableTableEntry *variable = var_decl->variable;
+//
+// // test if value is the maybe state
+// TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
+// TypeTableEntry *child_type = expr_type->data.maybe.child_type;
+//
+// LLVMValueRef init_val = gen_expr(g, var_decl->expr);
+//
+//
+// AstNode *then_node = node->data.if_var_expr.then_block;
+// AstNode *else_node = node->data.if_var_expr.else_node;
+// bool maybe_is_ptr = child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
+//
+// ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val;
+// if (const_val->ok) {
+// if (const_val->data.x_maybe) {
+// return gen_if_var_then_block(g, node, variable, maybe_is_ptr, init_val, child_type, then_node);
+// } else {
+// return gen_expr(g, else_node);
+// }
+// }
+//
+// LLVMValueRef cond_value;
+// if (maybe_is_ptr) {
+// cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), "");
+// } else {
+// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, "");
+// cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
+// }
+//
+// TypeTableEntry *then_type = get_expr_type(then_node);
+// TypeTableEntry *else_type = get_expr_type(else_node);
+//
+// bool use_then_value = type_has_bits(then_type);
+// bool use_else_value = type_has_bits(else_type);
+//
+// LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeThen");
+// LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeElse");
+//
+// LLVMBasicBlockRef endif_block;
+// bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable;
+// bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable;
+// if (then_endif_reachable || else_endif_reachable) {
+// endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEndIf");
+// }
+//
+// LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
+//
+// LLVMPositionBuilderAtEnd(g->builder, then_block);
+// LLVMValueRef then_expr_result = gen_if_var_then_block(g, node, variable, maybe_is_ptr, init_val, child_type, then_node);
+//
+// if (then_endif_reachable) {
+// LLVMBuildBr(g->builder, endif_block);
+// }
+// LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
+//
+//
+// LLVMPositionBuilderAtEnd(g->builder, else_block);
+// LLVMValueRef else_expr_result = gen_expr(g, else_node);
+// if (else_endif_reachable) {
+// LLVMBuildBr(g->builder, endif_block);
+// }
+// LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder);
+//
+// if (then_endif_reachable || else_endif_reachable) {
+// LLVMPositionBuilderAtEnd(g->builder, endif_block);
+// if (use_then_value && use_else_value) {
+// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
+// LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
+// LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block};
+// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
+// return phi;
+// } else if (use_then_value) {
+// return then_expr_result;
+// } else if (use_else_value) {
+// return else_expr_result;
+// }
+// }
+//
+// return nullptr;
+//}
+//
+//static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
+// assert(block_node->type == NodeTypeBlock);
+//
+// LLVMValueRef return_value = nullptr;
+// for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
+// AstNode *statement_node = block_node->data.block.statements.at(i);
+// return_value = gen_expr(g, statement_node);
+// }
+//
+// bool end_unreachable = implicit_return_type && implicit_return_type->id == TypeTableEntryIdUnreachable;
+// if (end_unreachable) {
+// return nullptr;
+// }
+//
+// gen_defers_for_block(g, block_node->data.block.nested_block, block_node->data.block.child_block,
+// false, false);
+//
+// if (implicit_return_type) {
+// return gen_return(g, block_node, return_value, ReturnKnowledgeSkipDefers);
+// } else {
+// return return_value;
+// }
+//}
+//
+//static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeAsmExpr);
+//
+// AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
+//
+// Buf *src_template = asm_expr->asm_template;
+//
+// Buf llvm_template = BUF_INIT;
+// buf_resize(&llvm_template, 0);
+//
+// for (size_t token_i = 0; token_i < asm_expr->token_list.length; token_i += 1) {
+// AsmToken *asm_token = &asm_expr->token_list.at(token_i);
+// switch (asm_token->id) {
+// case AsmTokenIdTemplate:
+// for (size_t offset = asm_token->start; offset < asm_token->end; offset += 1) {
+// uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset));
+// if (c == '$') {
+// buf_append_str(&llvm_template, "$$");
+// } else {
+// buf_append_char(&llvm_template, c);
+// }
+// }
+// break;
+// case AsmTokenIdPercent:
+// buf_append_char(&llvm_template, '%');
+// break;
+// case AsmTokenIdVar:
+// size_t index = find_asm_index(g, node, asm_token);
+// assert(index < SIZE_MAX);
+// buf_appendf(&llvm_template, "$%zu", index);
+// break;
+// }
+// }
+//
+// Buf constraint_buf = BUF_INIT;
+// buf_resize(&constraint_buf, 0);
+//
+// assert(asm_expr->return_count == 0 || asm_expr->return_count == 1);
+//
+// size_t total_constraint_count = asm_expr->output_list.length +
+// asm_expr->input_list.length +
+// asm_expr->clobber_list.length;
+// size_t input_and_output_count = asm_expr->output_list.length +
+// asm_expr->input_list.length -
+// asm_expr->return_count;
+// size_t total_index = 0;
+// size_t param_index = 0;
+// LLVMTypeRef *param_types = allocate<LLVMTypeRef>(input_and_output_count);
+// LLVMValueRef *param_values = allocate<LLVMValueRef>(input_and_output_count);
+// for (size_t i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) {
+// AsmOutput *asm_output = asm_expr->output_list.at(i);
+// bool is_return = (asm_output->return_type != nullptr);
+// assert(*buf_ptr(asm_output->constraint) == '=');
+// if (is_return) {
+// buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1);
+// } else {
+// buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1);
+// }
+// if (total_index + 1 < total_constraint_count) {
+// buf_append_char(&constraint_buf, ',');
+// }
+//
+// if (!is_return) {
+// VariableTableEntry *variable = asm_output->variable;
+// assert(variable);
+// param_types[param_index] = LLVMTypeOf(variable->value_ref);
+// param_values[param_index] = variable->value_ref;
+// param_index += 1;
+// }
+// }
+// for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) {
+// AsmInput *asm_input = asm_expr->input_list.at(i);
+// buf_append_buf(&constraint_buf, asm_input->constraint);
+// if (total_index + 1 < total_constraint_count) {
+// buf_append_char(&constraint_buf, ',');
+// }
+//
+// TypeTableEntry *expr_type = get_expr_type(asm_input->expr);
+// param_types[param_index] = expr_type->type_ref;
+// param_values[param_index] = gen_expr(g, asm_input->expr);
+// }
+// for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
+// Buf *clobber_buf = asm_expr->clobber_list.at(i);
+// buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf));
+// if (total_index + 1 < total_constraint_count) {
+// buf_append_char(&constraint_buf, ',');
+// }
+// }
+//
+// LLVMTypeRef ret_type;
+// if (asm_expr->return_count == 0) {
+// ret_type = LLVMVoidType();
+// } else {
+// ret_type = get_expr_type(node)->type_ref;
+// }
+// LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false);
+//
+// bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0);
+// LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),
+// buf_ptr(&constraint_buf), is_volatile, false);
+//
+// set_debug_source_node(g, node);
+// return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
+//}
+//
+//static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeContainerInitExpr);
+//
+// TypeTableEntry *type_entry = get_expr_type(node);
+//
+//
+// if (node->data.container_init_expr.enum_type) {
+// size_t param_count = node->data.container_init_expr.entries.length;
+// AstNode *arg1_node;
+// if (param_count == 1) {
+// arg1_node = node->data.container_init_expr.entries.at(0);
+// } else {
+// assert(param_count == 0);
+// arg1_node = nullptr;
+// }
+// return gen_enum_value_expr(g, node->data.container_init_expr.type,
+// node->data.container_init_expr.enum_type, arg1_node);
+// }
+//
+//
+// if (type_entry->id == TypeTableEntryIdStruct) {
+// assert(node->data.container_init_expr.kind == ContainerInitKindStruct);
+//
+// size_t src_field_count = type_entry->data.structure.src_field_count;
+// assert(src_field_count == node->data.container_init_expr.entries.length);
+//
+// StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr;
+// LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
+//
+// for (size_t i = 0; i < src_field_count; i += 1) {
+// AstNode *field_node = node->data.container_init_expr.entries.at(i);
+// assert(field_node->type == NodeTypeStructValueField);
+// TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;
+// if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
+// continue;
+// }
+// assert(buf_eql_buf(type_struct_field->name, field_node->data.struct_val_field.name));
+//
+// set_debug_source_node(g, field_node);
+// LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, "");
+// AstNode *expr_node = field_node->data.struct_val_field.expr;
+// LLVMValueRef value = gen_expr(g, expr_node);
+// gen_assign_raw(g, field_node, BinOpTypeAssign, field_ptr, value,
+// type_struct_field->type_entry, get_expr_type(expr_node));
+// }
+//
+// return tmp_struct_ptr;
+// } else if (type_entry->id == TypeTableEntryIdVoid) {
+// assert(node->data.container_init_expr.entries.length == 0);
+// return nullptr;
+// } else if (type_entry->id == TypeTableEntryIdArray) {
+// StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr;
+// LLVMValueRef tmp_array_ptr = struct_val_expr_node->ptr;
+//
+// size_t field_count = type_entry->data.array.len;
+// assert(field_count == node->data.container_init_expr.entries.length);
+//
+// TypeTableEntry *child_type = type_entry->data.array.child_type;
+//
+// for (size_t i = 0; i < field_count; i += 1) {
+// AstNode *field_node = node->data.container_init_expr.entries.at(i);
+// LLVMValueRef elem_val = gen_expr(g, field_node);
+//
+// LLVMValueRef indices[] = {
+// LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+// LLVMConstInt(g->builtin_types.entry_usize->type_ref, i, false),
+// };
+// set_debug_source_node(g, field_node);
+// LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, "");
+// gen_assign_raw(g, field_node, BinOpTypeAssign, elem_ptr, elem_val,
+// child_type, get_expr_type(field_node));
+// }
+//
+// return tmp_array_ptr;
+// } else {
+// zig_unreachable();
+// }
+//}
+//
+//static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeWhileExpr);
+// assert(node->data.while_expr.condition);
+// assert(node->data.while_expr.body);
+//
+// //AstNode *continue_expr_node = node->data.while_expr.continue_expr;
+//
+// bool condition_always_true = node->data.while_expr.condition_always_true;
+// //bool contains_break = node->data.while_expr.contains_break;
+// if (condition_always_true) {
+// // generate a forever loop
+// zig_panic("TODO IR");
+//
+// //LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");
+// //LLVMBasicBlockRef continue_block = continue_expr_node ?
+// // LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileContinue") : body_block;
+// //LLVMBasicBlockRef end_block = nullptr;
+// //if (contains_break) {
+// // end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");
+// //}
+//
+// //set_debug_source_node(g, node);
+// //LLVMBuildBr(g->builder, body_block);
+//
+// //if (continue_expr_node) {
+// // LLVMPositionBuilderAtEnd(g->builder, continue_block);
+//
+// // gen_expr(g, continue_expr_node);
+//
+// // set_debug_source_node(g, node);
+// // LLVMBuildBr(g->builder, body_block);
+// //}
+//
+// //LLVMPositionBuilderAtEnd(g->builder, body_block);
+// //g->break_block_stack.append(end_block);
+// //g->continue_block_stack.append(continue_block);
+// //gen_expr(g, node->data.while_expr.body);
+// //g->break_block_stack.pop();
+// //g->continue_block_stack.pop();
+//
+// //if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
+// // set_debug_source_node(g, node);
+// // LLVMBuildBr(g->builder, continue_block);
+// //}
+//
+// //if (contains_break) {
+// // LLVMPositionBuilderAtEnd(g->builder, end_block);
+// //}
+// } else {
+// zig_panic("moved to ir.cpp");
+// }
+//
+// return nullptr;
+//}
+
+//static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeBreak);
+// LLVMBasicBlockRef dest_block = g->break_block_stack.last();
+//
+// set_debug_source_node(g, node);
+// return LLVMBuildBr(g->builder, dest_block);
+//}
+
+//static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeContinue);
+// LLVMBasicBlockRef dest_block = g->continue_block_stack.last();
+//
+// set_debug_source_node(g, node);
+// return LLVMBuildBr(g->builder, dest_block);
+//}
+//
+//static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
+// bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr)
+//{
+// VariableTableEntry *variable = var_decl->variable;
+//
+// assert(variable);
+//
+// if (var_decl->expr) {
+// *init_value = gen_expr(g, var_decl->expr);
+// *expr_type = get_expr_type(var_decl->expr);
+// }
+// if (!type_has_bits(variable->type)) {
+// return nullptr;
+// }
+//
+// bool have_init_expr = false;
+// bool want_zeroes = false;
+// if (var_decl->expr) {
+// ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val;
+// if (!const_val->ok || const_val->special == ConstValSpecialOther) {
+// have_init_expr = true;
+// }
+// if (const_val->ok && const_val->special == ConstValSpecialZeroes) {
+// want_zeroes = true;
+// }
+// }
+// if (have_init_expr) {
+// TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
+// LLVMValueRef value;
+// if (unwrap_maybe) {
+// assert(var_decl->expr);
+// assert(expr_type->id == TypeTableEntryIdMaybe);
+// value = gen_unwrap_maybe(g, var_decl->expr, *init_value);
+// expr_type = expr_type->data.maybe.child_type;
+// } else {
+// value = *init_value;
+// }
+// gen_assign_raw(g, var_decl->expr, BinOpTypeAssign, variable->value_ref,
+// value, variable->type, expr_type);
+// } else {
+// bool ignore_uninit = false;
+// // handle runtime stack allocation
+// if (var_decl->type) {
+// TypeTableEntry *var_type = get_type_for_type_node(var_decl->type);
+// if (var_type->id == TypeTableEntryIdStruct &&
+// var_type->data.structure.is_slice)
+// {
+// assert(var_decl->type->type == NodeTypeArrayType);
+// AstNode *size_node = var_decl->type->data.array_type.size;
+// if (size_node) {
+// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
+// if (!const_val->ok) {
+// TypeTableEntry *ptr_type = var_type->data.structure.fields[0].type_entry;
+// assert(ptr_type->id == TypeTableEntryIdPointer);
+// TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
+//
+// LLVMValueRef size_val = gen_expr(g, size_node);
+//
+// set_debug_source_node(g, source_node);
+// LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref,
+// size_val, "");
+//
+// size_t ptr_index = var_type->data.structure.fields[0].gen_index;
+// assert(ptr_index != SIZE_MAX);
+// size_t len_index = var_type->data.structure.fields[1].gen_index;
+// assert(len_index != SIZE_MAX);
+//
+// // store the freshly allocated pointer in the unknown size array struct
+// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder,
+// variable->value_ref, ptr_index, "");
+// LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
+//
+// // store the size in the len field
+// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder,
+// variable->value_ref, len_index, "");
+// LLVMBuildStore(g->builder, size_val, len_field_ptr);
+//
+// // don't clobber what we just did with debug initialization
+// ignore_uninit = true;
+// }
+// }
+// }
+// }
+// bool want_safe = want_debug_safety(g, source_node);
+// if (!ignore_uninit && (want_safe || want_zeroes)) {
+// TypeTableEntry *usize = g->builtin_types.entry_usize;
+// uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, variable->type->type_ref);
+// uint64_t align_bytes = get_memcpy_align(g, variable->type);
+//
+// // memset uninitialized memory to 0xa
+// set_debug_source_node(g, source_node);
+// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
+// LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), want_zeroes ? 0x00 : 0xaa, false);
+// LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
+// LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
+// LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), align_bytes, false);
+// LLVMValueRef params[] = {
+// dest_ptr,
+// fill_char,
+// byte_count,
+// align_in_bytes,
+// LLVMConstNull(LLVMInt1Type()), // is volatile
+// };
+//
+// LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, "");
+// }
+// }
+//
+// gen_var_debug_decl(g, variable);
+// return nullptr;
+//}
+//
+//static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeSwitchExpr);
+//
+// if (node->data.switch_expr.const_chosen_prong_index != SIZE_MAX) {
+// AstNode *prong_node = node->data.switch_expr.prongs.at(node->data.switch_expr.const_chosen_prong_index);
+// assert(prong_node->type == NodeTypeSwitchProng);
+// AstNode *prong_expr = prong_node->data.switch_prong.expr;
+// return gen_expr(g, prong_expr);
+// }
+//
+// TypeTableEntry *target_type = get_expr_type(node->data.switch_expr.expr);
+// LLVMValueRef target_value_handle = gen_expr(g, node->data.switch_expr.expr);
+// LLVMValueRef target_value;
+// if (handle_is_ptr(target_type)) {
+// if (target_type->id == TypeTableEntryIdEnum) {
+// set_debug_source_node(g, node);
+// LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, 0, "");
+// target_value = LLVMBuildLoad(g->builder, tag_field_ptr, "");
+// } else if (target_type->id == TypeTableEntryIdErrorUnion) {
+// set_debug_source_node(g, node);
+// LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, 0, "");
+// target_value = LLVMBuildLoad(g->builder, tag_field_ptr, "");
+// } else {
+// zig_unreachable();
+// }
+// } else {
+// target_value = target_value_handle;
+// }
+//
+//
+// TypeTableEntry *switch_type = get_expr_type(node);
+// bool result_has_bits = type_has_bits(switch_type);
+// bool end_unreachable = (switch_type->id == TypeTableEntryIdUnreachable);
+//
+// LLVMBasicBlockRef end_block = end_unreachable ?
+// nullptr : LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchEnd");
+// LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchElse");
+// size_t prong_count = node->data.switch_expr.prongs.length;
+//
+// set_debug_source_node(g, node);
+// LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_value, else_block, prong_count);
+//
+// ZigList<LLVMValueRef> incoming_values = {0};
+// ZigList<LLVMBasicBlockRef> incoming_blocks = {0};
+//
+// AstNode *else_prong = nullptr;
+// for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
+// AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
+// VariableTableEntry *prong_var = prong_node->data.switch_prong.var;
+//
+// LLVMBasicBlockRef prong_block;
+// if (prong_node->data.switch_prong.items.length == 0) {
+// assert(!else_prong);
+// else_prong = prong_node;
+// prong_block = else_block;
+// } else {
+// prong_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProng");
+// size_t prong_item_count = prong_node->data.switch_prong.items.length;
+// bool make_item_blocks = prong_var && prong_item_count > 1;
+//
+// for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) {
+// AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
+//
+// assert(item_node->type != NodeTypeSwitchRange);
+// LLVMValueRef val;
+// if (target_type->id == TypeTableEntryIdEnum ||
+// target_type->id == TypeTableEntryIdErrorUnion)
+// {
+// assert(item_node->type == NodeTypeSymbol);
+// TypeEnumField *enum_field = nullptr;
+// uint32_t err_value = 0;
+// if (target_type->id == TypeTableEntryIdEnum) {
+// enum_field = item_node->data.symbol_expr.enum_field;
+// assert(enum_field);
+// val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref,
+// enum_field->value, false);
+// } else if (target_type->id == TypeTableEntryIdErrorUnion) {
+// err_value = item_node->data.symbol_expr.err_value;
+// val = LLVMConstInt(g->err_tag_type->type_ref, err_value, false);
+// } else {
+// zig_unreachable();
+// }
+//
+// if (prong_var && type_has_bits(prong_var->type)) {
+// LLVMBasicBlockRef item_block;
+//
+// if (make_item_blocks) {
+// item_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProngItem");
+// LLVMAddCase(switch_instr, val, item_block);
+// LLVMPositionBuilderAtEnd(g->builder, item_block);
+// } else {
+// LLVMAddCase(switch_instr, val, prong_block);
+// LLVMPositionBuilderAtEnd(g->builder, prong_block);
+// }
+//
+// AstNode *var_node = prong_node->data.switch_prong.var_symbol;
+// set_debug_source_node(g, var_node);
+// if (prong_node->data.switch_prong.var_is_target_expr) {
+// gen_assign_raw(g, var_node, BinOpTypeAssign,
+// prong_var->value_ref, target_value, prong_var->type, target_type);
+// } else if (target_type->id == TypeTableEntryIdEnum) {
+// assert(enum_field);
+// assert(type_has_bits(enum_field->type_entry));
+// LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle,
+// 1, "");
+// LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
+// LLVMPointerType(enum_field->type_entry->type_ref, 0), "");
+// LLVMValueRef handle_val = get_handle_value(g, bitcasted_union_field_ptr,
+// enum_field->type_entry);
+//
+// gen_assign_raw(g, var_node, BinOpTypeAssign,
+// prong_var->value_ref, handle_val, prong_var->type, enum_field->type_entry);
+// } else if (target_type->id == TypeTableEntryIdErrorUnion) {
+// if (err_value == 0) {
+// // variable is the payload
+// LLVMValueRef err_payload_ptr = LLVMBuildStructGEP(g->builder,
+// target_value_handle, 1, "");
+// LLVMValueRef handle_val = get_handle_value(g, err_payload_ptr, prong_var->type);
+// gen_assign_raw(g, var_node, BinOpTypeAssign,
+// prong_var->value_ref, handle_val, prong_var->type, prong_var->type);
+// } else {
+// // variable is the pure error value
+// LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder,
+// target_value_handle, 0, "");
+// LLVMValueRef handle_val = LLVMBuildLoad(g->builder, err_tag_ptr, "");
+// gen_assign_raw(g, var_node, BinOpTypeAssign,
+// prong_var->value_ref, handle_val, prong_var->type, g->err_tag_type);
+// }
+// } else {
+// zig_unreachable();
+// }
+// if (make_item_blocks) {
+// set_debug_source_node(g, var_node);
+// LLVMBuildBr(g->builder, prong_block);
+// }
+// } else {
+// LLVMAddCase(switch_instr, val, prong_block);
+// }
+// } else {
+// assert(get_resolved_expr(item_node)->const_val.ok);
+// val = gen_expr(g, item_node);
+// LLVMAddCase(switch_instr, val, prong_block);
+// }
+// }
+// }
+//
+// LLVMPositionBuilderAtEnd(g->builder, prong_block);
+// AstNode *prong_expr = prong_node->data.switch_prong.expr;
+// LLVMValueRef prong_val = gen_expr(g, prong_expr);
+//
+// if (get_expr_type(prong_expr)->id != TypeTableEntryIdUnreachable) {
+// set_debug_source_node(g, prong_expr);
+// LLVMBuildBr(g->builder, end_block);
+// incoming_values.append(prong_val);
+// incoming_blocks.append(LLVMGetInsertBlock(g->builder));
+// }
+// }
+//
+// if (!else_prong) {
+// LLVMPositionBuilderAtEnd(g->builder, else_block);
+// set_debug_source_node(g, node);
+// if (want_debug_safety(g, node)) {
+// gen_debug_safety_crash(g);
+// } else {
+// LLVMBuildUnreachable(g->builder);
+// }
+// }
+//
+// if (end_unreachable) {
+// return nullptr;
+// }
+//
+// LLVMPositionBuilderAtEnd(g->builder, end_block);
+//
+// if (result_has_bits) {
+// set_debug_source_node(g, node);
+// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(incoming_values.at(0)), "");
+// LLVMAddIncoming(phi, incoming_values.items, incoming_blocks.items, incoming_values.length);
+// return phi;
+// } else {
+// return nullptr;
+// }
+//}
+//
+//static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
+// assert(node->type == NodeTypeArrayAccessExpr);
+//
+// LLVMValueRef ptr = gen_array_ptr(g, node);
+// TypeTableEntry *child_type;
+// TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr);
+// if (array_type->id == TypeTableEntryIdPointer) {
+// child_type = array_type->data.pointer.child_type;
+// } else if (array_type->id == TypeTableEntryIdStruct) {
+// assert(array_type->data.structure.is_slice);
+// TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry;
+// assert(child_ptr_type->id == TypeTableEntryIdPointer);
+// child_type = child_ptr_type->data.pointer.child_type;
+// } else if (array_type->id == TypeTableEntryIdArray) {
+// child_type = array_type->data.array.child_type;
+// } else {
+// zig_unreachable();
+// }
+//
+// if (is_lvalue || !ptr || handle_is_ptr(child_type)) {
+// return ptr;
+// } else {
+// return LLVMBuildLoad(g->builder, ptr, "");
+// }
+//}
+//
+//static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
+// assert(node->type == NodeTypeFieldAccessExpr);
+//
+// AstNode *struct_expr = node->data.field_access_expr.struct_expr;
+// TypeTableEntry *struct_type = get_expr_type(struct_expr);
+//
+// if (struct_type->id == TypeTableEntryIdArray) {
+// Buf *name = node->data.field_access_expr.field_name;
+// assert(buf_eql_str(name, "len"));
+// return LLVMConstInt(g->builtin_types.entry_usize->type_ref,
+// struct_type->data.array.len, false);
+// } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer &&
+// struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct))
+// {
+// TypeTableEntry *type_entry;
+// LLVMValueRef ptr = gen_field_ptr(g, node, &type_entry);
+// if (is_lvalue || handle_is_ptr(type_entry)) {
+// return ptr;
+// } else {
+// return LLVMBuildLoad(g->builder, ptr, "");
+// }
+// } else if (struct_type->id == TypeTableEntryIdMetaType) {
+// assert(!is_lvalue);
+// TypeTableEntry *child_type = get_type_for_type_node(struct_expr);
+// if (child_type->id == TypeTableEntryIdEnum) {
+// return gen_enum_value_expr(g, node, child_type, nullptr);
+// } else {
+// zig_unreachable();
+// }
+// } else if (struct_type->id == TypeTableEntryIdNamespace) {
+// VariableTableEntry *variable = get_resolved_expr(node)->variable;
+// assert(variable);
+// return gen_variable(g, node, variable);
+// } else {
+// zig_unreachable();
+// }
+//}
+//
+//static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value, ReturnKnowledge rk) {
+// BlockContext *defer_inner_block = source_node->block_context;
+// BlockContext *defer_outer_block = source_node->block_context->fn_entry->fn_def_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) {
+// gen_defers_for_block(g, defer_inner_block, defer_outer_block,
+// rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull);
+// }
+//
+// TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
+// bool is_extern = g->cur_fn->type_entry->data.fn.fn_type_id.is_extern;
+// if (handle_is_ptr(return_type)) {
+// if (is_extern) {
+// LLVMValueRef by_val_value = LLVMBuildLoad(g->builder, value, "");
+// LLVMBuildRet(g->builder, by_val_value);
+// } else {
+// assert(g->cur_ret_ptr);
+// gen_assign_raw(g, source_node, BinOpTypeAssign, g->cur_ret_ptr, value, return_type, return_type);
+// LLVMBuildRetVoid(g->builder);
+// }
+// } else {
+// LLVMBuildRet(g->builder, value);
+// }
+// return nullptr;
+//}
+//
+//static LLVMValueRef gen_goto(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeGoto);
+//
+// // generate defers for blocks that we exit
+// LabelTableEntry *label = node->data.goto_expr.label_entry;
+// BlockContext *this_context = node->block_context;
+// BlockContext *target_context = label->decl_node->block_context;
+// gen_defers_for_block(g, this_context, target_context, false, false);
+//
+// set_debug_source_node(g, node);
+// LLVMBuildBr(g->builder, node->data.goto_expr.label_entry->basic_block);
+// return nullptr;
+//}
+//
+//static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
+// AstNode *init_expr = node->data.variable_declaration.expr;
+// if (node->data.variable_declaration.is_const && init_expr) {
+// TypeTableEntry *init_expr_type = get_expr_type(init_expr);
+// if (init_expr_type->id == TypeTableEntryIdNumLitFloat ||
+// init_expr_type->id == TypeTableEntryIdNumLitInt)
+// {
+// return nullptr;
+// }
+// }
+//
+// LLVMValueRef init_val = nullptr;
+// TypeTableEntry *init_val_type;
+// return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val, &init_val_type, false);
+//}
+//
+//static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) {
+// // [0-ctz,1-clz][0-8,1-16,2-32,3-64]
+// size_t index0 = (fn_id == BuiltinFnIdCtz) ? 0 : 1;
+// size_t index1 = bits_index(int_type->data.integral.bit_count);
+// LLVMValueRef *fn = &g->int_builtin_fns[index0][index1];
+// if (!*fn) {
+// const char *fn_name = (fn_id == BuiltinFnIdCtz) ? "cttz" : "ctlz";
+// Buf *llvm_name = buf_sprintf("llvm.%s.i%zu", fn_name, int_type->data.integral.bit_count);
+// LLVMTypeRef param_types[] = {
+// int_type->type_ref,
+// LLVMInt1Type(),
+// };
+// LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, 2, false);
+// *fn = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type);
+// }
+// return *fn;
+//}
+//
+//static LLVMValueRef gen_fence(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeFnCallExpr);
+//
+// AstNode *atomic_order_arg = node->data.fn_call_expr.params.at(0);
+// ConstExprValue *atomic_order_val = &get_resolved_expr(atomic_order_arg)->const_val;
+//
+// assert(atomic_order_val->ok);
+//
+// LLVMAtomicOrdering atomic_order = to_LLVMAtomicOrdering((AtomicOrder)atomic_order_val->data.x_enum.tag);
+//
+// LLVMBuildFence(g->builder, atomic_order, false, "");
+// return nullptr;
+//}
+//
+//static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
+// switch (atomic_order) {
+// case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
+// case AtomicOrderMonotonic: return LLVMAtomicOrderingMonotonic;
+// case AtomicOrderAcquire: return LLVMAtomicOrderingAcquire;
+// case AtomicOrderRelease: return LLVMAtomicOrderingRelease;
+// case AtomicOrderAcqRel: return LLVMAtomicOrderingAcquireRelease;
+// case AtomicOrderSeqCst: return LLVMAtomicOrderingSequentiallyConsistent;
+// }
+// zig_unreachable();
+//}
+//
+//static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) {
+// TypeTableEntry *type_entry = get_expr_type(node);
+// assert(type_entry->id == TypeTableEntryIdMaybe);
+// TypeTableEntry *child_type = type_entry->data.maybe.child_type;
+// if (child_type->id == TypeTableEntryIdPointer ||
+// child_type->id == TypeTableEntryIdFn)
+// {
+// return maybe_struct_ref;
+// } else {
+// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, "");
+// return get_handle_value(g, maybe_field_ptr, child_type);
+// }
+//}
+//
+//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 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;
+// size_t result = 0;
+// for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) {
+// AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
+// if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) {
+// return result;
+// }
+// }
+// for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) {
+// AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
+// if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) {
+// return result;
+// }
+// }
+// return SIZE_MAX;
+//}
+//
+//static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeSymbol);
+// VariableTableEntry *variable = get_resolved_expr(node)->variable;
+// if (variable) {
+// return gen_variable(g, node, variable);
+// }
+//
+// zig_unreachable();
+//}
+//
+//static LLVMValueRef gen_label(CodeGen *g, AstNode *node) {
+// assert(node->type == NodeTypeLabel);
+//
+// LabelTableEntry *label = node->data.label.label_entry;
+// assert(label);
+//
+// LLVMBasicBlockRef basic_block = label->basic_block;
+// if (label->entered_from_fallthrough) {
+// set_debug_source_node(g, node);
+// LLVMBuildBr(g->builder, basic_block);
+// }
+// LLVMPositionBuilderAtEnd(g->builder, basic_block);
+// return nullptr;
+//}
+//
+//static LLVMValueRef gen_variable(CodeGen *g, AstNode *source_node, VariableTableEntry *variable) {
+// if (!type_has_bits(variable->type)) {
+// return nullptr;
+// } else {
+// assert(variable->value_ref);
+// return get_handle_value(g, variable->value_ref, variable->type);
+// }
+//}
+//