Commit 77ae3442ef
Changed files (7)
src/all_types.hpp
@@ -29,6 +29,7 @@ struct TypeStructField;
struct CodeGen;
struct ConstExprValue;
struct IrInstruction;
+struct IrInstructionCast;
struct IrBasicBlock;
struct IrExecutable {
@@ -1121,7 +1122,7 @@ struct FnTableEntry {
AstNode *fn_test_set_node;
AstNode *fn_static_eval_set_node;
- ZigList<AstNode *> cast_alloca_list;
+ ZigList<IrInstructionCast *> cast_alloca_list;
ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
ZigList<VariableTableEntry *> variable_list;
ZigList<AstNode *> goto_list;
@@ -1435,6 +1436,7 @@ struct IrInstruction {
// if ref_count is zero, instruction can be omitted in codegen
size_t ref_count;
IrInstruction *other;
+ ReturnKnowledge return_knowledge;
};
struct IrInstructionCondBr {
@@ -1547,7 +1549,8 @@ struct IrInstructionCast {
IrInstruction *value;
IrInstruction *dest_type;
- bool is_implicit;
+ CastOp cast_op;
+ LLVMValueRef tmp_ptr;
};
#endif
src/analyze.cpp
@@ -25,8 +25,6 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE
BlockContext *context, TypeTableEntry *expected_type, AstNode *node);
static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type);
static TypeTableEntry *unwrapped_node_type(AstNode *node);
-static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- AstNode *node);
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node, Buf *err_name);
static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -115,7 +113,7 @@ AstNode *first_executing_node(AstNode *node) {
zig_unreachable();
}
-static void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node) {
+void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node) {
if (!context->fn_entry) return;
if (!context->fn_entry->is_pure) return;
@@ -261,11 +259,6 @@ uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
}
}
-static bool is_u8(TypeTableEntry *type) {
- return type->id == TypeTableEntryIdInt &&
- !type->data.integral.is_signed && type->data.integral.bit_count == 8;
-}
-
static bool is_slice(TypeTableEntry *type) {
return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;
}
@@ -4466,30 +4459,7 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
}
}
-static TypeTableEntry *resolve_cast(CodeGen *g, BlockContext *context, AstNode *node,
- AstNode *expr_node, TypeTableEntry *wanted_type, CastOp op, bool need_alloca)
-{
- node->data.fn_call_expr.cast_op = op;
-
- ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val;
- TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry;
- ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
- if (other_val->ok) {
- eval_const_expr_implicit_cast(node->data.fn_call_expr.cast_op, other_val, other_type,
- const_val, wanted_type);
- }
-
- if (need_alloca) {
- if (context->fn_entry) {
- context->fn_entry->cast_alloca_list.append(node);
- } else {
- assert(get_resolved_expr(node)->const_val.ok);
- }
- }
- return wanted_type;
-}
-
-static bool type_is_codegen_pointer(TypeTableEntry *type) {
+bool type_is_codegen_pointer(TypeTableEntry *type) {
if (type->id == TypeTableEntryIdPointer) return true;
if (type->id == TypeTableEntryIdFn) return true;
if (type->id == TypeTableEntryIdMaybe) {
@@ -4499,256 +4469,6 @@ static bool type_is_codegen_pointer(TypeTableEntry *type) {
return false;
}
-static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- AstNode *node)
-{
- assert(node->type == NodeTypeFnCallExpr);
-
- AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
- size_t actual_param_count = node->data.fn_call_expr.params.length;
-
- if (actual_param_count != 1) {
- add_node_error(g, fn_ref_expr, buf_sprintf("cast expression expects exactly one parameter"));
- return g->builtin_types.entry_invalid;
- }
-
- AstNode *expr_node = node->data.fn_call_expr.params.at(0);
- TypeTableEntry *wanted_type = resolve_type(g, fn_ref_expr);
- TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, expr_node);
- TypeTableEntry *wanted_type_canon = get_underlying_type(wanted_type);
- TypeTableEntry *actual_type_canon = get_underlying_type(actual_type);
-
- if (wanted_type_canon->id == TypeTableEntryIdInvalid ||
- actual_type_canon->id == TypeTableEntryIdInvalid)
- {
- return g->builtin_types.entry_invalid;
- }
-
- // explicit match or non-const to const
- if (types_match_const_cast_only(wanted_type, actual_type)) {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpNoop, false);
- }
-
- // explicit cast from bool to int
- if (wanted_type_canon->id == TypeTableEntryIdInt &&
- actual_type_canon->id == TypeTableEntryIdBool)
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpBoolToInt, false);
- }
-
- // explicit cast from pointer to isize or usize
- if ((wanted_type_canon == g->builtin_types.entry_isize || wanted_type_canon == g->builtin_types.entry_usize) &&
- type_is_codegen_pointer(actual_type_canon))
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpPtrToInt, false);
- }
-
-
- // explicit cast from isize or usize to pointer
- if (wanted_type_canon->id == TypeTableEntryIdPointer &&
- (actual_type_canon == g->builtin_types.entry_isize || actual_type_canon == g->builtin_types.entry_usize))
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpIntToPtr, false);
- }
-
- // explicit widening or shortening cast
- if ((wanted_type_canon->id == TypeTableEntryIdInt &&
- actual_type_canon->id == TypeTableEntryIdInt) ||
- (wanted_type_canon->id == TypeTableEntryIdFloat &&
- actual_type_canon->id == TypeTableEntryIdFloat))
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpWidenOrShorten, false);
- }
-
- // explicit cast from int to float
- if (wanted_type_canon->id == TypeTableEntryIdFloat &&
- actual_type_canon->id == TypeTableEntryIdInt)
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpIntToFloat, false);
- }
-
- // explicit cast from float to int
- if (wanted_type_canon->id == TypeTableEntryIdInt &&
- actual_type_canon->id == TypeTableEntryIdFloat)
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpFloatToInt, false);
- }
-
- // explicit cast from array to slice
- if (is_slice(wanted_type) &&
- actual_type->id == TypeTableEntryIdArray &&
- types_match_const_cast_only(
- wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type,
- actual_type->data.array.child_type))
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpToUnknownSizeArray, true);
- }
-
- // explicit cast from []T to []u8 or []u8 to []T
- if (is_slice(wanted_type) && is_slice(actual_type) &&
- (is_u8(wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type) ||
- is_u8(actual_type->data.structure.fields[0].type_entry->data.pointer.child_type)) &&
- (wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
- !actual_type->data.structure.fields[0].type_entry->data.pointer.is_const))
- {
- mark_impure_fn(g, context, node);
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true);
- }
-
- // explicit cast from [N]u8 to []T
- if (is_slice(wanted_type) &&
- actual_type->id == TypeTableEntryIdArray &&
- is_u8(actual_type->data.array.child_type))
- {
- mark_impure_fn(g, context, node);
- uint64_t child_type_size = type_size(g,
- wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type);
- if (actual_type->data.array.len % child_type_size == 0) {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpBytesToSlice, true);
- } else {
- add_node_error(g, node,
- buf_sprintf("unable to convert %s to %s: size mismatch",
- buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
- return g->builtin_types.entry_invalid;
- }
- }
-
- // explicit cast from pointer to another pointer
- if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
- (wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpPointerReinterpret, false);
- }
-
- // explicit cast from maybe pointer to another maybe pointer
- if (actual_type->id == TypeTableEntryIdMaybe &&
- (actual_type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
- actual_type->data.maybe.child_type->id == TypeTableEntryIdFn) &&
- wanted_type->id == TypeTableEntryIdMaybe &&
- (wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
- wanted_type->data.maybe.child_type->id == TypeTableEntryIdFn))
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpPointerReinterpret, false);
- }
-
- // explicit cast from child type of maybe type to maybe type
- if (wanted_type->id == TypeTableEntryIdMaybe) {
- if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) {
- get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonNull;
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpMaybeWrap, true);
- } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
- actual_type->id == TypeTableEntryIdNumLitFloat)
- {
- if (num_lit_fits_in_other_type(g, expr_node, wanted_type->data.maybe.child_type)) {
- get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonNull;
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpMaybeWrap, true);
- } else {
- return g->builtin_types.entry_invalid;
- }
- }
- }
-
- // explicit cast from null literal to maybe type
- if (wanted_type->id == TypeTableEntryIdMaybe &&
- actual_type->id == TypeTableEntryIdNullLit)
- {
- get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNull;
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpNullToMaybe, true);
- }
-
- // explicit cast from child type of error type to error type
- if (wanted_type->id == TypeTableEntryIdErrorUnion) {
- if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {
- get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonError;
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpErrorWrap, true);
- } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
- actual_type->id == TypeTableEntryIdNumLitFloat)
- {
- if (num_lit_fits_in_other_type(g, expr_node, wanted_type->data.error.child_type)) {
- get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonError;
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpErrorWrap, true);
- } else {
- return g->builtin_types.entry_invalid;
- }
- }
- }
-
- // explicit cast from pure error to error union type
- if (wanted_type->id == TypeTableEntryIdErrorUnion &&
- actual_type->id == TypeTableEntryIdPureError)
- {
- get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownError;
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpPureErrorWrap, false);
- }
-
- // explicit cast from number literal to another type
- if (actual_type->id == TypeTableEntryIdNumLitFloat ||
- actual_type->id == TypeTableEntryIdNumLitInt)
- {
- if (num_lit_fits_in_other_type(g, expr_node, wanted_type_canon)) {
- CastOp op;
- if ((actual_type->id == TypeTableEntryIdNumLitFloat &&
- wanted_type_canon->id == TypeTableEntryIdFloat) ||
- (actual_type->id == TypeTableEntryIdNumLitInt &&
- wanted_type_canon->id == TypeTableEntryIdInt))
- {
- op = CastOpNoop;
- } else if (wanted_type_canon->id == TypeTableEntryIdInt) {
- op = CastOpFloatToInt;
- } else if (wanted_type_canon->id == TypeTableEntryIdFloat) {
- op = CastOpIntToFloat;
- } else {
- zig_unreachable();
- }
- return resolve_cast(g, context, node, expr_node, wanted_type, op, false);
- } else {
- return g->builtin_types.entry_invalid;
- }
- }
-
- // explicit cast from %void to integer type which can fit it
- bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
- !type_has_bits(actual_type->data.error.child_type);
- bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError;
- if ((actual_type_is_void_err || actual_type_is_pure_err) &&
- wanted_type->id == TypeTableEntryIdInt)
- {
- BigNum bn;
- bignum_init_unsigned(&bn, g->error_decls.length);
- if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count,
- wanted_type->data.integral.is_signed))
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpErrToInt, false);
- } else {
- add_node_error(g, node,
- buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
- return g->builtin_types.entry_invalid;
- }
- }
-
- // explicit cast from integer to enum type with no payload
- if (actual_type->id == TypeTableEntryIdInt &&
- wanted_type->id == TypeTableEntryIdEnum &&
- wanted_type->data.enumeration.gen_field_count == 0)
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpIntToEnum, false);
- }
-
- // explicit cast from enum type with no payload to integer
- if (wanted_type->id == TypeTableEntryIdInt &&
- actual_type->id == TypeTableEntryIdEnum &&
- actual_type->data.enumeration.gen_field_count == 0)
- {
- return resolve_cast(g, context, node, expr_node, wanted_type, CastOpEnumToInt, false);
- }
-
- add_node_error(g, node,
- buf_sprintf("invalid cast from type '%s' to '%s'",
- buf_ptr(&actual_type->name),
- buf_ptr(&wanted_type->name)));
- return g->builtin_types.entry_invalid;
-}
-
static TypeTableEntry *analyze_import(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
@@ -5866,13 +5586,14 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
}
}
- if (handle_is_ptr(return_type)) {
- if (context->fn_entry) {
- context->fn_entry->cast_alloca_list.append(node);
- } else if (!result_val->ok) {
- add_node_error(g, node, buf_sprintf("unable to evaluate constant expression"));
- }
- }
+ // TODO
+ //if (handle_is_ptr(return_type)) {
+ // if (context->fn_entry) {
+ // context->fn_entry->cast_alloca_list.append(node);
+ // } else if (!result_val->ok) {
+ // add_node_error(g, node, buf_sprintf("unable to evaluate constant expression"));
+ // }
+ //}
return return_type;
}
@@ -6110,7 +5831,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
if (const_val->ok) {
if (invoke_type_entry->id == TypeTableEntryIdMetaType) {
- return analyze_cast_expr(g, import, context, node);
+ zig_unreachable();
} else if (invoke_type_entry->id == TypeTableEntryIdFn) {
AstNode *struct_node;
if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
src/analyze.hpp
@@ -49,10 +49,14 @@ TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, ImportTableEntry *im
BlockContext *block_context, AstNode *parent_source_node,
AstNode **child_nodes, TypeTableEntry **child_types, size_t child_count);
+
+
bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type);
VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context, Buf *name);
AstNode *find_decl(BlockContext *context, Buf *name);
void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only);
TopLevelDecl *get_as_top_level_decl(AstNode *node);
+void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node);
+bool type_is_codegen_pointer(TypeTableEntry *type);
#endif
src/codegen.cpp
@@ -344,11 +344,10 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui
return *fn;
}
-static LLVMValueRef get_handle_value(CodeGen *g, AstNode *source_node, LLVMValueRef ptr, TypeTableEntry *type) {
+static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *type) {
if (handle_is_ptr(type)) {
return ptr;
} else {
- set_debug_source_node(g, source_node);
return LLVMBuildLoad(g->builder, ptr, "");
}
}
@@ -378,7 +377,7 @@ static void gen_debug_safety_crash(CodeGen *g) {
LLVMBuildUnreachable(g->builder);
}
-static void add_bounds_check(CodeGen *g, AstNode *source_node, LLVMValueRef target_val,
+static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
LLVMIntPredicate lower_pred, LLVMValueRef lower_value,
LLVMIntPredicate upper_pred, LLVMValueRef upper_value)
{
@@ -391,8 +390,6 @@ static void add_bounds_check(CodeGen *g, AstNode *source_node, LLVMValueRef targ
upper_value = nullptr;
}
- set_debug_source_node(g, source_node);
-
LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckFail");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckOk");
LLVMBasicBlockRef lower_ok_block = upper_value ?
@@ -425,12 +422,11 @@ static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) {
AstNode *err_val_node = node->data.fn_call_expr.params.at(0);
LLVMValueRef err_val = gen_expr(g, err_val_node);
- set_debug_source_node(g, 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, node, err_val, LLVMIntNE, zero, LLVMIntULT, end_val);
+ add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val);
}
LLVMValueRef indices[] = {
@@ -514,15 +510,12 @@ static LLVMValueRef gen_truncate(CodeGen *g, AstNode *node) {
LLVMValueRef src_val = gen_expr(g, src_node);
- set_debug_source_node(g, node);
return LLVMBuildTrunc(g->builder, src_val, dest_type->type_ref, "");
}
static LLVMValueRef gen_unreachable(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr);
- set_debug_source_node(g, node);
-
if (want_debug_safety(g, node) || g->is_test_build) {
gen_debug_safety_crash(g);
} else {
@@ -545,7 +538,6 @@ static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) {
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));
- set_debug_source_node(g, node);
LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
LLVMValueRef orig_val;
if (int_type->data.integral.is_signed) {
@@ -590,7 +582,6 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
operand,
LLVMConstNull(LLVMInt1Type()),
};
- set_debug_source_node(g, node);
return LLVMBuildCall(g->builder, fn_val, params, 2, "");
}
case BuiltinFnIdAddWithOverflow:
@@ -622,7 +613,6 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
op2,
};
- set_debug_source_node(g, node);
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, "");
@@ -646,7 +636,6 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
- set_debug_source_node(g, node);
LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, "");
@@ -677,7 +666,6 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
- set_debug_source_node(g, node);
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);
@@ -707,13 +695,11 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
case BuiltinFnIdErrName:
return gen_err_name(g, node);
case BuiltinFnIdBreakpoint:
- set_debug_source_node(g, node);
return LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, "");
case BuiltinFnIdFrameAddress:
case BuiltinFnIdReturnAddress:
{
LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
- set_debug_source_node(g, node);
return LLVMBuildCall(g->builder, builtin_fn->fn_val, &zero, 1, "");
}
case BuiltinFnIdCmpExchange:
@@ -760,7 +746,6 @@ static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntr
LLVMValueRef tmp_struct_ptr = node->data.field_access_expr.resolved_struct_val_expr.ptr;
// populate the new tag value
- set_debug_source_node(g, node);
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, "");
LLVMBuildStore(g->builder, tag_value, tag_field_ptr);
@@ -804,7 +789,6 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
!wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed &&
want_debug_safety(g, source_node))
{
- set_debug_source_node(g, source_node);
LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, "");
@@ -822,14 +806,11 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
return expr_val;
} else if (actual_bits < wanted_bits) {
if (actual_type->id == TypeTableEntryIdFloat) {
- set_debug_source_node(g, source_node);
return LLVMBuildFPExt(g->builder, expr_val, wanted_type->type_ref, "");
} else if (actual_type->id == TypeTableEntryIdInt) {
if (actual_type->data.integral.is_signed) {
- set_debug_source_node(g, source_node);
return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
} else {
- set_debug_source_node(g, source_node);
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
}
} else {
@@ -837,10 +818,8 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
}
} else if (actual_bits > wanted_bits) {
if (actual_type->id == TypeTableEntryIdFloat) {
- set_debug_source_node(g, source_node);
return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, "");
} else if (actual_type->id == TypeTableEntryIdInt) {
- set_debug_source_node(g, source_node);
LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
if (!want_debug_safety(g, source_node)) {
return trunc_val;
@@ -869,256 +848,11 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
}
}
-static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
- assert(node->type == NodeTypeFnCallExpr);
-
- AstNode *expr_node = node->data.fn_call_expr.params.at(0);
-
- LLVMValueRef expr_val = gen_expr(g, expr_node);
-
- TypeTableEntry *actual_type = get_expr_type(expr_node);
- TypeTableEntry *wanted_type = get_expr_type(node);
-
- AstNodeFnCallExpr *cast_expr = &node->data.fn_call_expr;
-
- switch (cast_expr->cast_op) {
- case CastOpNoCast:
- zig_unreachable();
- case CastOpNoop:
- return expr_val;
- case CastOpErrToInt:
- assert(actual_type->id == TypeTableEntryIdErrorUnion);
- if (!type_has_bits(actual_type->data.error.child_type)) {
- return gen_widen_or_shorten(g, node, g->err_tag_type, wanted_type, expr_val);
- } else {
- zig_panic("TODO");
- }
- case CastOpMaybeWrap:
- {
- assert(cast_expr->tmp_ptr);
- assert(wanted_type->id == TypeTableEntryIdMaybe);
- assert(actual_type);
-
- TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
-
- if (child_type->id == TypeTableEntryIdPointer ||
- child_type->id == TypeTableEntryIdFn)
- {
- return expr_val;
- } else {
- set_debug_source_node(g, node);
- LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, "");
- gen_assign_raw(g, node, BinOpTypeAssign,
- val_ptr, expr_val, child_type, actual_type);
-
- set_debug_source_node(g, node);
- LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, "");
- LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
- }
-
- return cast_expr->tmp_ptr;
- }
- case CastOpNullToMaybe:
- // handled by constant expression evaluator
- zig_unreachable();
- case CastOpErrorWrap:
- {
- assert(wanted_type->id == TypeTableEntryIdErrorUnion);
- TypeTableEntry *child_type = wanted_type->data.error.child_type;
- LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);
-
- if (!type_has_bits(child_type)) {
- return ok_err_val;
- } else {
- assert(cast_expr->tmp_ptr);
- assert(wanted_type->id == TypeTableEntryIdErrorUnion);
- assert(actual_type);
-
- set_debug_source_node(g, node);
- LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, "");
- LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);
-
- LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, "");
- gen_assign_raw(g, node, BinOpTypeAssign,
- payload_ptr, expr_val, child_type, actual_type);
-
- return cast_expr->tmp_ptr;
- }
- }
- case CastOpPureErrorWrap:
- assert(wanted_type->id == TypeTableEntryIdErrorUnion);
-
- if (!type_has_bits(wanted_type->data.error.child_type)) {
- return expr_val;
- } else {
- zig_panic("TODO");
- }
- case CastOpPtrToInt:
- set_debug_source_node(g, node);
- return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
- case CastOpIntToPtr:
- set_debug_source_node(g, node);
- return LLVMBuildIntToPtr(g->builder, expr_val, wanted_type->type_ref, "");
- case CastOpPointerReinterpret:
- set_debug_source_node(g, node);
- return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
- case CastOpWidenOrShorten:
- return gen_widen_or_shorten(g, node, actual_type, wanted_type, expr_val);
- case CastOpToUnknownSizeArray:
- {
- assert(cast_expr->tmp_ptr);
- assert(wanted_type->id == TypeTableEntryIdStruct);
- assert(wanted_type->data.structure.is_slice);
-
- TypeTableEntry *pointer_type = wanted_type->data.structure.fields[0].type_entry;
-
- set_debug_source_node(g, node);
-
- size_t ptr_index = wanted_type->data.structure.fields[0].gen_index;
- if (ptr_index != SIZE_MAX) {
- LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, ptr_index, "");
- LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, "");
- LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr);
- }
-
- size_t len_index = wanted_type->data.structure.fields[1].gen_index;
- LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, len_index, "");
- LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
- actual_type->data.array.len, false);
- LLVMBuildStore(g->builder, len_val, len_ptr);
-
- return cast_expr->tmp_ptr;
- }
- case CastOpResizeSlice:
- {
- assert(cast_expr->tmp_ptr);
- assert(wanted_type->id == TypeTableEntryIdStruct);
- assert(wanted_type->data.structure.is_slice);
- assert(actual_type->id == TypeTableEntryIdStruct);
- assert(actual_type->data.structure.is_slice);
-
- TypeTableEntry *actual_pointer_type = actual_type->data.structure.fields[0].type_entry;
- TypeTableEntry *actual_child_type = actual_pointer_type->data.pointer.child_type;
- TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
- TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
-
- set_debug_source_node(g, node);
-
- size_t actual_ptr_index = actual_type->data.structure.fields[0].gen_index;
- size_t actual_len_index = actual_type->data.structure.fields[1].gen_index;
- size_t wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
- size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
-
- LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_ptr_index, "");
- LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, "");
- LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr,
- wanted_type->data.structure.fields[0].type_entry->type_ref, "");
- LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr,
- wanted_ptr_index, "");
- LLVMBuildStore(g->builder, src_ptr_casted, dest_ptr_ptr);
-
- LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_len_index, "");
- LLVMValueRef src_len = LLVMBuildLoad(g->builder, src_len_ptr, "");
- uint64_t src_size = type_size(g, actual_child_type);
- uint64_t dest_size = type_size(g, wanted_child_type);
-
- LLVMValueRef new_len;
- if (dest_size == 1) {
- LLVMValueRef src_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, src_size, false);
- new_len = LLVMBuildMul(g->builder, src_len, src_size_val, "");
- } else if (src_size == 1) {
- LLVMValueRef dest_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, dest_size, false);
- if (want_debug_safety(g, node)) {
- LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, "");
- LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
- LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
- LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenOk");
- LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenFail");
- LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
-
- LLVMPositionBuilderAtEnd(g->builder, fail_block);
- gen_debug_safety_crash(g);
-
- LLVMPositionBuilderAtEnd(g->builder, ok_block);
- }
- new_len = ZigLLVMBuildExactUDiv(g->builder, src_len, dest_size_val, "");
- } else {
- zig_unreachable();
- }
-
- LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr,
- wanted_len_index, "");
- LLVMBuildStore(g->builder, new_len, dest_len_ptr);
-
-
- return cast_expr->tmp_ptr;
- }
- case CastOpBytesToSlice:
- {
- assert(cast_expr->tmp_ptr);
- assert(wanted_type->id == TypeTableEntryIdStruct);
- assert(wanted_type->data.structure.is_slice);
- assert(actual_type->id == TypeTableEntryIdArray);
-
- TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
- TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
-
- set_debug_source_node(g, node);
-
- size_t wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
- LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, wanted_ptr_index, "");
- LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, "");
- LLVMBuildStore(g->builder, src_ptr_casted, dest_ptr_ptr);
-
- size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
- LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, wanted_len_index, "");
- LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
- actual_type->data.array.len / type_size(g, wanted_child_type), false);
- LLVMBuildStore(g->builder, len_val, len_ptr);
-
- return cast_expr->tmp_ptr;
- }
- case CastOpIntToFloat:
- assert(actual_type->id == TypeTableEntryIdInt);
- if (actual_type->data.integral.is_signed) {
- set_debug_source_node(g, node);
- return LLVMBuildSIToFP(g->builder, expr_val, wanted_type->type_ref, "");
- } else {
- set_debug_source_node(g, node);
- return LLVMBuildUIToFP(g->builder, expr_val, wanted_type->type_ref, "");
- }
- case CastOpFloatToInt:
- assert(wanted_type->id == TypeTableEntryIdInt);
- if (wanted_type->data.integral.is_signed) {
- set_debug_source_node(g, node);
- return LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
- } else {
- set_debug_source_node(g, node);
- return LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
- }
-
- case CastOpBoolToInt:
- assert(wanted_type->id == TypeTableEntryIdInt);
- assert(actual_type->id == TypeTableEntryIdBool);
- set_debug_source_node(g, node);
- return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
-
- case CastOpIntToEnum:
- return gen_widen_or_shorten(g, node, actual_type, wanted_type->data.enumeration.tag_type, expr_val);
- case CastOpEnumToInt:
- return gen_widen_or_shorten(g, node, actual_type->data.enumeration.tag_type, wanted_type, expr_val);
- }
- zig_unreachable();
-}
-
-
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);
- } else if (node->data.fn_call_expr.cast_op != CastOpNoCast) {
- return gen_cast_expr(g, node);
}
FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
@@ -1186,7 +920,6 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
}
}
- set_debug_source_node(g, node);
LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");
@@ -1209,7 +942,6 @@ static LLVMValueRef gen_array_base_ptr(CodeGen *g, AstNode *node) {
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
- set_debug_source_node(g, node);
array_ptr = LLVMBuildLoad(g->builder, array_ptr, "");
}
} else {
@@ -1234,20 +966,18 @@ static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMVal
if (want_debug_safety(g, source_node)) {
LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
array_type->data.array.len, false);
- add_bounds_check(g, source_node, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end);
+ add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end);
}
LLVMValueRef indices[] = {
LLVMConstNull(g->builtin_types.entry_usize->type_ref),
subscript_value
};
- set_debug_source_node(g, source_node);
return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
} else if (array_type->id == TypeTableEntryIdPointer) {
assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
LLVMValueRef indices[] = {
subscript_value
};
- set_debug_source_node(g, source_node);
return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, "");
} else if (array_type->id == TypeTableEntryIdStruct) {
assert(array_type->data.structure.is_slice);
@@ -1255,15 +985,13 @@ static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMVal
assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
if (want_debug_safety(g, source_node)) {
- set_debug_source_node(g, source_node);
size_t len_index = array_type->data.structure.fields[1].gen_index;
assert(len_index != SIZE_MAX);
LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, "");
LLVMValueRef len = LLVMBuildLoad(g->builder, len_ptr, "");
- add_bounds_check(g, source_node, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, len);
+ add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, len);
}
- set_debug_source_node(g, source_node);
size_t ptr_index = array_type->data.structure.fields[0].gen_index;
assert(ptr_index != SIZE_MAX);
LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, "");
@@ -1302,7 +1030,6 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
assert(var);
if (var->type->id == TypeTableEntryIdPointer) {
- set_debug_source_node(g, node);
struct_ptr = LLVMBuildLoad(g->builder, var->value_ref, "");
} else {
struct_ptr = var->value_ref;
@@ -1312,7 +1039,6 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
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
- set_debug_source_node(g, node);
struct_ptr = LLVMBuildLoad(g->builder, struct_ptr, "");
}
} else {
@@ -1325,7 +1051,6 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
size_t gen_field_index = node->data.field_access_expr.type_struct_field->gen_index;
assert(gen_field_index != SIZE_MAX);
- set_debug_source_node(g, node);
return LLVMBuildStructGEP(g->builder, struct_ptr, gen_field_index, "");
}
@@ -1348,15 +1073,14 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
}
if (want_debug_safety(g, node)) {
- add_bounds_check(g, node, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
+ 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, node, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end);
+ add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end);
}
}
- set_debug_source_node(g, node);
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, "");
LLVMValueRef indices[] = {
LLVMConstNull(g->builtin_types.entry_usize->type_ref),
@@ -1375,10 +1099,9 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
LLVMValueRef end_val = gen_expr(g, node->data.slice_expr.end);
if (want_debug_safety(g, node)) {
- add_bounds_check(g, node, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
+ add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
}
- set_debug_source_node(g, node);
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);
@@ -1400,7 +1123,6 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
LLVMValueRef prev_end = nullptr;
if (!node->data.slice_expr.end || want_debug_safety(g, node)) {
- set_debug_source_node(g, node);
LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, "");
prev_end = LLVMBuildLoad(g->builder, src_len_ptr, "");
}
@@ -1415,13 +1137,12 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
if (want_debug_safety(g, node)) {
assert(prev_end);
- add_bounds_check(g, node, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
+ add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
if (node->data.slice_expr.end) {
- add_bounds_check(g, node, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end);
+ add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end);
}
}
- set_debug_source_node(g, node);
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, "");
@@ -1461,7 +1182,6 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lva
if (is_lvalue || !ptr || handle_is_ptr(child_type)) {
return ptr;
} else {
- set_debug_source_node(g, node);
return LLVMBuildLoad(g->builder, ptr, "");
}
}
@@ -1471,7 +1191,7 @@ static LLVMValueRef gen_variable(CodeGen *g, AstNode *source_node, VariableTable
return nullptr;
} else {
assert(variable->value_ref);
- return get_handle_value(g, source_node, variable->value_ref, variable->type);
+ return get_handle_value(g, variable->value_ref, variable->type);
}
}
@@ -1494,7 +1214,6 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva
if (is_lvalue || handle_is_ptr(type_entry)) {
return ptr;
} else {
- set_debug_source_node(g, node);
return LLVMBuildLoad(g->builder, ptr, "");
}
} else if (struct_type->id == TypeTableEntryIdMetaType) {
@@ -1631,7 +1350,6 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
case PrefixOpNegationWrap:
{
LLVMValueRef expr = gen_expr(g, expr_node);
- set_debug_source_node(g, node);
if (expr_type->id == TypeTableEntryIdFloat) {
return LLVMBuildFNeg(g->builder, expr, "");
} else if (expr_type->id == TypeTableEntryIdInt) {
@@ -1653,13 +1371,11 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
{
LLVMValueRef expr = gen_expr(g, expr_node);
LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr));
- set_debug_source_node(g, node);
return LLVMBuildICmp(g->builder, LLVMIntEQ, expr, zero, "");
}
case PrefixOpBinNot:
{
LLVMValueRef expr = gen_expr(g, expr_node);
- set_debug_source_node(g, node);
return LLVMBuildNot(g->builder, expr, "");
}
case PrefixOpAddressOf:
@@ -1677,7 +1393,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
return nullptr;
} else {
TypeTableEntry *child_type = expr_type->data.pointer.child_type;
- return get_handle_value(g, node, expr, child_type);
+ return get_handle_value(g, expr, child_type);
}
}
case PrefixOpMaybe:
@@ -1698,13 +1414,11 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
if (want_debug_safety(g, node)) {
LLVMValueRef err_val;
if (type_has_bits(child_type)) {
- set_debug_source_node(g, node);
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, "");
err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
} else {
err_val = expr_val;
}
- set_debug_source_node(g, node);
LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError");
@@ -1719,7 +1433,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
if (type_has_bits(child_type)) {
LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, "");
- return get_handle_value(g, expr_node, child_val_ptr, child_type);
+ return get_handle_value(g, child_val_ptr, child_type);
} else {
return nullptr;
}
@@ -1733,7 +1447,6 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
TypeTableEntry *child_type = expr_type->data.maybe.child_type;
if (want_debug_safety(g, node)) {
- set_debug_source_node(g, node);
LLVMValueRef cond_val;
if (child_type->id == TypeTableEntryIdPointer ||
child_type->id == TypeTableEntryIdFn)
@@ -1761,9 +1474,8 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
{
return expr_val;
} else {
- set_debug_source_node(g, node);
LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, "");
- return get_handle_value(g, node, maybe_field_ptr, child_type);
+ return get_handle_value(g, maybe_field_ptr, child_type);
}
}
}
@@ -1773,7 +1485,6 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
TypeTableEntry *type_entry, bool exact)
{
- set_debug_source_node(g, source_node);
if (want_debug_safety(g, source_node)) {
LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
@@ -1846,22 +1557,18 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
switch (bin_op) {
case BinOpTypeBinOr:
case BinOpTypeAssignBitOr:
- set_debug_source_node(g, source_node);
return LLVMBuildOr(g->builder, val1, val2, "");
case BinOpTypeBinXor:
case BinOpTypeAssignBitXor:
- set_debug_source_node(g, source_node);
return LLVMBuildXor(g->builder, val1, val2, "");
case BinOpTypeBinAnd:
case BinOpTypeAssignBitAnd:
- set_debug_source_node(g, source_node);
return LLVMBuildAnd(g->builder, val1, val2, "");
case BinOpTypeBitShiftLeft:
case BinOpTypeBitShiftLeftWrap:
case BinOpTypeAssignBitShiftLeft:
case BinOpTypeAssignBitShiftLeftWrap:
{
- set_debug_source_node(g, source_node);
assert(op1_type->id == TypeTableEntryIdInt);
bool is_wrapping = (bin_op == BinOpTypeBitShiftLeftWrap) ||
(bin_op == BinOpTypeAssignBitShiftLeftWrap);
@@ -1880,7 +1587,6 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
assert(op1_type->id == TypeTableEntryIdInt);
assert(op2_type->id == TypeTableEntryIdInt);
- set_debug_source_node(g, source_node);
if (op1_type->data.integral.is_signed) {
return LLVMBuildAShr(g->builder, val1, val2, "");
} else {
@@ -1890,7 +1596,6 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
case BinOpTypeAddWrap:
case BinOpTypeAssignPlus:
case BinOpTypeAssignPlusWrap:
- set_debug_source_node(g, source_node);
if (op1_type->id == TypeTableEntryIdFloat) {
return LLVMBuildFAdd(g->builder, val1, val2, "");
} else if (op1_type->id == TypeTableEntryIdInt) {
@@ -1911,7 +1616,6 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
case BinOpTypeSubWrap:
case BinOpTypeAssignMinus:
case BinOpTypeAssignMinusWrap:
- set_debug_source_node(g, source_node);
if (op1_type->id == TypeTableEntryIdFloat) {
return LLVMBuildFSub(g->builder, val1, val2, "");
} else if (op1_type->id == TypeTableEntryIdInt) {
@@ -1932,7 +1636,6 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
case BinOpTypeMultWrap:
case BinOpTypeAssignTimes:
case BinOpTypeAssignTimesWrap:
- set_debug_source_node(g, source_node);
if (op1_type->id == TypeTableEntryIdFloat) {
return LLVMBuildFMul(g->builder, val1, val2, "");
} else if (op1_type->id == TypeTableEntryIdInt) {
@@ -1954,7 +1657,6 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
return gen_div(g, source_node, val1, val2, op1_type, false);
case BinOpTypeMod:
case BinOpTypeAssignMod:
- set_debug_source_node(g, source_node);
if (op1_type->id == TypeTableEntryIdFloat) {
return LLVMBuildFRem(g->builder, val1, val2, "");
} else {
@@ -2044,7 +1746,6 @@ static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) {
TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
assert(op1_type == op2_type);
- set_debug_source_node(g, node);
if (op1_type->id == TypeTableEntryIdFloat) {
LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op);
return LLVMBuildFCmp(g->builder, pred, val1, val2, "");
@@ -2081,18 +1782,15 @@ static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
// block for when val1 == false (don't even evaluate the second part)
LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndFalse");
- set_debug_source_node(g, node);
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);
- set_debug_source_node(g, node);
LLVMBuildBr(g->builder, false_block);
LLVMPositionBuilderAtEnd(g->builder, false_block);
- set_debug_source_node(g, node);
LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
LLVMValueRef incoming_values[2] = {val1, val2};
LLVMBasicBlockRef incoming_blocks[2] = {post_val1_block, post_val2_block};
@@ -2112,7 +1810,6 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
// block for when val1 == true (don't even evaluate the second part)
LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrTrue");
- set_debug_source_node(g, expr_node);
LLVMBuildCondBr(g->builder, val1, true_block, false_block);
LLVMPositionBuilderAtEnd(g->builder, false_block);
@@ -2120,11 +1817,9 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
LLVMBasicBlockRef post_val2_block = LLVMGetInsertBlock(g->builder);
- set_debug_source_node(g, expr_node);
LLVMBuildBr(g->builder, true_block);
LLVMPositionBuilderAtEnd(g->builder, true_block);
- set_debug_source_node(g, expr_node);
LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
LLVMValueRef incoming_values[2] = {val1, val2};
LLVMBasicBlockRef incoming_blocks[2] = {post_val1_block, post_val2_block};
@@ -2133,14 +1828,13 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
return phi;
}
-static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValueRef src, LLVMValueRef dest,
+static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef dest,
TypeTableEntry *type_entry)
{
assert(handle_is_ptr(type_entry));
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
- set_debug_source_node(g, source_node);
LLVMValueRef src_ptr = LLVMBuildBitCast(g->builder, src, ptr_u8, "");
LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, dest, ptr_u8, "");
@@ -2172,18 +1866,16 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b
assert(op1_type == op2_type);
assert(bin_op == BinOpTypeAssign);
- return gen_struct_memcpy(g, source_node, value, target_ref, op1_type);
+ return gen_struct_memcpy(g, value, target_ref, op1_type);
}
if (bin_op != BinOpTypeAssign) {
assert(source_node->type == NodeTypeBinOpExpr);
- set_debug_source_node(g, source_node->data.bin_op_expr.op1);
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);
}
- set_debug_source_node(g, source_node);
LLVMBuildStore(g->builder, value, target_ref);
return nullptr;
}
@@ -2214,9 +1906,8 @@ static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef may
{
return maybe_struct_ref;
} else {
- set_debug_source_node(g, node);
LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, "");
- return get_handle_value(g, node, maybe_field_ptr, child_type);
+ return get_handle_value(g, maybe_field_ptr, child_type);
}
}
@@ -2240,7 +1931,6 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref,
LLVMConstNull(child_type->type_ref), "");
} else {
- set_debug_source_node(g, node);
LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, "");
cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
}
@@ -2255,21 +1945,18 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
LLVMPositionBuilderAtEnd(g->builder, non_null_block);
LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref);
- set_debug_source_node(g, node);
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) {
- set_debug_source_node(g, node);
LLVMBuildBr(g->builder, end_block);
}
LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder);
LLVMPositionBuilderAtEnd(g->builder, end_block);
if (null_reachable) {
- set_debug_source_node(g, node);
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};
@@ -2351,7 +2038,6 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
assert(expr_type->id == TypeTableEntryIdErrorUnion);
TypeTableEntry *child_type = expr_type->data.error.child_type;
LLVMValueRef err_val;
- set_debug_source_node(g, node);
if (handle_is_ptr(expr_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, "");
err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
@@ -2377,7 +2063,6 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
LLVMBuildStore(g->builder, err_val, var->value_ref);
}
LLVMValueRef err_result = gen_expr(g, op2);
- set_debug_source_node(g, node);
if (have_end_block) {
LLVMBuildBr(g->builder, end_block);
} else if (err_reachable) {
@@ -2389,7 +2074,7 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
return nullptr;
}
LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, "");
- LLVMValueRef child_val = get_handle_value(g, node, child_val_ptr, child_type);
+ LLVMValueRef child_val = get_handle_value(g, child_val_ptr, child_type);
if (!have_end_block) {
return child_val;
@@ -2452,17 +2137,14 @@ static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef va
bool is_extern = g->cur_fn->type_entry->data.fn.fn_type_id.is_extern;
if (handle_is_ptr(return_type)) {
if (is_extern) {
- set_debug_source_node(g, source_node);
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);
- set_debug_source_node(g, source_node);
LLVMBuildRetVoid(g->builder);
}
} else {
- set_debug_source_node(g, source_node);
LLVMBuildRet(g->builder, value);
}
return nullptr;
@@ -2504,7 +2186,6 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrRetReturn");
LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrRetContinue");
- set_debug_source_node(g, node);
LLVMValueRef err_val;
if (type_has_bits(child_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, value, 0, "");
@@ -2524,7 +2205,6 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
if (type_has_bits(return_type->data.error.child_type)) {
assert(g->cur_ret_ptr);
- set_debug_source_node(g, node);
LLVMValueRef tag_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 0, "");
LLVMBuildStore(g->builder, err_val, tag_ptr);
LLVMBuildRetVoid(g->builder);
@@ -2537,9 +2217,8 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
LLVMPositionBuilderAtEnd(g->builder, continue_block);
if (type_has_bits(child_type)) {
- set_debug_source_node(g, node);
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, "");
- return get_handle_value(g, node, val_ptr, child_type);
+ return get_handle_value(g, val_ptr, child_type);
} else {
return nullptr;
}
@@ -2552,7 +2231,6 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetReturn");
LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetContinue");
- set_debug_source_node(g, node);
LLVMValueRef maybe_val_ptr = LLVMBuildStructGEP(g->builder, value, 1, "");
LLVMValueRef is_non_null = LLVMBuildLoad(g->builder, maybe_val_ptr, "");
@@ -2566,7 +2244,6 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
if (handle_is_ptr(return_type)) {
assert(g->cur_ret_ptr);
- set_debug_source_node(g, node);
LLVMValueRef maybe_bit_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 1, "");
LLVMBuildStore(g->builder, zero, maybe_bit_ptr);
LLVMBuildRetVoid(g->builder);
@@ -2577,9 +2254,8 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
LLVMPositionBuilderAtEnd(g->builder, continue_block);
if (type_has_bits(child_type)) {
- set_debug_source_node(g, node);
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 0, "");
- return get_handle_value(g, node, val_ptr, child_type);
+ return get_handle_value(g, val_ptr, child_type);
} else {
return nullptr;
}
@@ -2610,7 +2286,6 @@ static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMV
endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
}
- set_debug_source_node(g, source_node);
LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
LLVMPositionBuilderAtEnd(g->builder, then_block);
@@ -2632,7 +2307,6 @@ static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMV
if (then_endif_reachable || else_endif_reachable) {
LLVMPositionBuilderAtEnd(g->builder, endif_block);
if (use_then_value && use_else_value) {
- set_debug_source_node(g, source_node);
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};
@@ -2697,7 +2371,7 @@ static LLVMValueRef gen_if_var_then_block(CodeGen *g, AstNode *node, VariableTab
payload_val = init_val;
} else {
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, "");
- payload_val = get_handle_value(g, node, payload_ptr, child_type);
+ 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);
@@ -2736,10 +2410,8 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
LLVMValueRef cond_value;
if (maybe_is_ptr) {
- set_debug_source_node(g, node);
cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), "");
} else {
- set_debug_source_node(g, node);
LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, "");
cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
}
@@ -2760,7 +2432,6 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEndIf");
}
- set_debug_source_node(g, node);
LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
LLVMPositionBuilderAtEnd(g->builder, then_block);
@@ -2810,7 +2481,7 @@ static LLVMValueRef ir_render_load_var(CodeGen *g, IrExecutable *executable,
return nullptr;
assert(var->value_ref);
- return get_handle_value(g, load_var_instruction->base.source_node, var->value_ref, var->type);
+ return get_handle_value(g, var->value_ref, var->type);
}
static LLVMValueRef ir_render_bin_op_bool(CodeGen *g, IrExecutable *executable,
@@ -2894,6 +2565,233 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
zig_unreachable();
}
+static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
+ IrInstructionCast *cast_instruction)
+{
+ TypeTableEntry *actual_type = cast_instruction->value->type_entry;
+ TypeTableEntry *wanted_type = cast_instruction->base.type_entry;
+ LLVMValueRef expr_val = cast_instruction->value->llvm_value;
+ assert(expr_val);
+
+ switch (cast_instruction->cast_op) {
+ case CastOpNoCast:
+ zig_unreachable();
+ case CastOpNoop:
+ return expr_val;
+ case CastOpErrToInt:
+ assert(actual_type->id == TypeTableEntryIdErrorUnion);
+ if (!type_has_bits(actual_type->data.error.child_type)) {
+ return gen_widen_or_shorten(g, cast_instruction->base.source_node,
+ g->err_tag_type, wanted_type, expr_val);
+ } else {
+ zig_panic("TODO");
+ }
+ case CastOpMaybeWrap:
+ {
+ assert(cast_instruction->tmp_ptr);
+ assert(wanted_type->id == TypeTableEntryIdMaybe);
+ assert(actual_type);
+
+ TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
+
+ if (child_type->id == TypeTableEntryIdPointer ||
+ child_type->id == TypeTableEntryIdFn)
+ {
+ return expr_val;
+ } else {
+ LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 0, "");
+ gen_assign_raw(g, cast_instruction->base.source_node, BinOpTypeAssign,
+ val_ptr, expr_val, child_type, actual_type);
+
+ LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, "");
+ LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
+ }
+
+ return cast_instruction->tmp_ptr;
+ }
+ case CastOpNullToMaybe:
+ // handled by constant expression evaluator
+ zig_unreachable();
+ case CastOpErrorWrap:
+ {
+ assert(wanted_type->id == TypeTableEntryIdErrorUnion);
+ TypeTableEntry *child_type = wanted_type->data.error.child_type;
+ LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);
+
+ if (!type_has_bits(child_type)) {
+ return ok_err_val;
+ } else {
+ assert(cast_instruction->tmp_ptr);
+ assert(wanted_type->id == TypeTableEntryIdErrorUnion);
+ assert(actual_type);
+
+ LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 0, "");
+ LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);
+
+ LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, "");
+ gen_assign_raw(g, cast_instruction->base.source_node, BinOpTypeAssign,
+ payload_ptr, expr_val, child_type, actual_type);
+
+ return cast_instruction->tmp_ptr;
+ }
+ }
+ case CastOpPureErrorWrap:
+ assert(wanted_type->id == TypeTableEntryIdErrorUnion);
+
+ if (!type_has_bits(wanted_type->data.error.child_type)) {
+ return expr_val;
+ } else {
+ zig_panic("TODO");
+ }
+ case CastOpPtrToInt:
+ return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
+ case CastOpIntToPtr:
+ return LLVMBuildIntToPtr(g->builder, expr_val, wanted_type->type_ref, "");
+ case CastOpPointerReinterpret:
+ return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
+ case CastOpWidenOrShorten:
+ return gen_widen_or_shorten(g, cast_instruction->base.source_node, actual_type, wanted_type, expr_val);
+ case CastOpToUnknownSizeArray:
+ {
+ assert(cast_instruction->tmp_ptr);
+ assert(wanted_type->id == TypeTableEntryIdStruct);
+ assert(wanted_type->data.structure.is_slice);
+
+ TypeTableEntry *pointer_type = wanted_type->data.structure.fields[0].type_entry;
+
+
+ size_t ptr_index = wanted_type->data.structure.fields[0].gen_index;
+ if (ptr_index != SIZE_MAX) {
+ LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, ptr_index, "");
+ LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, "");
+ LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr);
+ }
+
+ size_t len_index = wanted_type->data.structure.fields[1].gen_index;
+ LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, len_index, "");
+ LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
+ actual_type->data.array.len, false);
+ LLVMBuildStore(g->builder, len_val, len_ptr);
+
+ return cast_instruction->tmp_ptr;
+ }
+ case CastOpResizeSlice:
+ {
+ assert(cast_instruction->tmp_ptr);
+ assert(wanted_type->id == TypeTableEntryIdStruct);
+ assert(wanted_type->data.structure.is_slice);
+ assert(actual_type->id == TypeTableEntryIdStruct);
+ assert(actual_type->data.structure.is_slice);
+
+ TypeTableEntry *actual_pointer_type = actual_type->data.structure.fields[0].type_entry;
+ TypeTableEntry *actual_child_type = actual_pointer_type->data.pointer.child_type;
+ TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
+ TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
+
+
+ size_t actual_ptr_index = actual_type->data.structure.fields[0].gen_index;
+ size_t actual_len_index = actual_type->data.structure.fields[1].gen_index;
+ size_t wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
+ size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
+
+ LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_ptr_index, "");
+ LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, "");
+ LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr,
+ wanted_type->data.structure.fields[0].type_entry->type_ref, "");
+ LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
+ wanted_ptr_index, "");
+ LLVMBuildStore(g->builder, src_ptr_casted, dest_ptr_ptr);
+
+ LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_len_index, "");
+ LLVMValueRef src_len = LLVMBuildLoad(g->builder, src_len_ptr, "");
+ uint64_t src_size = type_size(g, actual_child_type);
+ uint64_t dest_size = type_size(g, wanted_child_type);
+
+ LLVMValueRef new_len;
+ if (dest_size == 1) {
+ LLVMValueRef src_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, src_size, false);
+ new_len = LLVMBuildMul(g->builder, src_len, src_size_val, "");
+ } else if (src_size == 1) {
+ LLVMValueRef dest_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, dest_size, false);
+ if (ir_want_debug_safety(g, &cast_instruction->base)) {
+ LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, "");
+ LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
+ LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenFail");
+ LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_debug_safety_crash(g);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ }
+ new_len = ZigLLVMBuildExactUDiv(g->builder, src_len, dest_size_val, "");
+ } else {
+ zig_unreachable();
+ }
+
+ LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
+ wanted_len_index, "");
+ LLVMBuildStore(g->builder, new_len, dest_len_ptr);
+
+
+ return cast_instruction->tmp_ptr;
+ }
+ case CastOpBytesToSlice:
+ {
+ assert(cast_instruction->tmp_ptr);
+ assert(wanted_type->id == TypeTableEntryIdStruct);
+ assert(wanted_type->data.structure.is_slice);
+ assert(actual_type->id == TypeTableEntryIdArray);
+
+ TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
+ TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
+
+
+ size_t wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
+ LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, wanted_ptr_index, "");
+ LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, "");
+ LLVMBuildStore(g->builder, src_ptr_casted, dest_ptr_ptr);
+
+ size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
+ LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, wanted_len_index, "");
+ LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
+ actual_type->data.array.len / type_size(g, wanted_child_type), false);
+ LLVMBuildStore(g->builder, len_val, len_ptr);
+
+ return cast_instruction->tmp_ptr;
+ }
+ case CastOpIntToFloat:
+ assert(actual_type->id == TypeTableEntryIdInt);
+ if (actual_type->data.integral.is_signed) {
+ return LLVMBuildSIToFP(g->builder, expr_val, wanted_type->type_ref, "");
+ } else {
+ return LLVMBuildUIToFP(g->builder, expr_val, wanted_type->type_ref, "");
+ }
+ case CastOpFloatToInt:
+ assert(wanted_type->id == TypeTableEntryIdInt);
+ if (wanted_type->data.integral.is_signed) {
+ return LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
+ } else {
+ return LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
+ }
+
+ case CastOpBoolToInt:
+ assert(wanted_type->id == TypeTableEntryIdInt);
+ assert(actual_type->id == TypeTableEntryIdBool);
+ return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
+
+ case CastOpIntToEnum:
+ return gen_widen_or_shorten(g, cast_instruction->base.source_node,
+ actual_type, wanted_type->data.enumeration.tag_type, expr_val);
+ case CastOpEnumToInt:
+ return gen_widen_or_shorten(g, cast_instruction->base.source_node,
+ actual_type->data.enumeration.tag_type, wanted_type, expr_val);
+ }
+ zig_unreachable();
+}
+
static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
set_debug_source_node(g, instruction->source_node);
switch (instruction->id) {
@@ -2907,13 +2805,14 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_load_var(g, executable, (IrInstructionLoadVar *)instruction);
case IrInstructionIdBinOp:
return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction);
+ case IrInstructionIdCast:
+ return ir_render_cast(g, executable, (IrInstructionCast *)instruction);
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdStoreVar:
case IrInstructionIdCall:
case IrInstructionIdBuiltinCall:
- case IrInstructionIdCast:
zig_panic("TODO render more IR instructions to LLVM");
}
zig_unreachable();
@@ -3592,7 +3491,7 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
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, var_node, bitcasted_union_field_ptr,
+ LLVMValueRef handle_val = get_handle_value(g, bitcasted_union_field_ptr,
enum_field->type_entry);
gen_assign_raw(g, var_node, BinOpTypeAssign,
@@ -3602,8 +3501,7 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
// variable is the payload
LLVMValueRef err_payload_ptr = LLVMBuildStructGEP(g->builder,
target_value_handle, 1, "");
- LLVMValueRef handle_val = get_handle_value(g, var_node,
- err_payload_ptr, prong_var->type);
+ 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 {
@@ -4375,10 +4273,8 @@ static void do_code_gen(CodeGen *g) {
// allocate structs which are the result of casts
for (size_t cea_i = 0; cea_i < fn_table_entry->cast_alloca_list.length; cea_i += 1) {
- AstNode *fn_call_node = fn_table_entry->cast_alloca_list.at(cea_i);
- Expr *expr = &fn_call_node->data.fn_call_expr.resolved_expr;
- fn_call_node->data.fn_call_expr.tmp_ptr = LLVMBuildAlloca(g->builder,
- expr->type_entry->type_ref, "");
+ IrInstructionCast *cast_instruction = fn_table_entry->cast_alloca_list.at(cea_i);
+ cast_instruction->tmp_ptr = LLVMBuildAlloca(g->builder, cast_instruction->base.type_entry->type_ref, "");
}
// allocate structs which are struct value expressions
src/eval.cpp
@@ -773,6 +773,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
case CastOpEnumToInt:
bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag);
const_val->ok = true;
+ break;
}
}
src/ir.cpp
@@ -1,6 +1,7 @@
#include "analyze.hpp"
-#include "ir.hpp"
#include "error.hpp"
+#include "eval.hpp"
+#include "ir.hpp"
struct IrVarSlot {
ConstExprValue value;
@@ -100,12 +101,12 @@ static T *ir_build_instruction(IrBuilder *irb, AstNode *source_node) {
}
static IrInstruction *ir_build_cast(IrBuilder *irb, AstNode *source_node, IrInstruction *dest_type,
- IrInstruction *value, bool is_implicit)
+ IrInstruction *value, CastOp cast_op)
{
IrInstructionCast *cast_instruction = ir_build_instruction<IrInstructionCast>(irb, source_node);
cast_instruction->dest_type = dest_type;
cast_instruction->value = value;
- cast_instruction->is_implicit = is_implicit;
+ cast_instruction->cast_op = cast_op;
return &cast_instruction->base;
}
@@ -117,6 +118,13 @@ static IrInstruction *ir_build_return(IrBuilder *irb, AstNode *source_node, IrIn
return &return_instruction->base;
}
+static IrInstruction *ir_build_const(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
+ IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
+ const_instruction->base.type_entry = type_entry;
+ const_instruction->base.static_value.ok = true;
+ return &const_instruction->base;
+}
+
static IrInstruction *ir_build_const_void(IrBuilder *irb, AstNode *source_node) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
const_instruction->base.type_entry = irb->codegen->builtin_types.entry_void;
@@ -133,14 +141,20 @@ static IrInstruction *ir_build_const_bignum(IrBuilder *irb, AstNode *source_node
return &const_instruction->base;
}
-static IrInstruction *ir_build_const_type(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
- IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
+static IrInstruction *ir_create_const_type(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
+ IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb->exec, source_node);
const_instruction->base.type_entry = irb->codegen->builtin_types.entry_type;
const_instruction->base.static_value.ok = true;
const_instruction->base.static_value.data.x_type = type_entry;
return &const_instruction->base;
}
+static IrInstruction *ir_build_const_type(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
+ IrInstruction *instruction = ir_create_const_type(irb, source_node, type_entry);
+ ir_instruction_append(irb->current_basic_block, instruction);
+ return instruction;
+}
+
static IrInstruction *ir_build_const_fn(IrBuilder *irb, AstNode *source_node, FnTableEntry *fn_entry) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
const_instruction->base.type_entry = fn_entry->type_entry;
@@ -174,6 +188,16 @@ static IrInstruction *ir_build_load_var(IrBuilder *irb, AstNode *source_node, Va
return &load_var_instruction->base;
}
+static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node,
+ IrInstruction *fn, size_t arg_count, IrInstruction **args)
+{
+ IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, source_node);
+ call_instruction->fn = fn;
+ call_instruction->arg_count = arg_count;
+ call_instruction->args = args;
+ return &call_instruction->base;
+}
+
//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
// size_t result = 0;
@@ -409,6 +433,26 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, bool pointer_
return irb->codegen->invalid_instruction;
}
+static IrInstruction *ir_gen_fn_call(IrBuilder *irb, AstNode *node) {
+ assert(node->type == NodeTypeFnCallExpr);
+
+ if (node->data.fn_call_expr.is_builtin) {
+ zig_panic("TODO ir gen builtin fn");
+ }
+
+ AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
+ IrInstruction *fn = ir_gen_node(irb, fn_ref_node, node->block_context);
+
+ size_t arg_count = node->data.fn_call_expr.params.length;
+ IrInstruction **args = allocate<IrInstruction*>(arg_count);
+ for (size_t i = 0; i < arg_count; i += 1) {
+ AstNode *arg_node = node->data.fn_call_expr.params.at(i);
+ args[i] = ir_gen_node(irb, arg_node, node->block_context);
+ }
+
+ return ir_build_call(irb, node, fn, arg_count, args);
+}
+
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
bool pointer_only)
{
@@ -423,12 +467,13 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
return ir_gen_num_lit(irb, node);
case NodeTypeSymbol:
return ir_gen_symbol(irb, node, pointer_only);
+ case NodeTypeFnCallExpr:
+ return ir_gen_fn_call(irb, node);
case NodeTypeUnwrapErrorExpr:
case NodeTypeReturnExpr:
case NodeTypeDefer:
case NodeTypeVariableDeclaration:
case NodeTypePrefixOpExpr:
- case NodeTypeFnCallExpr:
case NodeTypeArrayAccessExpr:
case NodeTypeSliceExpr:
case NodeTypeFieldAccessExpr:
@@ -782,6 +827,296 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, IrInstruction *pare
return ir_determine_peer_types(ira, parent_instruction, instructions, instruction_count);
}
+static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
+ IrInstruction *dest_type, CastOp cast_op, bool need_alloca)
+{
+ assert(dest_type->type_entry->id == TypeTableEntryIdMetaType);
+ assert(dest_type->static_value.ok);
+ TypeTableEntry *wanted_type = dest_type->static_value.data.x_type;
+
+ if (value->static_value.ok) {
+ IrInstruction *result = ir_build_const(&ira->new_irb, source_instr->source_node, wanted_type);
+ eval_const_expr_implicit_cast(cast_op, &value->static_value, value->type_entry,
+ &result->static_value, wanted_type);
+ return result;
+ } else {
+ IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->source_node,
+ dest_type->other, value->other, cast_op);
+ result->type_entry = wanted_type;
+ if (need_alloca && source_instr->source_node->block_context->fn_entry) {
+ IrInstructionCast *cast_instruction = (IrInstructionCast *)result;
+ source_instr->source_node->block_context->fn_entry->cast_alloca_list.append(cast_instruction);
+ }
+ return result;
+ }
+}
+
+static bool is_slice(TypeTableEntry *type) {
+ return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;
+}
+
+static bool is_u8(TypeTableEntry *type) {
+ return type->id == TypeTableEntryIdInt &&
+ !type->data.integral.is_signed && type->data.integral.bit_count == 8;
+}
+
+static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *dest_type, IrInstruction *value)
+{
+ assert(dest_type->type_entry->id == TypeTableEntryIdMetaType);
+ assert(dest_type->static_value.ok);
+
+ TypeTableEntry *wanted_type = dest_type->static_value.data.x_type;
+ TypeTableEntry *actual_type = value->type_entry;
+ TypeTableEntry *wanted_type_canon = get_underlying_type(wanted_type);
+ TypeTableEntry *actual_type_canon = get_underlying_type(actual_type);
+
+ TypeTableEntry *isize_type = ira->codegen->builtin_types.entry_isize;
+ TypeTableEntry *usize_type = ira->codegen->builtin_types.entry_usize;
+
+ if (wanted_type_canon->id == TypeTableEntryIdInvalid ||
+ actual_type_canon->id == TypeTableEntryIdInvalid)
+ {
+ return ira->codegen->invalid_instruction;
+ }
+
+ // explicit match or non-const to const
+ if (types_match_const_cast_only(wanted_type, actual_type)) {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpNoop, false);
+ }
+
+ // explicit cast from bool to int
+ if (wanted_type_canon->id == TypeTableEntryIdInt &&
+ actual_type_canon->id == TypeTableEntryIdBool)
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpBoolToInt, false);
+ }
+
+ // explicit cast from pointer to isize or usize
+ if ((wanted_type_canon == isize_type || wanted_type_canon == usize_type) &&
+ type_is_codegen_pointer(actual_type_canon))
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPtrToInt, false);
+ }
+
+
+ // explicit cast from isize or usize to pointer
+ if (wanted_type_canon->id == TypeTableEntryIdPointer &&
+ (actual_type_canon == isize_type || actual_type_canon == usize_type))
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToPtr, false);
+ }
+
+ // explicit widening or shortening cast
+ if ((wanted_type_canon->id == TypeTableEntryIdInt &&
+ actual_type_canon->id == TypeTableEntryIdInt) ||
+ (wanted_type_canon->id == TypeTableEntryIdFloat &&
+ actual_type_canon->id == TypeTableEntryIdFloat))
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpWidenOrShorten, false);
+ }
+
+ // explicit cast from int to float
+ if (wanted_type_canon->id == TypeTableEntryIdFloat &&
+ actual_type_canon->id == TypeTableEntryIdInt)
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToFloat, false);
+ }
+
+ // explicit cast from float to int
+ if (wanted_type_canon->id == TypeTableEntryIdInt &&
+ actual_type_canon->id == TypeTableEntryIdFloat)
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpFloatToInt, false);
+ }
+
+ // explicit cast from array to slice
+ if (is_slice(wanted_type) &&
+ actual_type->id == TypeTableEntryIdArray &&
+ types_match_const_cast_only(
+ wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type,
+ actual_type->data.array.child_type))
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpToUnknownSizeArray, true);
+ }
+
+ // explicit cast from []T to []u8 or []u8 to []T
+ if (is_slice(wanted_type) && is_slice(actual_type) &&
+ (is_u8(wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type) ||
+ is_u8(actual_type->data.structure.fields[0].type_entry->data.pointer.child_type)) &&
+ (wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
+ !actual_type->data.structure.fields[0].type_entry->data.pointer.is_const))
+ {
+ mark_impure_fn(ira->codegen, source_instr->source_node->block_context, source_instr->source_node);
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpResizeSlice, true);
+ }
+
+ // explicit cast from [N]u8 to []T
+ if (is_slice(wanted_type) &&
+ actual_type->id == TypeTableEntryIdArray &&
+ is_u8(actual_type->data.array.child_type))
+ {
+ mark_impure_fn(ira->codegen, source_instr->source_node->block_context, source_instr->source_node);
+ uint64_t child_type_size = type_size(ira->codegen,
+ wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type);
+ if (actual_type->data.array.len % child_type_size == 0) {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpBytesToSlice, true);
+ } else {
+ add_node_error(ira->codegen, source_instr->source_node,
+ buf_sprintf("unable to convert %s to %s: size mismatch",
+ buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+ }
+
+ // explicit cast from pointer to another pointer
+ if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
+ (wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPointerReinterpret, false);
+ }
+
+ // explicit cast from maybe pointer to another maybe pointer
+ if (actual_type->id == TypeTableEntryIdMaybe &&
+ (actual_type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
+ actual_type->data.maybe.child_type->id == TypeTableEntryIdFn) &&
+ wanted_type->id == TypeTableEntryIdMaybe &&
+ (wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
+ wanted_type->data.maybe.child_type->id == TypeTableEntryIdFn))
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPointerReinterpret, false);
+ }
+
+ // explicit cast from child type of maybe type to maybe type
+ if (wanted_type->id == TypeTableEntryIdMaybe) {
+ if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) {
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ CastOpMaybeWrap, true);
+ cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull;
+ return cast_instruction;
+ } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
+ actual_type->id == TypeTableEntryIdNumLitFloat)
+ {
+ if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type)) {
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ CastOpMaybeWrap, true);
+ cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull;
+ return cast_instruction;
+ } else {
+ return ira->codegen->invalid_instruction;
+ }
+ }
+ }
+
+ // explicit cast from null literal to maybe type
+ if (wanted_type->id == TypeTableEntryIdMaybe &&
+ actual_type->id == TypeTableEntryIdNullLit)
+ {
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ CastOpNullToMaybe, true);
+ cast_instruction->return_knowledge = ReturnKnowledgeKnownNull;
+ return cast_instruction;
+ }
+
+ // explicit cast from child type of error type to error type
+ if (wanted_type->id == TypeTableEntryIdErrorUnion) {
+ if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ CastOpErrorWrap, true);
+ cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError;
+ return cast_instruction;
+ } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
+ actual_type->id == TypeTableEntryIdNumLitFloat)
+ {
+ if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type)) {
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ CastOpErrorWrap, true);
+ cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError;
+ return cast_instruction;
+ } else {
+ return ira->codegen->invalid_instruction;
+ }
+ }
+ }
+
+ // explicit cast from pure error to error union type
+ if (wanted_type->id == TypeTableEntryIdErrorUnion &&
+ actual_type->id == TypeTableEntryIdPureError)
+ {
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ CastOpPureErrorWrap, false);
+ cast_instruction->return_knowledge = ReturnKnowledgeKnownError;
+ return cast_instruction;
+ }
+
+ // explicit cast from number literal to another type
+ if (actual_type->id == TypeTableEntryIdNumLitFloat ||
+ actual_type->id == TypeTableEntryIdNumLitInt)
+ {
+ if (ir_num_lit_fits_in_other_type(ira, value, wanted_type_canon)) {
+ CastOp op;
+ if ((actual_type->id == TypeTableEntryIdNumLitFloat &&
+ wanted_type_canon->id == TypeTableEntryIdFloat) ||
+ (actual_type->id == TypeTableEntryIdNumLitInt &&
+ wanted_type_canon->id == TypeTableEntryIdInt))
+ {
+ op = CastOpNoop;
+ } else if (wanted_type_canon->id == TypeTableEntryIdInt) {
+ op = CastOpFloatToInt;
+ } else if (wanted_type_canon->id == TypeTableEntryIdFloat) {
+ op = CastOpIntToFloat;
+ } else {
+ zig_unreachable();
+ }
+ return ir_resolve_cast(ira, source_instr, value, dest_type, op, false);
+ } else {
+ return ira->codegen->invalid_instruction;
+ }
+ }
+
+ // explicit cast from %void to integer type which can fit it
+ bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
+ !type_has_bits(actual_type->data.error.child_type);
+ bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError;
+ if ((actual_type_is_void_err || actual_type_is_pure_err) &&
+ wanted_type->id == TypeTableEntryIdInt)
+ {
+ BigNum bn;
+ bignum_init_unsigned(&bn, ira->codegen->error_decls.length);
+ if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count,
+ wanted_type->data.integral.is_signed))
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpErrToInt, false);
+ } else {
+ add_node_error(ira->codegen, source_instr->source_node,
+ buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+ }
+
+ // explicit cast from integer to enum type with no payload
+ if (actual_type->id == TypeTableEntryIdInt &&
+ wanted_type->id == TypeTableEntryIdEnum &&
+ wanted_type->data.enumeration.gen_field_count == 0)
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToEnum, false);
+ }
+
+ // explicit cast from enum type with no payload to integer
+ if (wanted_type->id == TypeTableEntryIdInt &&
+ actual_type->id == TypeTableEntryIdEnum &&
+ actual_type->data.enumeration.gen_field_count == 0)
+ {
+ return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpEnumToInt, false);
+ }
+
+ add_node_error(ira->codegen, source_instr->source_node,
+ buf_sprintf("invalid cast from type '%s' to '%s'",
+ buf_ptr(&actual_type->name),
+ buf_ptr(&wanted_type->name)));
+ return ira->codegen->invalid_instruction;
+}
+
static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type) {
assert(value);
assert(value != ira->old_irb.codegen->invalid_instruction);
@@ -806,10 +1141,8 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,
case ImplicitCastMatchResultYes:
{
- IrInstruction *dest_type = ir_build_const_type(&ira->new_irb, value->source_node, expected_type);
- bool is_implicit = true;
- IrInstruction *cast_instruction = ir_build_cast(&ira->new_irb, value->source_node, dest_type,
- value, is_implicit);
+ IrInstruction *dest_type = ir_create_const_type(&ira->new_irb, value->source_node, expected_type);
+ IrInstruction *cast_instruction = ir_analyze_cast(ira, value, dest_type, value);
return cast_instruction;
}
case ImplicitCastMatchResultReportedError:
@@ -849,18 +1182,41 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
IrInstruction *op1 = bin_op_instruction->op1;
IrInstruction *op2 = bin_op_instruction->op2;
- IrInstruction *casted_op1 = ir_get_casted_value(ira, op1->other, ira->old_irb.codegen->builtin_types.entry_bool);
+ TypeTableEntry *bool_type = ira->old_irb.codegen->builtin_types.entry_bool;
+
+ IrInstruction *casted_op1 = ir_get_casted_value(ira, op1->other, bool_type);
if (casted_op1 == ira->old_irb.codegen->invalid_instruction)
return ira->old_irb.codegen->builtin_types.entry_invalid;
- IrInstruction *casted_op2 = ir_get_casted_value(ira, op2->other, ira->old_irb.codegen->builtin_types.entry_bool);
+ IrInstruction *casted_op2 = ir_get_casted_value(ira, op2->other, bool_type);
if (casted_op2 == ira->old_irb.codegen->invalid_instruction)
return ira->old_irb.codegen->builtin_types.entry_invalid;
+ ConstExprValue *op1_val = &casted_op1->static_value;
+ ConstExprValue *op2_val = &casted_op2->static_value;
+ if (op1_val->ok && op2_val->ok) {
+ ConstExprValue *out_val = &bin_op_instruction->base.static_value;
+ bin_op_instruction->base.other = &bin_op_instruction->base;
+
+ assert(op1->type_entry->id == TypeTableEntryIdBool);
+ assert(op2->type_entry->id == TypeTableEntryIdBool);
+ if (bin_op_instruction->op_id == IrBinOpBoolOr) {
+ out_val->data.x_bool = op1_val->data.x_bool || op2_val->data.x_bool;
+ } else if (bin_op_instruction->op_id == IrBinOpBoolAnd) {
+ out_val->data.x_bool = op1_val->data.x_bool && op2_val->data.x_bool;
+ } else {
+ zig_unreachable();
+ }
+ out_val->ok = true;
+ out_val->depends_on_compile_var = op1_val->depends_on_compile_var ||
+ op2_val->depends_on_compile_var;
+ return bool_type;
+ }
+
ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
bin_op_instruction->op_id, op1->other, op2->other), &bin_op_instruction->base);
- return ira->old_irb.codegen->builtin_types.entry_bool;
+ return bool_type;
}
static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
@@ -925,12 +1281,109 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
zig_unreachable();
}
+ zig_panic("TODO interpret bin_op_cmp");
+
ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
op_id, op1->other, op2->other), &bin_op_instruction->base);
return ira->old_irb.codegen->builtin_types.entry_bool;
}
+static uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
+ assert(type_entry->id == TypeTableEntryIdInt);
+ if (type_entry->data.integral.bit_count == 64) {
+ return UINT64_MAX;
+ } else if (type_entry->data.integral.bit_count == 32) {
+ return UINT32_MAX;
+ } else if (type_entry->data.integral.bit_count == 16) {
+ return UINT16_MAX;
+ } else if (type_entry->data.integral.bit_count == 8) {
+ return UINT8_MAX;
+ } else {
+ zig_unreachable();
+ }
+}
+
+static int ir_eval_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
+ ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *),
+ TypeTableEntry *type, bool wrapping_op)
+{
+ bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
+ if (overflow) {
+ return ErrorOverflow;
+ }
+
+ if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum,
+ type->data.integral.bit_count, type->data.integral.is_signed))
+ {
+ if (wrapping_op) {
+ if (type->data.integral.is_signed) {
+ out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
+ out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative;
+ } else if (out_val->data.x_bignum.is_negative) {
+ out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
+ out_val->data.x_bignum.is_negative = false;
+ } else {
+ bignum_truncate(&out_val->data.x_bignum, type->data.integral.bit_count);
+ }
+ } else {
+ return ErrorOverflow;
+ }
+ }
+
+ out_val->ok = true;
+ out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
+ return 0;
+}
+
+static int ir_eval_math_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
+ IrBinOp op_id, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val)
+{
+ switch (op_id) {
+ case IrBinOpInvalid:
+ case IrBinOpBoolOr:
+ case IrBinOpBoolAnd:
+ case IrBinOpCmpEq:
+ case IrBinOpCmpNotEq:
+ case IrBinOpCmpLessThan:
+ case IrBinOpCmpGreaterThan:
+ case IrBinOpCmpLessOrEq:
+ case IrBinOpCmpGreaterOrEq:
+ case IrBinOpArrayCat:
+ case IrBinOpArrayMult:
+ zig_unreachable();
+ case IrBinOpBinOr:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_or, op1_type, false);
+ case IrBinOpBinXor:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type, false);
+ case IrBinOpBinAnd:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_and, op1_type, false);
+ case IrBinOpBitShiftLeft:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, false);
+ case IrBinOpBitShiftLeftWrap:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, true);
+ case IrBinOpBitShiftRight:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type, false);
+ case IrBinOpAdd:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, false);
+ case IrBinOpAddWrap:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, true);
+ case IrBinOpSub:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, false);
+ case IrBinOpSubWrap:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, true);
+ case IrBinOpMult:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, false);
+ case IrBinOpMultWrap:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, true);
+ case IrBinOpDiv:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_div, op1_type, false);
+ case IrBinOpMod:
+ return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type, false);
+ }
+ zig_unreachable();
+}
+
static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
IrInstruction *op1 = bin_op_instruction->op1;
IrInstruction *op2 = bin_op_instruction->op2;
@@ -955,12 +1408,39 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
// float
} else {
AstNode *source_node = bin_op_instruction->base.source_node;
- add_node_error(ira->old_irb.codegen, source_node, buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
+ add_node_error(ira->old_irb.codegen, source_node,
+ buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
buf_ptr(&op1->type_entry->name),
buf_ptr(&op2->type_entry->name)));
return ira->old_irb.codegen->builtin_types.entry_invalid;
}
+ if (op1->static_value.ok && op2->static_value.ok) {
+ ConstExprValue *op1_val = &op1->static_value;
+ ConstExprValue *op2_val = &op2->static_value;
+ ConstExprValue *out_val = &bin_op_instruction->base.static_value;
+
+ bin_op_instruction->base.other = &bin_op_instruction->base;
+
+ int err;
+ if ((err = ir_eval_math_op(op1_val, resolved_type, op_id, op2_val, resolved_type, out_val))) {
+ if (err == ErrorDivByZero) {
+ add_node_error(ira->codegen, bin_op_instruction->base.source_node,
+ buf_sprintf("division by zero is undefined"));
+ return ira->codegen->builtin_types.entry_invalid;
+ } else if (err == ErrorOverflow) {
+ add_node_error(ira->codegen, bin_op_instruction->base.source_node,
+ buf_sprintf("value cannot be represented in any integer type"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ ir_num_lit_fits_in_other_type(ira, &bin_op_instruction->base, resolved_type);
+ return resolved_type;
+
+ }
+
ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
op_id, op1->other, op2->other), &bin_op_instruction->base);
@@ -1011,6 +1491,40 @@ static TypeTableEntry *ir_analyze_instruction_load_var(IrAnalyze *ira, IrInstruc
return load_var_instruction->var->type;
}
+static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) {
+ IrInstruction *fn_ref = call_instruction->fn->other;
+ if (fn_ref->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (fn_ref->static_value.ok) {
+ if (fn_ref->type_entry->id == TypeTableEntryIdMetaType) {
+ size_t actual_param_count = call_instruction->arg_count;
+
+ if (actual_param_count != 1) {
+ add_node_error(ira->codegen, call_instruction->base.source_node,
+ buf_sprintf("cast expression expects exactly one parameter"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ IrInstruction *arg = call_instruction->args[0];
+ IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, fn_ref, arg);
+ if (cast_instruction == ira->codegen->invalid_instruction)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ ir_link_new(cast_instruction, &call_instruction->base);
+ return cast_instruction->type_entry;
+ } else {
+ zig_panic("TODO analyze more fn call types");
+ }
+ } else {
+ //ir_link_new(ir_build_call(&ira->new_irb, call_instruction->base.source_node,
+ // call_instruction->fn, call_instruction->arg_count, call_instruction->args),
+ // &call_instruction->base);
+
+ zig_panic("TODO analyze fn call");
+ }
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -1023,11 +1537,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction);
case IrInstructionIdLoadVar:
return ir_analyze_instruction_load_var(ira, (IrInstructionLoadVar *)instruction);
+ case IrInstructionIdCall:
+ return ir_analyze_instruction_call(ira, (IrInstructionCall *)instruction);
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdStoreVar:
- case IrInstructionIdCall:
case IrInstructionIdBuiltinCall:
case IrInstructionIdCast:
zig_panic("TODO analyze more instructions");
src/ir_print.cpp
@@ -20,7 +20,7 @@ static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) {
static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) {
ir_print_prefix(irp, &return_instruction->base);
assert(return_instruction->value);
- fprintf(irp->f, "return #%zu;\n", return_instruction->value->debug_id);
+ fprintf(irp->f, "return #%zu\n", return_instruction->value->debug_id);
}
static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
@@ -43,8 +43,10 @@ static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction)
fprintf(irp->f, "%s%llu\n", negative_str, bignum->data.x_uint);
break;
}
- case TypeTableEntryIdVar:
case TypeTableEntryIdMetaType:
+ fprintf(irp->f, "%s\n", buf_ptr(&const_instruction->base.static_value.data.x_type->name));
+ break;
+ case TypeTableEntryIdVar:
case TypeTableEntryIdBool:
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdInt:
@@ -139,6 +141,25 @@ static void ir_print_load_var(IrPrint *irp, IrInstructionLoadVar *load_var_instr
buf_ptr(&load_var_instruction->var->name));
}
+static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
+ ir_print_prefix(irp, &cast_instruction->base);
+ fprintf(irp->f, "cast #%zu to #%zu\n",
+ cast_instruction->value->debug_id,
+ cast_instruction->dest_type->debug_id);
+}
+
+static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
+ ir_print_prefix(irp, &call_instruction->base);
+ fprintf(irp->f, "#%zu(", call_instruction->fn->debug_id);
+ for (size_t i = 0; i < call_instruction->arg_count; i += 1) {
+ IrInstruction *arg = call_instruction->args[i];
+ if (i != 0)
+ fprintf(irp->f, ", ");
+ fprintf(irp->f, "#%zu", arg->debug_id);
+ }
+ fprintf(irp->f, ")\n");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -155,13 +176,17 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdLoadVar:
ir_print_load_var(irp, (IrInstructionLoadVar *)instruction);
break;
+ case IrInstructionIdCast:
+ ir_print_cast(irp, (IrInstructionCast *)instruction);
+ break;
+ case IrInstructionIdCall:
+ ir_print_call(irp, (IrInstructionCall *)instruction);
+ break;
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdStoreVar:
- case IrInstructionIdCall:
case IrInstructionIdBuiltinCall:
- case IrInstructionIdCast:
zig_panic("TODO print more IR instructions");
}
}