Commit 9d19b8d66e
Changed files (2)
src/codegen.cpp
@@ -22,7 +22,6 @@
#include <stdio.h>
#include <errno.h>
-
static void init_darwin_native(CodeGen *g) {
char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
@@ -227,27 +226,8 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
g->linker_rdynamic = rdynamic;
}
-static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
-static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry);
-static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue);
-static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
- bool unwrap_maybe, LLVMValueRef *init_val, TypeTableEntry **init_val_type, bool var_is_ptr);
-static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
- LLVMValueRef target_ref, LLVMValueRef value,
- TypeTableEntry *op1_type, TypeTableEntry *op2_type);
-static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref);
-static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
- TypeTableEntry *type_entry, bool exact);
static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
-static TypeTableEntry *get_type_for_type_node(AstNode *node) {
- Expr *expr = get_resolved_expr(node);
- assert(expr->type_entry->id == TypeTableEntryIdMetaType);
- ConstExprValue *const_val = &expr->const_val;
- assert(const_val->ok);
- return const_val->data.x_type;
-}
-
static void set_debug_source_node(CodeGen *g, AstNode *node) {
assert(node->block_context);
ZigLLVMSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, node->block_context->di_scope);
@@ -257,10 +237,6 @@ static void clear_debug_source_node(CodeGen *g) {
ZigLLVMClearCurrentDebugLocation(g->builder);
}
-static TypeTableEntry *get_expr_type(AstNode *node) {
- return get_resolved_expr(node)->type_entry;
-}
-
enum AddSubMul {
AddSubMulAdd = 0,
AddSubMulSub = 1,
@@ -329,24 +305,6 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
return *fn;
}
-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 get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *type) {
if (handle_is_ptr(type)) {
return ptr;
@@ -413,349 +371,6 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
-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 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_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_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 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_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type_non_canon,
TypeTableEntry *wanted_type_non_canon, LLVMValueRef expr_val)
{
@@ -839,111 +454,6 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
}
}
-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_elem_ptr(CodeGen *g, AstNode *source_node, LLVMValueRef array_ptr,
TypeTableEntry *array_type, LLVMValueRef subscript_value)
{
@@ -993,358 +503,78 @@ static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMVal
}
}
-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);
+static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op,
+ LLVMValueRef val1, LLVMValueRef val2)
+{
+ LLVMValueRef fn_val = get_int_overflow_fn(g, type_entry, op);
+ LLVMValueRef params[] = {
+ val1,
+ val2,
+ };
+ 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, "");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
+ LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block);
- LLVMValueRef array_ptr = gen_array_base_ptr(g, array_expr_node);
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_debug_safety_crash(g);
- 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);
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ return result;
}
-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;
- }
+static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
+ LLVMValueRef val1, LLVMValueRef val2)
+{
+ // for unsigned left shifting, we do the wrapping shift, then logically shift
+ // right the same number of bits
+ // if the values don't match, we have an overflow
+ // for signed left shifting we do the same except arithmetic shift right
- LLVMValueRef struct_ptr;
- if (struct_expr_node->type == NodeTypeSymbol) {
- VariableTableEntry *var = get_resolved_expr(struct_expr_node)->variable;
- assert(var);
+ assert(type_entry->id == TypeTableEntryIdInt);
- 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, "");
- }
+ LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
+ LLVMValueRef orig_val;
+ if (type_entry->data.integral.is_signed) {
+ orig_val = LLVMBuildAShr(g->builder, result, val2, "");
} else {
- struct_ptr = gen_expr(g, struct_expr_node);
+ orig_val = LLVMBuildLShr(g->builder, result, val2, "");
}
+ LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
- assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind);
- assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind);
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
+ LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
- size_t gen_field_index = node->data.field_access_expr.type_struct_field->gen_index;
- assert(gen_field_index != SIZE_MAX);
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_debug_safety_crash(g);
- return LLVMBuildStructGEP(g->builder, struct_ptr, gen_field_index, "");
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ return result;
}
-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);
+static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
+ TypeTableEntry *type_entry, bool exact)
+{
- 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);
+ if (want_debug_safety(g, source_node)) {
+ LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
+ LLVMValueRef is_zero_bit;
+ if (type_entry->id == TypeTableEntryIdInt) {
+ is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");
+ } else if (type_entry->id == TypeTableEntryIdFloat) {
+ is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, "");
} else {
- end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
+ zig_unreachable();
}
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
+ LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
- 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_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_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);
- }
-}
-
-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_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_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op,
- LLVMValueRef val1, LLVMValueRef val2)
-{
- LLVMValueRef fn_val = get_int_overflow_fn(g, type_entry, op);
- LLVMValueRef params[] = {
- val1,
- val2,
- };
- 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, "");
- LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
- LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
- LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block);
-
- LLVMPositionBuilderAtEnd(g->builder, fail_block);
- gen_debug_safety_crash(g);
-
- LLVMPositionBuilderAtEnd(g->builder, ok_block);
- return result;
-}
-
-static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
- LLVMValueRef val1, LLVMValueRef val2)
-{
- // for unsigned left shifting, we do the wrapping shift, then logically shift
- // right the same number of bits
- // if the values don't match, we have an overflow
- // for signed left shifting we do the same except arithmetic shift right
-
- assert(type_entry->id == TypeTableEntryIdInt);
-
- LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
- LLVMValueRef orig_val;
- if (type_entry->data.integral.is_signed) {
- orig_val = LLVMBuildAShr(g->builder, result, val2, "");
- } else {
- orig_val = LLVMBuildLShr(g->builder, result, val2, "");
- }
- LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
-
- LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
- LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
- LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
-
- LLVMPositionBuilderAtEnd(g->builder, fail_block);
- gen_debug_safety_crash(g);
-
- LLVMPositionBuilderAtEnd(g->builder, ok_block);
- return result;
-}
-
-static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
- TypeTableEntry *type_entry, bool exact)
-{
-
- if (want_debug_safety(g, source_node)) {
- LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
- LLVMValueRef is_zero_bit;
- if (type_entry->id == TypeTableEntryIdInt) {
- is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");
- } else if (type_entry->id == TypeTableEntryIdFloat) {
- is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, "");
- } else {
- zig_unreachable();
- }
- LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
- LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
- LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
-
- LLVMPositionBuilderAtEnd(g->builder, fail_block);
- gen_debug_safety_crash(g);
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_debug_safety_crash(g);
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
@@ -1529,18 +759,6 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
}
zig_unreachable();
}
-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 LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) {
switch (cmp_op) {
case IrBinOpCmpEq:
@@ -1579,63 +797,6 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_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_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef dest,
TypeTableEntry *type_entry)
{
@@ -1650,632 +811,53 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
uint64_t align_bytes = get_memcpy_align(g, type_entry);
assert(size_bytes > 0);
- assert(align_bytes > 0);
-
- LLVMValueRef params[] = {
- dest_ptr, // dest pointer
- src_ptr, // source pointer
- LLVMConstInt(usize->type_ref, size_bytes, false),
- LLVMConstInt(LLVMInt32Type(), align_bytes, false),
- LLVMConstNull(LLVMInt1Type()), // is volatile
- };
-
- return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
-}
-
-static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
- LLVMValueRef target_ref, LLVMValueRef value,
- TypeTableEntry *op1_type, TypeTableEntry *op2_type)
-{
- if (!type_has_bits(op1_type)) {
- return nullptr;
- }
- if (handle_is_ptr(op1_type)) {
- assert(op1_type == op2_type);
- assert(bin_op == BinOpTypeAssign);
-
- return gen_struct_memcpy(g, value, target_ref, op1_type);
- }
-
- if (bin_op != BinOpTypeAssign) {
- assert(source_node->type == NodeTypeBinOpExpr);
- LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, "");
-
- value = gen_arithmetic_bin_op(g, source_node, left_value, value, op1_type, op2_type, bin_op);
- }
-
- LLVMBuildStore(g->builder, value, target_ref);
- return nullptr;
-}
-
-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(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 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_bin_op_expr(CodeGen *g, AstNode *node) {
- switch (node->data.bin_op_expr.bin_op) {
- case BinOpTypeInvalid:
- case BinOpTypeArrayCat:
- case BinOpTypeArrayMult:
- zig_unreachable();
- case BinOpTypeAssign:
- case BinOpTypeAssignTimes:
- case BinOpTypeAssignTimesWrap:
- case BinOpTypeAssignDiv:
- case BinOpTypeAssignMod:
- case BinOpTypeAssignPlus:
- case BinOpTypeAssignPlusWrap:
- case BinOpTypeAssignMinus:
- case BinOpTypeAssignMinusWrap:
- case BinOpTypeAssignBitShiftLeft:
- case BinOpTypeAssignBitShiftLeftWrap:
- case BinOpTypeAssignBitShiftRight:
- case BinOpTypeAssignBitAnd:
- case BinOpTypeAssignBitXor:
- case BinOpTypeAssignBitOr:
- case BinOpTypeAssignBoolAnd:
- case BinOpTypeAssignBoolOr:
- return gen_assign_expr(g, node);
- case BinOpTypeBoolOr:
- return gen_bool_or_expr(g, node);
- case BinOpTypeBoolAnd:
- return gen_bool_and_expr(g, node);
- case BinOpTypeCmpEq:
- case BinOpTypeCmpNotEq:
- case BinOpTypeCmpLessThan:
- case BinOpTypeCmpGreaterThan:
- case BinOpTypeCmpLessOrEq:
- case BinOpTypeCmpGreaterOrEq:
- zig_panic("moved to ir_render");
- case BinOpTypeUnwrapMaybe:
- return gen_unwrap_maybe_expr(g, node);
- case BinOpTypeBinOr:
- case BinOpTypeBinXor:
- case BinOpTypeBinAnd:
- case BinOpTypeBitShiftLeft:
- case BinOpTypeBitShiftLeftWrap:
- case BinOpTypeBitShiftRight:
- case BinOpTypeAdd:
- case BinOpTypeAddWrap:
- case BinOpTypeSub:
- case BinOpTypeSubWrap:
- case BinOpTypeMult:
- case BinOpTypeMultWrap:
- case BinOpTypeDiv:
- case BinOpTypeMod:
- return gen_arithmetic_bin_op_expr(g, node);
- }
- zig_unreachable();
-}
-
-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 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 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_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 void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) {
- BlockContext *block_context = var->block_context;
- AstNode *source_node = var->decl_node;
- ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc(source_node->line + 1, source_node->column + 1,
- block_context->di_scope);
- ZigLLVMInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc,
- LLVMGetInsertBlock(g->builder));
-}
-
-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);
+ assert(align_bytes > 0);
- bool use_then_value = type_has_bits(then_type);
- bool use_else_value = type_has_bits(else_type);
+ LLVMValueRef params[] = {
+ dest_ptr, // dest pointer
+ src_ptr, // source pointer
+ LLVMConstInt(usize->type_ref, size_bytes, false),
+ LLVMConstInt(LLVMInt32Type(), align_bytes, false),
+ LLVMConstNull(LLVMInt1Type()), // is volatile
+ };
- LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeThen");
- LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeElse");
+ return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
+}
- 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");
+static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
+ LLVMValueRef target_ref, LLVMValueRef value,
+ TypeTableEntry *op1_type, TypeTableEntry *op2_type)
+{
+ if (!type_has_bits(op1_type)) {
+ return nullptr;
}
+ if (handle_is_ptr(op1_type)) {
+ assert(op1_type == op2_type);
+ assert(bin_op == BinOpTypeAssign);
- 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);
+ return gen_struct_memcpy(g, value, target_ref, op1_type);
}
- LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
+ if (bin_op != BinOpTypeAssign) {
+ assert(source_node->type == NodeTypeBinOpExpr);
+ LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, "");
- 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;
- }
+ value = gen_arithmetic_bin_op(g, source_node, left_value, value, op1_type, op2_type, bin_op);
}
+ LLVMBuildStore(g->builder, value, target_ref);
return nullptr;
}
+static void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) {
+ BlockContext *block_context = var->block_context;
+ AstNode *source_node = var->decl_node;
+ ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc(source_node->line + 1, source_node->column + 1,
+ block_context->di_scope);
+ ZigLLVMInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc,
+ LLVMGetInsertBlock(g->builder));
+}
+
static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
if (!type_has_bits(instruction->type_entry))
return nullptr;
@@ -3025,745 +1607,6 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
}
}
-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 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_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_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 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_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_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_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_expr(CodeGen *g, AstNode *node) {
- Expr *expr = get_resolved_expr(node);
- if (expr->const_val.ok) {
- if (!type_has_bits(expr->type_entry)) {
- return nullptr;
- } else {
- assert(expr->const_llvm_val);
- return expr->const_llvm_val;
- }
- }
- switch (node->type) {
- case NodeTypeBinOpExpr:
- return gen_bin_op_expr(g, node);
- case NodeTypeUnwrapErrorExpr:
- return gen_unwrap_err_expr(g, node);
- case NodeTypeReturnExpr:
- return gen_return_expr(g, node);
- case NodeTypeDefer:
- // nothing to do
- return nullptr;
- case NodeTypeVariableDeclaration:
- return gen_var_decl_expr(g, node);
- case NodeTypePrefixOpExpr:
- zig_panic("moved to ir render");
- case NodeTypeFnCallExpr:
- return gen_fn_call_expr(g, node);
- case NodeTypeArrayAccessExpr:
- return gen_array_access_expr(g, node, false);
- case NodeTypeSliceExpr:
- return gen_slice_expr(g, node);
- case NodeTypeFieldAccessExpr:
- return gen_field_access_expr(g, node, false);
- case NodeTypeIfBoolExpr:
- return gen_if_bool_expr(g, node);
- case NodeTypeIfVarExpr:
- return gen_if_var_expr(g, node);
- case NodeTypeWhileExpr:
- return gen_while_expr(g, node);
- case NodeTypeForExpr:
- zig_panic("moved to ir render");
- case NodeTypeAsmExpr:
- return gen_asm_expr(g, node);
- case NodeTypeSymbol:
- return gen_symbol(g, node);
- case NodeTypeBlock:
- return gen_block(g, node, nullptr);
- case NodeTypeGoto:
- return gen_goto(g, node);
- case NodeTypeBreak:
- zig_panic("TODO IR");
- case NodeTypeContinue:
- zig_panic("TODO IR");
- case NodeTypeLabel:
- return gen_label(g, node);
- case NodeTypeContainerInitExpr:
- return gen_container_init_expr(g, node);
- case NodeTypeSwitchExpr:
- return gen_switch_expr(g, node);
- case NodeTypeNumberLiteral:
- case NodeTypeBoolLiteral:
- case NodeTypeStringLiteral:
- case NodeTypeCharLiteral:
- case NodeTypeNullLiteral:
- case NodeTypeUndefinedLiteral:
- case NodeTypeZeroesLiteral:
- case NodeTypeThisLiteral:
- case NodeTypeErrorType:
- case NodeTypeTypeLiteral:
- case NodeTypeArrayType:
- case NodeTypeVarLiteral:
- // caught by constant expression eval codegen
- zig_unreachable();
- case NodeTypeRoot:
- case NodeTypeFnProto:
- case NodeTypeFnDef:
- case NodeTypeFnDecl:
- case NodeTypeParamDecl:
- case NodeTypeUse:
- case NodeTypeContainerDecl:
- case NodeTypeStructField:
- case NodeTypeStructValueField:
- case NodeTypeSwitchProng:
- case NodeTypeSwitchRange:
- case NodeTypeErrorValueDecl:
- case NodeTypeTypeDecl:
- zig_unreachable();
- }
- zig_unreachable();
-}
-
static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
assert(const_val->ok);
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);
+// }
+//}
+//