From 1bf72c693b50cc050021a858511b302f560d3c2a Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 18 Oct 2018 19:32:44 -0400
Subject: [PATCH 001/190] copy elision using the ir system
---
doc/langref.html.in | 11 +-
src/all_types.hpp | 147 +++--
src/codegen.cpp | 216 +++-----
src/ir.cpp | 1274 +++++++++++++++++++++++--------------------
src/ir_print.cpp | 107 +++-
5 files changed, 967 insertions(+), 788 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 0a5ff19389b7..51d90911f869 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -5855,13 +5855,13 @@ fn add(a: i32, b: i32) i32 { return a + b; }
This function is a low level intrinsic with no safety mechanisms. Most code
should not use this function, instead using something like this:
- {#syntax#}for (source[0...byte_count]) |b, i| dest[i] = b;{#endsyntax#}
+ {#syntax#}for (source[0..byte_count]) |b, i| dest[i] = b;{#endsyntax#}
The optimizer is intelligent enough to turn the above snippet into a memcpy.
There is also a standard library function for this:
{#syntax#}const mem = @import("std").mem;
-mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
+mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}
{#header_close#}
{#header_open|@memset#}
{#syntax#}@memset(dest: [*]u8, c: u8, byte_count: usize){#endsyntax#}
@@ -5872,7 +5872,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
This function is a low level intrinsic with no safety mechanisms. Most
code should not use this function, instead using something like this:
- {#syntax#}for (dest[0...byte_count]) |*b| b.* = c;{#endsyntax#}
+ {#syntax#}for (dest[0..byte_count]) |*b| b.* = c;{#endsyntax#}
The optimizer is intelligent enough to turn the above snippet into a memset.
@@ -6514,9 +6514,10 @@ pub const TypeInfo = union(TypeId).{
{#code_end#}
{#header_close#}
{#header_open|@typeName#}
- {#syntax#}@typeName(T: type) []u8{#endsyntax#}
+ {#syntax#}@typeName(T: type) [N]u8{#endsyntax#}
- This function returns the string representation of a type.
+ This function returns the string representation of a type, as
+ an array. It is equivalent to a string literal of the type name.
{#header_close#}
diff --git a/src/all_types.hpp b/src/all_types.hpp
index c490999a2bb6..c05c48f95f51 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -33,7 +33,7 @@ struct TypeStructField;
struct CodeGen;
struct ConstExprValue;
struct IrInstruction;
-struct IrInstructionCast;
+struct IrInstructionAlloca;
struct IrBasicBlock;
struct ScopeDecls;
struct ZigWindowsSDK;
@@ -68,6 +68,8 @@ struct IrExecutable {
Scope *begin_scope;
ZigList tld_list;
+ IrInstruction *return_result_loc;
+
IrInstruction *coro_handle;
IrInstruction *atomic_state_field_ptr; // this one is shared and in the promise
IrInstruction *coro_result_ptr_field_ptr;
@@ -1320,7 +1322,7 @@ struct ZigFn {
AstNode *fn_no_inline_set_node;
AstNode *fn_static_eval_set_node;
- ZigList alloca_list;
+ ZigList alloca_list;
ZigList variable_list;
Buf *section_name;
@@ -1885,6 +1887,7 @@ struct ScopeBlock {
Buf *name;
IrBasicBlock *end_block;
IrInstruction *is_comptime;
+ IrInstruction *result_loc;
ZigList *incoming_values;
ZigList *incoming_blocks;
@@ -1937,6 +1940,7 @@ struct ScopeLoop {
IrBasicBlock *break_block;
IrBasicBlock *continue_block;
IrInstruction *is_comptime;
+ IrInstruction *result_loc;
ZigList *incoming_values;
ZigList *incoming_blocks;
};
@@ -2029,6 +2033,8 @@ struct IrBasicBlock {
enum IrInstructionId {
IrInstructionIdInvalid,
+ IrInstructionIdDeclVarSrc,
+ IrInstructionIdDeclVarGen,
IrInstructionIdBr,
IrInstructionIdCondBr,
IrInstructionIdSwitchBr,
@@ -2037,7 +2043,6 @@ enum IrInstructionId {
IrInstructionIdPhi,
IrInstructionIdUnOp,
IrInstructionIdBinOp,
- IrInstructionIdDeclVar,
IrInstructionIdLoadPtr,
IrInstructionIdStorePtr,
IrInstructionIdFieldPtr,
@@ -2166,9 +2171,16 @@ enum IrInstructionId {
IrInstructionIdMarkErrRetTracePtr,
IrInstructionIdSqrt,
IrInstructionIdErrSetCast,
- IrInstructionIdToBytes,
- IrInstructionIdFromBytes,
IrInstructionIdCheckRuntimeScope,
+ IrInstructionIdResultErrorUnionPayload,
+ IrInstructionIdResultReturn,
+ IrInstructionIdResultBytesToSlice,
+ IrInstructionIdResultSliceToBytes,
+ IrInstructionIdResultParam,
+ IrInstructionIdResultPtrCast,
+ IrInstructionIdLoadResult,
+ IrInstructionIdStoreResult,
+ IrInstructionIdAlloca,
};
struct IrInstruction {
@@ -2190,6 +2202,21 @@ struct IrInstruction {
bool is_gen;
};
+struct IrInstructionDeclVarSrc {
+ IrInstruction base;
+
+ ZigVar *var;
+ IrInstruction *var_type;
+ IrInstruction *align_value;
+ IrInstruction *ptr;
+};
+
+struct IrInstructionDeclVarGen {
+ IrInstruction base;
+
+ ZigVar *var;
+};
+
struct IrInstructionCondBr {
IrInstruction base;
@@ -2303,25 +2330,30 @@ struct IrInstructionBinOp {
bool safety_check_on;
};
-struct IrInstructionDeclVar {
+struct IrInstructionLoadPtr {
IrInstruction base;
- ZigVar *var;
- IrInstruction *var_type;
- IrInstruction *align_value;
- IrInstruction *init_value;
+ IrInstruction *ptr;
};
-struct IrInstructionLoadPtr {
+struct IrInstructionStorePtr {
IrInstruction base;
IrInstruction *ptr;
+ IrInstruction *value;
};
-struct IrInstructionStorePtr {
+struct IrInstructionLoadResult {
IrInstruction base;
IrInstruction *ptr;
+ IrInstruction *result_loc;
+};
+
+struct IrInstructionStoreResult {
+ IrInstruction base;
+
+ IrInstruction *result_loc;
IrInstruction *value;
};
@@ -2374,13 +2406,12 @@ struct IrInstructionCall {
ZigFn *fn_entry;
size_t arg_count;
IrInstruction **args;
- bool is_comptime;
- LLVMValueRef tmp_ptr;
- FnInline fn_inline;
- bool is_async;
-
IrInstruction *async_allocator;
IrInstruction *new_stack;
+ IrInstruction *result_loc;
+ FnInline fn_inline;
+ bool is_async;
+ bool is_comptime;
};
struct IrInstructionConst {
@@ -2401,23 +2432,24 @@ struct IrInstructionCast {
IrInstruction base;
IrInstruction *value;
+ IrInstruction *result_loc;
ZigType *dest_type;
CastOp cast_op;
- LLVMValueRef tmp_ptr;
};
struct IrInstructionContainerInitList {
IrInstruction base;
IrInstruction *container_type;
+ IrInstruction *result_loc;
size_t item_count;
IrInstruction **items;
- LLVMValueRef tmp_ptr;
};
struct IrInstructionContainerInitFieldsField {
Buf *name;
IrInstruction *value;
+ IrInstruction *result_loc;
AstNode *source_node;
TypeStructField *type_struct_field;
};
@@ -2439,9 +2471,9 @@ struct IrInstructionStructInit {
IrInstruction base;
ZigType *struct_type;
+ IrInstruction *result_loc;
size_t field_count;
IrInstructionStructInitField *fields;
- LLVMValueRef tmp_ptr;
};
struct IrInstructionUnionInit {
@@ -2450,7 +2482,7 @@ struct IrInstructionUnionInit {
ZigType *union_type;
TypeUnionField *field;
IrInstruction *init_value;
- LLVMValueRef tmp_ptr;
+ IrInstruction *result_loc;
};
struct IrInstructionUnreachable {
@@ -2523,9 +2555,9 @@ struct IrInstructionSliceType {
IrInstruction base;
IrInstruction *align_value;
+ IrInstruction *child_type;
bool is_const;
bool is_volatile;
- IrInstruction *child_type;
};
struct IrInstructionAsm {
@@ -2600,7 +2632,7 @@ struct IrInstructionRef {
IrInstruction base;
IrInstruction *value;
- LLVMValueRef tmp_ptr;
+ IrInstruction *result_loc;
bool is_const;
bool is_volatile;
};
@@ -2662,6 +2694,7 @@ struct IrInstructionCmpxchg {
IrInstruction *new_value;
IrInstruction *success_order_value;
IrInstruction *failure_order_value;
+ IrInstruction *result_loc;
// if this instruction gets to runtime then we know these values:
ZigType *type;
@@ -2669,8 +2702,6 @@ struct IrInstructionCmpxchg {
AtomicOrder failure_order;
bool is_weak;
-
- LLVMValueRef tmp_ptr;
};
struct IrInstructionFence {
@@ -2710,19 +2741,6 @@ struct IrInstructionErrSetCast {
IrInstruction *target;
};
-struct IrInstructionToBytes {
- IrInstruction base;
-
- IrInstruction *target;
-};
-
-struct IrInstructionFromBytes {
- IrInstruction base;
-
- IrInstruction *dest_child_type;
- IrInstruction *target;
-};
-
struct IrInstructionIntToFloat {
IrInstruction base;
@@ -2778,8 +2796,8 @@ struct IrInstructionSlice {
IrInstruction *ptr;
IrInstruction *start;
IrInstruction *end;
+ IrInstruction *result_loc;
bool safety_check_on;
- LLVMValueRef tmp_ptr;
};
struct IrInstructionMemberCount {
@@ -2867,21 +2885,21 @@ struct IrInstructionOptionalWrap {
IrInstruction base;
IrInstruction *value;
- LLVMValueRef tmp_ptr;
+ IrInstruction *result_loc;
};
struct IrInstructionErrWrapPayload {
IrInstruction base;
IrInstruction *value;
- LLVMValueRef tmp_ptr;
+ IrInstruction *result_loc;
};
struct IrInstructionErrWrapCode {
IrInstruction base;
IrInstruction *value;
- LLVMValueRef tmp_ptr;
+ IrInstruction *result_loc;
};
struct IrInstructionFnProto {
@@ -2983,6 +3001,7 @@ struct IrInstructionTypeName {
IrInstruction base;
IrInstruction *type_value;
+ IrInstruction *result_loc;
};
enum LVal {
@@ -3007,6 +3026,7 @@ struct IrInstructionTagName {
IrInstruction base;
IrInstruction *target;
+ IrInstruction *result_loc;
};
struct IrInstructionTagType {
@@ -3264,6 +3284,49 @@ struct IrInstructionCheckRuntimeScope {
IrInstruction *is_comptime;
};
+struct IrInstructionResultErrorUnionPayload {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionResultBytesToSlice {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionResultSliceToBytes {
+ IrInstruction base;
+
+ IrInstruction *elem_type;
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionResultReturn {
+ IrInstruction base;
+};
+
+struct IrInstructionResultParam {
+ IrInstruction base;
+
+ IrInstruction *fn_ref;
+ size_t param_index;
+};
+
+struct IrInstructionResultPtrCast {
+ IrInstruction base;
+
+ IrInstruction *elem_type;
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionAlloca {
+ IrInstruction base;
+
+ IrInstruction *ty;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 71de547353d6..e4df2de81572 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -2818,12 +2818,13 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
return expr_val;
case CastOpResizeSlice:
{
- assert(cast_instruction->tmp_ptr);
assert(wanted_type->id == ZigTypeIdStruct);
assert(wanted_type->data.structure.is_slice);
assert(actual_type->id == ZigTypeIdStruct);
assert(actual_type->data.structure.is_slice);
+ LLVMValueRef result_ptr = ir_llvm_value(g, cast_instruction->result_loc);
+
ZigType *actual_pointer_type = actual_type->data.structure.fields[0].type_entry;
ZigType *actual_child_type = actual_pointer_type->data.pointer.child_type;
ZigType *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
@@ -2839,7 +2840,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, "");
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,
+ LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
(unsigned)wanted_ptr_index, "");
gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false);
@@ -2872,38 +2873,39 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
zig_unreachable();
}
- LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
+ LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
(unsigned)wanted_len_index, "");
gen_store_untyped(g, new_len, dest_len_ptr, 0, false);
- return cast_instruction->tmp_ptr;
+ return result_ptr;
}
case CastOpBytesToSlice:
{
- assert(cast_instruction->tmp_ptr);
assert(wanted_type->id == ZigTypeIdStruct);
assert(wanted_type->data.structure.is_slice);
assert(actual_type->id == ZigTypeIdArray);
+ LLVMValueRef result_ptr = ir_llvm_value(g, cast_instruction->result_loc);
+
ZigType *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
ZigType *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,
+ LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
(unsigned)wanted_ptr_index, "");
LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, "");
gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false);
size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
- LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
+ LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
(unsigned)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);
gen_store_untyped(g, len_val, len_ptr, 0, false);
- return cast_instruction->tmp_ptr;
+ return result_ptr;
}
case CastOpIntToFloat:
assert(actual_type->id == ZigTypeIdInt);
@@ -2959,12 +2961,13 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
case CastOpBitCast:
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpPtrOfArrayToSlice: {
- assert(cast_instruction->tmp_ptr);
assert(actual_type->id == ZigTypeIdPointer);
ZigType *array_type = actual_type->data.pointer.child_type;
assert(array_type->id == ZigTypeIdArray);
- LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
+ LLVMValueRef result_ptr = ir_llvm_value(g, cast_instruction->result_loc);
+
+ LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
slice_ptr_index, "");
LLVMValueRef indices[] = {
LLVMConstNull(g->builtin_types.entry_usize->type_ref),
@@ -2973,13 +2976,12 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, "");
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
- LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
- slice_len_index, "");
+ LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, result_ptr, slice_len_index, "");
LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
array_type->data.array.len, false);
gen_store_untyped(g, len_value, len_field_ptr, 0, false);
- return cast_instruction->tmp_ptr;
+ return result_ptr;
}
}
zig_unreachable();
@@ -3174,7 +3176,7 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI
}
static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
- IrInstructionDeclVar *decl_var_instruction)
+ IrInstructionDeclVarGen *decl_var_instruction)
{
ZigVar *var = decl_var_instruction->var;
@@ -3184,38 +3186,6 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
if (var->ref_count == 0 && g->build_mode != BuildModeDebug)
return nullptr;
- IrInstruction *init_value = decl_var_instruction->init_value;
-
- bool have_init_expr = false;
-
- ConstExprValue *const_val = &init_value->value;
- if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic)
- have_init_expr = true;
-
- if (have_init_expr) {
- assert(var->value->type == init_value->value.type);
- ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false,
- PtrLenSingle, var->align_bytes, 0, 0);
- LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value);
- gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val);
- } else {
- bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base);
- if (want_safe) {
- ZigType *usize = g->builtin_types.entry_usize;
- uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref);
- assert(size_bytes > 0);
-
- assert(var->align_bytes > 0);
-
- // memset uninitialized memory to 0xa
- LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
- LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
- LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, var->value_ref, ptr_u8, "");
- LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
- ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, var->align_bytes, false);
- }
- }
-
gen_var_debug_decl(g, var);
return nullptr;
}
@@ -3444,8 +3414,13 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
bool is_var_args = fn_type_id->is_var_args;
ZigList gen_param_values = {};
+ LLVMValueRef result_ptr = nullptr;
+ if (first_arg_ret || instruction->is_async) {
+ result_ptr = ir_llvm_value(g, instruction->result_loc);
+ }
+
if (first_arg_ret) {
- gen_param_values.append(instruction->tmp_ptr);
+ gen_param_values.append(result_ptr);
}
if (prefix_arg_err_ret_stack) {
gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
@@ -3453,7 +3428,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
if (instruction->is_async) {
gen_param_values.append(ir_llvm_value(g, instruction->async_allocator));
- LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
+ LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, result_ptr, err_union_err_index, "");
gen_param_values.append(err_val_ptr);
}
FnWalk fn_walk = {};
@@ -3496,9 +3471,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
if (instruction->is_async) {
- LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
+ LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, result_ptr, err_union_payload_index, "");
LLVMBuildStore(g->builder, result, payload_ptr);
- return instruction->tmp_ptr;
+ return result_ptr;
}
if (src_return_type->id == ZigTypeIdUnreachable) {
@@ -3507,11 +3482,11 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
return nullptr;
} else if (first_arg_ret) {
set_call_instr_sret(g, result);
- return instruction->tmp_ptr;
+ return result_ptr;
} else if (handle_is_ptr(src_return_type)) {
- auto store_instr = LLVMBuildStore(g->builder, result, instruction->tmp_ptr);
- LLVMSetAlignment(store_instr, LLVMGetAlignment(instruction->tmp_ptr));
- return instruction->tmp_ptr;
+ auto store_instr = LLVMBuildStore(g->builder, result, result_ptr);
+ LLVMSetAlignment(store_instr, LLVMGetAlignment(result_ptr));
+ return result_ptr;
} else {
return result;
}
@@ -3883,9 +3858,9 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru
if (handle_is_ptr(instruction->value->value.type)) {
return value;
} else {
- assert(instruction->tmp_ptr);
- gen_store_untyped(g, value, instruction->tmp_ptr, 0, false);
- return instruction->tmp_ptr;
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
+ gen_store_untyped(g, value, result_ptr, 0, false);
+ return result_ptr;
}
}
@@ -4187,18 +4162,19 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, "");
}
- assert(instruction->tmp_ptr != nullptr);
assert(type_has_bits(instruction->type));
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
+
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
- LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
+ LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_ptr, maybe_child_index, "");
gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val);
LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, "");
- LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
+ LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, result_ptr, maybe_null_index, "");
gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false);
- return instruction->tmp_ptr;
+ return result_ptr;
}
static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) {
@@ -4261,15 +4237,13 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns
}
static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) {
- assert(instruction->tmp_ptr);
-
LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr);
ZigType *array_ptr_type = instruction->ptr->value.type;
assert(array_ptr_type->id == ZigTypeIdPointer);
ZigType *array_type = array_ptr_type->data.pointer.child_type;
LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
- LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
+ LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
@@ -4603,15 +4577,15 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
return payload_val;
}
- assert(instruction->tmp_ptr);
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
- LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
+ LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_ptr, maybe_child_index, "");
// child_type and instruction->value->value.type may differ by constness
gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val);
- LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
+ LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, result_ptr, maybe_null_index, "");
gen_store_untyped(g, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr, 0, false);
- return instruction->tmp_ptr;
+ return result_ptr;
}
static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapCode *instruction) {
@@ -4627,12 +4601,12 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable
if (!type_has_bits(payload_type) || !type_has_bits(err_set_type))
return err_val;
- assert(instruction->tmp_ptr);
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
- LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
+ LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, result_ptr, err_union_err_index, "");
gen_store_untyped(g, err_val, err_tag_ptr, 0, false);
- return instruction->tmp_ptr;
+ return result_ptr;
}
static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapPayload *instruction) {
@@ -4652,17 +4626,17 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
if (!type_has_bits(payload_type))
return ok_err_val;
- assert(instruction->tmp_ptr);
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
- LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
+ LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, result_ptr, err_union_err_index, "");
gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false);
- LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
+ LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, result_ptr, err_union_payload_index, "");
gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val);
- return instruction->tmp_ptr;
+ return result_ptr;
}
static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) {
@@ -4683,14 +4657,18 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir
return get_handle_value(g, tag_field_ptr, tag_type, ptr_type);
}
-static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) {
+static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
+ IrInstructionStructInit *instruction)
+{
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
+
for (size_t i = 0; i < instruction->field_count; i += 1) {
IrInstructionStructInitField *field = &instruction->fields[i];
TypeStructField *type_struct_field = field->type_struct_field;
if (!type_has_bits(type_struct_field->type_entry))
continue;
- LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
+ LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
(unsigned)type_struct_field->gen_index, "");
LLVMValueRef value = ir_llvm_value(g, field->value);
@@ -4703,7 +4681,7 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
gen_assign_raw(g, field_ptr, ptr_type, value);
}
- return instruction->tmp_ptr;
+ return result_ptr;
}
static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) {
@@ -4717,22 +4695,24 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
false, false, PtrLenSingle, field_align_bytes,
0, 0);
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
+
LLVMValueRef uncasted_union_ptr;
// Even if safety is off in this block, if the union type has the safety field, we have to populate it
// correctly. Otherwise safety code somewhere other than here could fail.
ZigType *union_type = instruction->union_type;
if (union_type->data.unionation.gen_tag_index != SIZE_MAX) {
- LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
+ LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
union_type->data.unionation.gen_tag_index, "");
LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
&type_union_field->enum_field->value);
gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
- uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
+ uncasted_union_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
(unsigned)union_type->data.unionation.gen_union_index, "");
} else {
- uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, "");
+ uncasted_union_ptr = LLVMBuildStructGEP(g->builder, result_ptr, (unsigned)0, "");
}
LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, ptr_type->type_ref, "");
@@ -4740,7 +4720,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
gen_assign_raw(g, field_ptr, ptr_type, value);
- return instruction->tmp_ptr;
+ return result_ptr;
}
static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable,
@@ -4748,7 +4728,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
{
ZigType *array_type = instruction->base.value.type;
assert(array_type->id == ZigTypeIdArray);
- LLVMValueRef tmp_array_ptr = instruction->tmp_ptr;
+ LLVMValueRef tmp_array_ptr = ir_llvm_value(g, instruction->result_loc);
assert(tmp_array_ptr);
size_t field_count = instruction->item_count;
@@ -5142,16 +5122,15 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdFloatToInt:
case IrInstructionIdBoolToInt:
case IrInstructionIdErrSetCast:
- case IrInstructionIdFromBytes:
- case IrInstructionIdToBytes:
case IrInstructionIdEnumToInt:
case IrInstructionIdCheckRuntimeScope:
+ case IrInstructionIdDeclVarSrc:
zig_unreachable();
+ case IrInstructionIdDeclVarGen:
+ return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction);
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
- case IrInstructionIdDeclVar:
- return ir_render_decl_var(g, executable, (IrInstructionDeclVar *)instruction);
case IrInstructionIdBinOp:
return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction);
case IrInstructionIdCast:
@@ -5308,6 +5287,24 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
case IrInstructionIdSqrt:
return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
+ case IrInstructionIdResultErrorUnionPayload:
+ zig_panic("TODO");
+ case IrInstructionIdResultReturn:
+ zig_panic("TODO");
+ case IrInstructionIdResultSliceToBytes:
+ zig_panic("TODO");
+ case IrInstructionIdResultBytesToSlice:
+ zig_panic("TODO");
+ case IrInstructionIdResultParam:
+ zig_panic("TODO");
+ case IrInstructionIdResultPtrCast:
+ zig_panic("TODO");
+ case IrInstructionIdLoadResult:
+ zig_panic("TODO");
+ case IrInstructionIdStoreResult:
+ zig_panic("TODO");
+ case IrInstructionIdAlloca:
+ zig_panic("TODO");
}
zig_unreachable();
}
@@ -6196,48 +6193,9 @@ static void do_code_gen(CodeGen *g) {
// allocate temporary stack data
for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
- IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
- LLVMValueRef *slot;
- ZigType *slot_type = instruction->value.type;
- if (instruction->id == IrInstructionIdCast) {
- IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction;
- slot = &cast_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdRef) {
- IrInstructionRef *ref_instruction = (IrInstructionRef *)instruction;
- slot = &ref_instruction->tmp_ptr;
- assert(instruction->value.type->id == ZigTypeIdPointer);
- slot_type = instruction->value.type->data.pointer.child_type;
- } else if (instruction->id == IrInstructionIdContainerInitList) {
- IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction;
- slot = &container_init_list_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdStructInit) {
- IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction;
- slot = &struct_init_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdUnionInit) {
- IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction;
- slot = &union_init_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdCall) {
- IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
- slot = &call_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdSlice) {
- IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
- slot = &slice_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdOptionalWrap) {
- IrInstructionOptionalWrap *maybe_wrap_instruction = (IrInstructionOptionalWrap *)instruction;
- slot = &maybe_wrap_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdErrWrapPayload) {
- IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction;
- slot = &err_wrap_payload_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdErrWrapCode) {
- IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
- slot = &err_wrap_code_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdCmpxchg) {
- IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction;
- slot = &cmpxchg_instruction->tmp_ptr;
- } else {
- zig_unreachable();
- }
- *slot = build_alloca(g, slot_type, "", get_abi_alignment(g, slot_type));
+ IrInstructionAlloca *instruction = fn_table_entry->alloca_list.at(alloca_i);
+ ZigType *slot_type = instruction->base.value.type;
+ instruction->base.llvm_value = build_alloca(g, slot_type, "", get_abi_alignment(g, slot_type));
}
ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
diff --git a/src/ir.cpp b/src/ir.cpp
index 83ad9c020dc2..dbb2554ba03b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -138,8 +138,8 @@ struct ConstCastErrSetMismatch {
ZigList missing_errors;
};
-static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
-static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
+static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope,
+ LVal lval, IrInstruction *result_loc);
static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type);
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr);
@@ -295,6 +295,14 @@ static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) {
return new_bb;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarSrc *) {
+ return IrInstructionIdDeclVarSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarGen *) {
+ return IrInstructionIdDeclVarGen;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) {
return IrInstructionIdCondBr;
}
@@ -327,10 +335,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) {
return IrInstructionIdBinOp;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) {
- return IrInstructionIdDeclVar;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) {
return IrInstructionIdExport;
}
@@ -343,6 +347,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStorePtr *) {
return IrInstructionIdStorePtr;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadResult *) {
+ return IrInstructionIdLoadResult;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionStoreResult *) {
+ return IrInstructionIdStoreResult;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldPtr *) {
return IrInstructionIdFieldPtr;
}
@@ -535,14 +547,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrSetCast *) {
return IrInstructionIdErrSetCast;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionToBytes *) {
- return IrInstructionIdToBytes;
-}
-
-static constexpr IrInstructionId ir_instruction_id(IrInstructionFromBytes *) {
- return IrInstructionIdFromBytes;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToFloat *) {
return IrInstructionIdIntToFloat;
}
@@ -855,6 +859,34 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScop
return IrInstructionIdCheckRuntimeScope;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultErrorUnionPayload *) {
+ return IrInstructionIdResultErrorUnionPayload;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultReturn *) {
+ return IrInstructionIdResultReturn;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultParam *) {
+ return IrInstructionIdResultParam;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtrCast *) {
+ return IrInstructionIdResultPtrCast;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultSliceToBytes *) {
+ return IrInstructionIdResultSliceToBytes;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultBytesToSlice *) {
+ return IrInstructionIdResultBytesToSlice;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) {
+ return IrInstructionIdAlloca;
+}
+
template
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate(1);
@@ -1161,7 +1193,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast
static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
- IrInstruction *new_stack)
+ IrInstruction *new_stack, IrInstruction *result_loc)
{
IrInstructionCall *call_instruction = ir_build_instruction(irb, scope, source_node);
call_instruction->fn_entry = fn_entry;
@@ -1173,6 +1205,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
call_instruction->is_async = is_async;
call_instruction->async_allocator = async_allocator;
call_instruction->new_stack = new_stack;
+ call_instruction->result_loc = result_loc;
if (fn_ref)
ir_ref_instruction(fn_ref, irb->current_basic_block);
@@ -1183,6 +1216,8 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
if (new_stack != nullptr)
ir_ref_instruction(new_stack, irb->current_basic_block);
+ ir_ref_instruction(result_loc, irb->current_basic_block);
+
return &call_instruction->base;
}
@@ -1341,20 +1376,29 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *
return &instruction->base;
}
-static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
- ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value)
+static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *ptr)
{
- IrInstructionDeclVar *decl_var_instruction = ir_build_instruction(irb, scope, source_node);
+ IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction(irb, scope, source_node);
decl_var_instruction->base.value.special = ConstValSpecialStatic;
decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
decl_var_instruction->var = var;
decl_var_instruction->var_type = var_type;
decl_var_instruction->align_value = align_value;
- decl_var_instruction->init_value = init_value;
+ decl_var_instruction->ptr = ptr;
if (var_type) ir_ref_instruction(var_type, irb->current_basic_block);
if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
- ir_ref_instruction(init_value, irb->current_basic_block);
+ ir_ref_instruction(ptr, irb->current_basic_block);
+
+ return &decl_var_instruction->base;
+}
+
+static IrInstruction *ir_build_var_decl_gen(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var) {
+ IrInstructionDeclVarGen *decl_var_instruction = ir_build_instruction(irb, scope, source_node);
+ decl_var_instruction->base.value.special = ConstValSpecialStatic;
+ decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
+ decl_var_instruction->var = var;
return &decl_var_instruction->base;
}
@@ -1386,6 +1430,32 @@ static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *s
return &instruction->base;
}
+static IrInstruction *ir_build_load_result(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *ptr, IrInstruction *result_loc)
+{
+ IrInstructionLoadResult *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->ptr = ptr;
+ instruction->result_loc = result_loc;
+
+ ir_ref_instruction(ptr, irb->current_basic_block);
+ ir_ref_instruction(result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_store_result(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *result_loc, IrInstruction *value)
+{
+ IrInstructionStoreResult *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->result_loc = result_loc;
+ instruction->value = value;
+
+ ir_ref_instruction(result_loc, irb->current_basic_block);
+ ir_ref_instruction(value, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_typeof(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
IrInstructionTypeOf *instruction = ir_build_instruction(irb, scope, source_node);
instruction->value = value;
@@ -1760,11 +1830,10 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base;
}
-static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value,
- IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
- IrInstruction *success_order_value, IrInstruction *failure_order_value,
- bool is_weak,
- ZigType *type, AtomicOrder success_order, AtomicOrder failure_order)
+static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
+ IrInstruction *success_order_value, IrInstruction *failure_order_value, bool is_weak,
+ ZigType *type, AtomicOrder success_order, AtomicOrder failure_order, IrInstruction *result_loc)
{
IrInstructionCmpxchg *instruction = ir_build_instruction(irb, scope, source_node);
instruction->type_value = type_value;
@@ -1777,6 +1846,7 @@ static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *so
instruction->type = type;
instruction->success_order = success_order;
instruction->failure_order = failure_order;
+ instruction->result_loc = result_loc;
if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block);
ir_ref_instruction(ptr, irb->current_basic_block);
@@ -1784,6 +1854,7 @@ static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *so
ir_ref_instruction(new_value, irb->current_basic_block);
if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block);
if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block);
+ ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -1842,26 +1913,6 @@ static IrInstruction *ir_build_err_set_cast(IrBuilder *irb, Scope *scope, AstNod
return &instruction->base;
}
-static IrInstruction *ir_build_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) {
- IrInstructionToBytes *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->target = target;
-
- ir_ref_instruction(target, irb->current_basic_block);
-
- return &instruction->base;
-}
-
-static IrInstruction *ir_build_from_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_child_type, IrInstruction *target) {
- IrInstructionFromBytes *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->dest_child_type = dest_child_type;
- instruction->target = target;
-
- ir_ref_instruction(dest_child_type, irb->current_basic_block);
- ir_ref_instruction(target, irb->current_basic_block);
-
- return &instruction->base;
-}
-
static IrInstruction *ir_build_int_to_float(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
IrInstructionIntToFloat *instruction = ir_build_instruction(irb, scope, source_node);
instruction->dest_type = dest_type;
@@ -1944,16 +1995,18 @@ static IrInstruction *ir_build_memcpy(IrBuilder *irb, Scope *scope, AstNode *sou
}
static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on)
+ IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, IrInstruction *result_loc)
{
IrInstructionSlice *instruction = ir_build_instruction(irb, scope, source_node);
instruction->ptr = ptr;
instruction->start = start;
instruction->end = end;
+ instruction->result_loc = result_loc;
instruction->safety_check_on = safety_check_on;
ir_ref_instruction(ptr, irb->current_basic_block);
ir_ref_instruction(start, irb->current_basic_block);
+ ir_ref_instruction(result_loc, irb->current_basic_block);
if (end) ir_ref_instruction(end, irb->current_basic_block);
return &instruction->base;
@@ -2261,13 +2314,15 @@ static IrInstruction *ir_build_check_statement_is_void(IrBuilder *irb, Scope *sc
}
static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *type_value)
+ IrInstruction *type_value, IrInstruction *result_loc)
{
IrInstructionTypeName *instruction = ir_build_instruction(
irb, scope, source_node);
instruction->type_value = type_value;
+ instruction->result_loc = result_loc;
ir_ref_instruction(type_value, irb->current_basic_block);
+ ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -2295,12 +2350,14 @@ static IrInstruction *ir_build_panic(IrBuilder *irb, Scope *scope, AstNode *sour
}
static IrInstruction *ir_build_tag_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *target)
+ IrInstruction *target, IrInstruction *result_loc)
{
IrInstructionTagName *instruction = ir_build_instruction(irb, scope, source_node);
instruction->target = target;
+ instruction->result_loc = result_loc;
ir_ref_instruction(target, irb->current_basic_block);
+ ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -2720,6 +2777,79 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope,
return &instruction->base;
}
+static IrInstruction *ir_build_result_error_union_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc)
+{
+ IrInstructionResultErrorUnionPayload *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_return(IrBuilder *irb, Scope *scope, AstNode *source_node) {
+ IrInstructionResultReturn *instruction = ir_build_instruction(irb, scope, source_node);
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_param(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *fn_ref, size_t param_index)
+{
+ IrInstructionResultParam *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->fn_ref = fn_ref;
+
+ ir_ref_instruction(fn_ref, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *elem_type, IrInstruction *prev_result_loc)
+{
+ IrInstructionResultPtrCast *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->elem_type = elem_type;
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(elem_type, irb->current_basic_block);
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_slice_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *elem_type, IrInstruction *prev_result_loc)
+{
+ IrInstructionResultSliceToBytes *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->elem_type = elem_type;
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(elem_type, irb->current_basic_block);
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_bytes_to_slice(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc)
+{
+ IrInstructionResultBytesToSlice *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_alloca(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ty) {
+ IrInstructionAlloca *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->ty = ty;
+
+ if (ty != nullptr) ir_ref_instruction(ty, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -2778,12 +2908,16 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
{
AstNode *defer_expr_node = defer_node->data.defer.expr;
Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
- IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
+ IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope,
+ LValNone, nullptr);
if (defer_expr_value != irb->codegen->invalid_instruction) {
- if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == ZigTypeIdUnreachable) {
+ if (defer_expr_value->value.type != nullptr &&
+ defer_expr_value->value.type->id == ZigTypeIdUnreachable)
+ {
is_noreturn = true;
} else {
- ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
+ ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node,
+ defer_expr_value));
}
}
}
@@ -2905,7 +3039,9 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime);
}
-static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeReturnExpr);
ZigFn *fn_entry = exec_fn_entry(irb->exec);
@@ -2934,7 +3070,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
// Temporarily set this so that if we return a type it gets the name of the function
ZigFn *prev_name_fn = irb->exec->name_fn;
irb->exec->name_fn = exec_fn_entry(irb->exec);
- return_value = ir_gen_node(irb, expr_node, scope);
+ return_value = ir_gen_node(irb, expr_node, scope, LValNone, irb->exec->return_result_loc);
irb->exec->name_fn = prev_name_fn;
if (return_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -2991,7 +3127,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
case ReturnKindError:
{
assert(expr_node);
- IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
+ IrInstruction *new_result_loc = ir_build_result_error_union_payload(irb, scope, node, result_loc);
+ IrInstruction *err_union_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, new_result_loc);
if (err_union_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr);
@@ -3104,7 +3241,9 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n
return var;
}
-static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
+static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node,
+ IrInstruction *result_loc)
+{
assert(block_node->type == NodeTypeBlock);
ZigList incoming_values = {0};
@@ -3126,6 +3265,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
}
if (block_node->data.block.name != nullptr) {
+ scope_block->result_loc = result_loc;
scope_block->incoming_blocks = &incoming_blocks;
scope_block->incoming_values = &incoming_values;
scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd");
@@ -3137,7 +3277,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
AstNode *statement_node = block_node->data.block.statements.at(i);
- IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope);
+ IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope, LValNone, nullptr);
is_continuation_unreachable = instr_is_unreachable(statement_value);
if (is_continuation_unreachable) {
// keep the last noreturn statement value around in case we need to return it
@@ -3147,9 +3287,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
// defer starts a new scope
child_scope = statement_node->data.defer.child_scope;
assert(child_scope);
- } else if (statement_value->id == IrInstructionIdDeclVar) {
+ } else if (statement_value->id == IrInstructionIdDeclVarSrc) {
// variable declarations start a new scope
- IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value;
+ IrInstructionDeclVarSrc *decl_var_instruction = (IrInstructionDeclVarSrc *)statement_value;
child_scope = decl_var_instruction->var->child_scope;
} else if (statement_value != irb->codegen->invalid_instruction && !is_continuation_unreachable) {
// this statement's value must be void
@@ -3182,8 +3322,10 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
}
static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
- IrInstruction *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope);
- IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
+ // All the binary ops operate either on scalar values or comptime values, so
+ // we do not need a result location.
+ IrInstruction *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValNone, nullptr);
+ IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
if (op1 == irb->codegen->invalid_instruction || op2 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -3192,22 +3334,24 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *no
}
static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) {
- IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr);
- IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
+ IrInstruction *lvalue = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
+ IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, lvalue);
if (lvalue == irb->codegen->invalid_instruction || rvalue == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- ir_build_store_ptr(irb, scope, node, lvalue, rvalue);
+ ir_build_store_result(irb, scope, node, lvalue, rvalue);
return ir_build_const_void(irb, scope, node);
}
static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
- IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr);
+ // All the assign ops operate on scalar values or comptime values, so
+ // we do not need a result location.
+ IrInstruction *lvalue = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
if (lvalue == irb->codegen->invalid_instruction)
return lvalue;
IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue);
- IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
+ IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
if (op2 == irb->codegen->invalid_instruction)
return op2;
IrInstruction *result = ir_build_bin_op(irb, scope, node, op_id, op1, op2, true);
@@ -3218,7 +3362,7 @@ static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *no
static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeBinOpExpr);
- IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope);
+ IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValNone, nullptr);
if (val1 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrBasicBlock *post_val1_block = irb->current_basic_block;
@@ -3238,7 +3382,7 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node
ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, false_block);
- IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
+ IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
if (val2 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrBasicBlock *post_val2_block = irb->current_basic_block;
@@ -3260,7 +3404,7 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node
static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeBinOpExpr);
- IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope);
+ IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValNone, nullptr);
if (val1 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrBasicBlock *post_val1_block = irb->current_basic_block;
@@ -3280,7 +3424,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, true_block);
- IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
+ IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
if (val2 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrBasicBlock *post_val2_block = irb->current_basic_block;
@@ -3299,13 +3443,13 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
}
-static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node, IrInstruction *result_loc) {
assert(node->type == NodeTypeBinOpExpr);
AstNode *op1_node = node->data.bin_op_expr.op1;
AstNode *op2_node = node->data.bin_op_expr.op2;
- IrInstruction *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr);
+ IrInstruction *maybe_ptr = ir_gen_node(irb, op1_node, parent_scope, LValPtr, nullptr);
if (maybe_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -3325,7 +3469,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, null_block);
- IrInstruction *null_result = ir_gen_node(irb, op2_node, parent_scope);
+ IrInstruction *null_result = ir_gen_node(irb, op2_node, parent_scope, LValNone, result_loc);
if (null_result == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrBasicBlock *after_null_block = irb->current_basic_block;
@@ -3334,7 +3478,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
ir_set_cursor_at_end_and_append_block(irb, ok_block);
IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, parent_scope, node, maybe_ptr, false);
- IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr);
+ IrInstruction *unwrapped_payload = ir_build_load_result(irb, parent_scope, node, unwrapped_ptr, result_loc);
IrBasicBlock *after_ok_block = irb->current_basic_block;
ir_build_br(irb, parent_scope, node, end_block, is_comptime);
@@ -3354,18 +3498,18 @@ static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, As
AstNode *op1_node = node->data.bin_op_expr.op1;
AstNode *op2_node = node->data.bin_op_expr.op2;
- IrInstruction *err_set = ir_gen_node(irb, op1_node, parent_scope);
+ IrInstruction *err_set = ir_gen_node(irb, op1_node, parent_scope, LValNone, nullptr);
if (err_set == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *payload = ir_gen_node(irb, op2_node, parent_scope);
+ IrInstruction *payload = ir_gen_node(irb, op2_node, parent_scope, LValNone, nullptr);
if (payload == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
return ir_build_error_union(irb, parent_scope, node, err_set, payload);
}
-static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
assert(node->type == NodeTypeBinOpExpr);
BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
@@ -3451,7 +3595,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
case BinOpTypeMergeErrorSets:
return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
case BinOpTypeUnwrapOptional:
- return ir_gen_maybe_ok_or(irb, scope, node);
+ return ir_gen_orelse(irb, scope, node, result_loc);
case BinOpTypeErrorUnion:
return ir_gen_error_union(irb, scope, node);
}
@@ -3537,16 +3681,18 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
return irb->codegen->invalid_instruction;
}
-static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeArrayAccessExpr);
AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr;
- IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LValPtr);
+ IrInstruction *array_ref_instruction = ir_gen_node(irb, array_ref_node, scope, LValPtr, nullptr);
if (array_ref_instruction == irb->codegen->invalid_instruction)
return array_ref_instruction;
AstNode *subscript_node = node->data.array_access_expr.subscript;
- IrInstruction *subscript_instruction = ir_gen_node(irb, subscript_node, scope);
+ IrInstruction *subscript_instruction = ir_gen_node(irb, subscript_node, scope, LValNone, nullptr);
if (subscript_instruction == irb->codegen->invalid_instruction)
return subscript_instruction;
@@ -3555,7 +3701,7 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode
if (lval == LValPtr)
return ptr_instruction;
- return ir_build_load_ptr(irb, scope, node, ptr_instruction);
+ return ir_build_load_result(irb, scope, node, ptr_instruction, result_loc);
}
static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -3564,7 +3710,7 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode
AstNode *container_ref_node = node->data.field_access_expr.struct_expr;
Buf *field_name = node->data.field_access_expr.field_name;
- IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LValPtr);
+ IrInstruction *container_ref_instruction = ir_gen_node(irb, container_ref_node, scope, LValPtr, nullptr);
if (container_ref_instruction == irb->codegen->invalid_instruction)
return container_ref_instruction;
@@ -3579,20 +3725,19 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *
AstNode *op2_node = node->data.fn_call_expr.params.at(2);
AstNode *result_ptr_node = node->data.fn_call_expr.params.at(3);
-
- IrInstruction *type_value = ir_gen_node(irb, type_node, scope);
+ IrInstruction *type_value = ir_gen_node(irb, type_node, scope, LValNone, nullptr);
if (type_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *op1 = ir_gen_node(irb, op1_node, scope);
+ IrInstruction *op1 = ir_gen_node(irb, op1_node, scope, LValNone, nullptr);
if (op1 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *op2 = ir_gen_node(irb, op2_node, scope);
+ IrInstruction *op2 = ir_gen_node(irb, op2_node, scope, LValNone, nullptr);
if (op2 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *result_ptr = ir_gen_node(irb, result_ptr_node, scope);
+ IrInstruction *result_ptr = ir_gen_node(irb, result_ptr_node, scope, LValNone, nullptr);
if (result_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -3614,7 +3759,9 @@ static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *no
zig_unreachable();
}
-static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
@@ -3645,7 +3792,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdTypeof:
{
AstNode *arg_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
+ IrInstruction *arg = ir_gen_node(irb, arg_node, scope, LValNone, nullptr);
if (arg == irb->codegen->invalid_instruction)
return arg;
@@ -3655,7 +3802,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdSetCold:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3665,7 +3812,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdSetRuntimeSafety:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3675,7 +3822,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdSetFloatMode:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3685,7 +3832,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdSizeof:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3695,7 +3842,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdCtz:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3705,7 +3852,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdPopCount:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3715,7 +3862,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdClz:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3725,7 +3872,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdImport:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3740,7 +3887,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdCInclude:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3755,12 +3902,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdCDefine:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -3775,7 +3922,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdCUndef:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3790,7 +3937,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdCompileErr:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3803,7 +3950,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
for (size_t i = 0; i < actual_param_count; i += 1) {
AstNode *arg_node = node->data.fn_call_expr.params.at(i);
- args[i] = ir_gen_node(irb, arg_node, scope);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, nullptr);
if (args[i] == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
}
@@ -3814,7 +3961,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdErrName:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3824,7 +3971,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdEmbedFile:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3835,44 +3982,44 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdCmpxchgStrong:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
AstNode *arg3_node = node->data.fn_call_expr.params.at(3);
- IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope);
+ IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope, LValNone, nullptr);
if (arg3_value == irb->codegen->invalid_instruction)
return arg3_value;
AstNode *arg4_node = node->data.fn_call_expr.params.at(4);
- IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope);
+ IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope, LValNone, nullptr);
if (arg4_value == irb->codegen->invalid_instruction)
return arg4_value;
AstNode *arg5_node = node->data.fn_call_expr.params.at(5);
- IrInstruction *arg5_value = ir_gen_node(irb, arg5_node, scope);
+ IrInstruction *arg5_value = ir_gen_node(irb, arg5_node, scope, LValNone, nullptr);
if (arg5_value == irb->codegen->invalid_instruction)
return arg5_value;
IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak),
- nullptr, AtomicOrderUnordered, AtomicOrderUnordered);
+ nullptr, AtomicOrderUnordered, AtomicOrderUnordered, result_loc);
return ir_lval_wrap(irb, scope, cmpxchg, lval);
}
case BuiltinFnIdFence:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3882,12 +4029,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdDivExact:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -3897,12 +4044,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdDivTrunc:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -3912,12 +4059,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdDivFloor:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -3927,12 +4074,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdRem:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -3942,12 +4089,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdMod:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -3957,12 +4104,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdSqrt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -3972,12 +4119,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdTruncate:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -3987,12 +4134,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdIntCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4002,12 +4149,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdFloatCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4017,12 +4164,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdErrSetCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4032,37 +4179,43 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdFromBytes:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
+ IrInstruction *new_result_loc = ir_build_result_slice_to_bytes(irb, scope, node, arg0_value, result_loc);
+
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, new_result_loc);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ if (lval == LValPtr)
+ return result_loc;
+ return ir_build_load_result(irb, scope, node, result_loc, result_loc);
}
case BuiltinFnIdToBytes:
{
+ IrInstruction *new_result_loc = ir_build_result_bytes_to_slice(irb, scope, node, result_loc);
+
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, new_result_loc);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ if (lval == LValPtr)
+ return result_loc;
+ return ir_build_load_result(irb, scope, node, result_loc, result_loc);
}
case BuiltinFnIdIntToFloat:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4072,12 +4225,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdFloatToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4087,7 +4240,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdErrToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4097,7 +4250,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdIntToErr:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4107,7 +4260,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdBoolToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4117,12 +4270,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdIntType:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4132,17 +4285,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdMemcpy:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
@@ -4152,17 +4305,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdMemset:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
@@ -4172,7 +4325,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdMemberCount:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4182,12 +4335,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdMemberType:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4198,12 +4351,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdMemberName:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4214,12 +4367,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdField:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node_extra(irb, arg0_node, scope, LValPtr);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValPtr, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4228,12 +4381,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (lval == LValPtr)
return ptr_instruction;
- return ir_build_load_ptr(irb, scope, node, ptr_instruction);
+ return ir_build_load_result(irb, scope, node, ptr_instruction, result_loc);
}
case BuiltinFnIdTypeInfo:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4259,7 +4412,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdAlignOf:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4277,17 +4430,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdTypeName:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value);
+ IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value, result_loc);
return ir_lval_wrap(irb, scope, type_name, lval);
}
case BuiltinFnIdPanic:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4297,12 +4450,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdPtrCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4312,27 +4465,31 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdBitCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
+ IrInstruction *new_result_loc = ir_build_result_ptr_cast(irb, scope, node, arg0_value, result_loc);
+
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, new_result_loc);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *bit_cast = ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, bit_cast, lval);
+ if (lval == LValPtr)
+ return result_loc;
+
+ return ir_build_load_result(irb, scope, node, result_loc, result_loc);
}
case BuiltinFnIdIntToPtr:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4342,7 +4499,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdPtrToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4352,18 +4509,18 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdTagName:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
- IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag);
+ IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag, result_loc);
return ir_lval_wrap(irb, scope, tag_name, lval);
}
case BuiltinFnIdTagType:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4373,17 +4530,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdFieldParentPtr:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
@@ -4393,12 +4550,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdByteOffsetOf:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4408,12 +4565,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdBitOffsetOf:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4429,7 +4586,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
AstNode *fn_ref_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
+ IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope, LValNone, nullptr);
if (fn_ref == irb->codegen->invalid_instruction)
return fn_ref;
@@ -4437,14 +4594,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction **args = allocate(arg_count);
for (size_t i = 0; i < arg_count; i += 1) {
+ IrInstruction *param_result_loc = ir_build_result_param(irb, scope, node, fn_ref, i);
AstNode *arg_node = node->data.fn_call_expr.params.at(i + 1);
- args[i] = ir_gen_node(irb, arg_node, scope);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, param_result_loc);
if (args[i] == irb->codegen->invalid_instruction)
return args[i];
}
FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
- IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr);
+ IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
+ fn_inline, false, nullptr, nullptr, result_loc);
return ir_lval_wrap(irb, scope, call, lval);
}
case BuiltinFnIdNewStackCall:
@@ -4455,12 +4614,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
AstNode *new_stack_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *new_stack = ir_gen_node(irb, new_stack_node, scope);
+ IrInstruction *new_stack = ir_gen_node(irb, new_stack_node, scope, LValNone, nullptr);
if (new_stack == irb->codegen->invalid_instruction)
return new_stack;
AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
+ IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope, LValNone, nullptr);
if (fn_ref == irb->codegen->invalid_instruction)
return fn_ref;
@@ -4468,19 +4627,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction **args = allocate(arg_count);
for (size_t i = 0; i < arg_count; i += 1) {
+ IrInstruction *param_result_loc = ir_build_result_param(irb, scope, node, fn_ref, i);
AstNode *arg_node = node->data.fn_call_expr.params.at(i + 2);
- args[i] = ir_gen_node(irb, arg_node, scope);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, param_result_loc);
if (args[i] == irb->codegen->invalid_instruction)
return args[i];
}
- IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack);
+ IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args,
+ false, FnInlineAuto, false, nullptr, new_stack, result_loc);
return ir_lval_wrap(irb, scope, call, lval);
}
case BuiltinFnIdTypeId:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4490,12 +4651,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdShlExact:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4505,12 +4666,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdShrExact:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4520,7 +4681,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdSetEvalBranchQuota:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4530,12 +4691,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdAlignCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4555,7 +4716,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdSetAlignStack:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4565,12 +4726,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdArgType:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4580,17 +4741,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdExport:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
@@ -4605,27 +4766,27 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdAtomicRmw:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
AstNode *arg3_node = node->data.fn_call_expr.params.at(3);
- IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope);
+ IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope, LValNone, nullptr);
if (arg3_value == irb->codegen->invalid_instruction)
return arg3_value;
AstNode *arg4_node = node->data.fn_call_expr.params.at(4);
- IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope);
+ IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope, LValNone, nullptr);
if (arg4_value == irb->codegen->invalid_instruction)
return arg4_value;
@@ -4637,17 +4798,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdAtomicLoad:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
@@ -4658,12 +4819,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdIntToEnum:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -4673,7 +4834,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdEnumToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -4684,22 +4845,25 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
zig_unreachable();
}
-static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeFnCallExpr);
if (node->data.fn_call_expr.is_builtin)
- return ir_gen_builtin_fn_call(irb, scope, node, lval);
+ return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc);
AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
- IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
+ IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope, LValNone, nullptr);
if (fn_ref == irb->codegen->invalid_instruction)
return fn_ref;
size_t arg_count = node->data.fn_call_expr.params.length;
IrInstruction **args = allocate(arg_count);
for (size_t i = 0; i < arg_count; i += 1) {
+ IrInstruction *param_result_loc = ir_build_result_param(irb, scope, node, fn_ref, i);
AstNode *arg_node = node->data.fn_call_expr.params.at(i);
- args[i] = ir_gen_node(irb, arg_node, scope);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, param_result_loc);
if (args[i] == irb->codegen->invalid_instruction)
return args[i];
}
@@ -4708,20 +4872,21 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
IrInstruction *async_allocator = nullptr;
if (is_async) {
if (node->data.fn_call_expr.async_allocator) {
- async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
+ async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope, LValNone, nullptr);
if (async_allocator == irb->codegen->invalid_instruction)
return async_allocator;
}
}
- IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
+ IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto,
+ is_async, async_allocator, nullptr, result_loc);
return ir_lval_wrap(irb, scope, fn_call, lval);
}
-static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
assert(node->type == NodeTypeIfBoolExpr);
- IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope);
+ IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope, LValNone, nullptr);
if (condition == irb->codegen->invalid_instruction)
return condition;
@@ -4744,7 +4909,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
ir_set_cursor_at_end_and_append_block(irb, then_block);
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
- IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope);
+ IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope, LValNone, result_loc);
if (then_expr_result == irb->codegen->invalid_instruction)
return then_expr_result;
IrBasicBlock *after_then_block = irb->current_basic_block;
@@ -4754,7 +4919,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
ir_set_cursor_at_end_and_append_block(irb, else_block);
IrInstruction *else_expr_result;
if (else_node) {
- else_expr_result = ir_gen_node(irb, else_node, subexpr_scope);
+ else_expr_result = ir_gen_node(irb, else_node, subexpr_scope, LValNone, result_loc);
if (else_expr_result == irb->codegen->invalid_instruction)
return else_expr_result;
} else {
@@ -4775,21 +4940,17 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
}
-static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) {
+static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id) {
assert(node->type == NodeTypePrefixOpExpr);
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
- IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
+ IrInstruction *value = ir_gen_node(irb, expr_node, scope, LValNone, nullptr);
if (value == irb->codegen->invalid_instruction)
return value;
return ir_build_un_op(irb, scope, node, op_id, value);
}
-static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id) {
- return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValNone);
-}
-
static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval) {
if (lval != LValPtr)
return value;
@@ -4812,14 +4973,14 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *align_value;
if (align_expr != nullptr) {
- align_value = ir_gen_node(irb, align_expr, scope);
+ align_value = ir_gen_node(irb, align_expr, scope, LValNone, nullptr);
if (align_value == irb->codegen->invalid_instruction)
return align_value;
} else {
align_value = nullptr;
}
- IrInstruction *child_type = ir_gen_node(irb, expr_node, scope);
+ IrInstruction *child_type = ir_gen_node(irb, expr_node, scope, LValNone, nullptr);
if (child_type == irb->codegen->invalid_instruction)
return child_type;
@@ -4860,7 +5021,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node,
LVal lval)
{
- IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
+ IrInstruction *err_union_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, nullptr);
if (err_union_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -4878,7 +5039,7 @@ static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *nod
assert(node->type == NodeTypePrefixOpExpr);
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
- IrInstruction *value = ir_gen_node(irb, expr_node, scope);
+ IrInstruction *value = ir_gen_node(irb, expr_node, scope, LValNone, nullptr);
if (value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -4905,19 +5066,21 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval);
case PrefixOpAddrOf: {
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
- return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_node(irb, expr_node, scope, LValPtr, nullptr), lval);
}
}
zig_unreachable();
}
-static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeContainerInitExpr);
AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr;
ContainerInitKind kind = container_init_expr->kind;
- IrInstruction *container_type = ir_gen_node(irb, container_init_expr->type, scope);
+ IrInstruction *container_type = ir_gen_node(irb, container_init_expr->type, scope, LValNone, nullptr);
if (container_type == irb->codegen->invalid_instruction)
return container_type;
@@ -4929,8 +5092,10 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
assert(entry_node->type == NodeTypeStructValueField);
Buf *name = entry_node->data.struct_val_field.name;
+ IrInstruction *field_result_loc = ir_build_field_ptr(irb, scope, entry_node, result_loc, name);
+
AstNode *expr_node = entry_node->data.struct_val_field.expr;
- IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope);
+ IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope, LValNone, field_result_loc);
if (expr_value == irb->codegen->invalid_instruction)
return expr_value;
@@ -4944,7 +5109,10 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
IrInstruction **values = allocate(item_count);
for (size_t i = 0; i < item_count; i += 1) {
AstNode *expr_node = container_init_expr->entries.at(i);
- IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope);
+ IrInstruction *index_value = ir_build_const_usize(irb, scope, expr_node, i);
+ IrInstruction *elem_result_loc = ir_build_elem_ptr(irb, scope, expr_node, result_loc, index_value, true,
+ PtrLenSingle);
+ IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope, LValNone, elem_result_loc);
if (expr_value == irb->codegen->invalid_instruction)
return expr_value;
@@ -4968,7 +5136,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
IrInstruction *type_instruction;
if (variable_declaration->type != nullptr) {
- type_instruction = ir_gen_node(irb, variable_declaration->type, scope);
+ type_instruction = ir_gen_node(irb, variable_declaration->type, scope, LValNone, nullptr);
if (type_instruction == irb->codegen->invalid_instruction)
return type_instruction;
} else {
@@ -4983,7 +5151,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime);
ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol,
is_const, is_const, is_shadowable, is_comptime);
- // we detect IrInstructionIdDeclVar in gen_block to make sure the next node
+ // we detect IrInstructionIdDeclVarSrc in gen_block to make sure the next node
// is inside var->child_scope
if (!is_extern && !variable_declaration->expr) {
@@ -4994,7 +5162,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
IrInstruction *align_value = nullptr;
if (variable_declaration->align_expr != nullptr) {
- align_value = ir_gen_node(irb, variable_declaration->align_expr, scope);
+ align_value = ir_gen_node(irb, variable_declaration->align_expr, scope, LValNone, nullptr);
if (align_value == irb->codegen->invalid_instruction)
return align_value;
}
@@ -5004,20 +5172,23 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol)));
}
+ IrInstruction *alloca = ir_build_alloca(irb, scope, node, type_instruction);
+
// Temporarily set the name of the IrExecutable to the VariableDeclaration
// so that the struct or enum from the init expression inherits the name.
Buf *old_exec_name = irb->exec->name;
irb->exec->name = variable_declaration->symbol;
- IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope);
+ IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope, LValNone, alloca);
irb->exec->name = old_exec_name;
if (init_value == irb->codegen->invalid_instruction)
return init_value;
- return ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value);
+ ir_build_store_result(irb, scope, node, alloca, init_value);
+ return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, alloca);
}
-static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
assert(node->type == NodeTypeWhileExpr);
AstNode *continue_expr_node = node->data.while_expr.continue_expr;
@@ -5052,7 +5223,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
} else {
payload_scope = subexpr_scope;
}
- IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, LValPtr);
+ IrInstruction *err_val_ptr = ir_gen_node(irb, node->data.while_expr.condition, subexpr_scope,
+ LValPtr, nullptr);
if (err_val_ptr == irb->codegen->invalid_instruction)
return err_val_ptr;
IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
@@ -5069,8 +5241,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node,
err_val_ptr, false);
IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
- var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value);
- ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
+ ir_build_ref(irb, payload_scope, symbol_node, var_ptr_value, true, false) : var_ptr_value;
+ ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
}
ZigList incoming_values = {0};
@@ -5080,10 +5252,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
loop_scope->break_block = end_block;
loop_scope->continue_block = continue_block;
loop_scope->is_comptime = is_comptime;
+ loop_scope->result_loc = result_loc;
loop_scope->incoming_blocks = &incoming_blocks;
loop_scope->incoming_values = &incoming_values;
- IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base);
+ IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base,
+ LValNone, result_loc);
if (body_result == irb->codegen->invalid_instruction)
return body_result;
@@ -5094,7 +5268,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (continue_expr_node) {
ir_set_cursor_at_end_and_append_block(irb, continue_block);
- IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, payload_scope);
+ IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, payload_scope, LValNone, nullptr);
if (expr_result == irb->codegen->invalid_instruction)
return expr_result;
if (!instr_is_unreachable(expr_result))
@@ -5111,9 +5285,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
true, false, false, is_comptime);
Scope *err_scope = err_var->child_scope;
IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);
- ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value);
+ ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value);
- else_result = ir_gen_node(irb, else_node, err_scope);
+ else_result = ir_gen_node(irb, else_node, err_scope, LValNone, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
if (!instr_is_unreachable(else_result))
@@ -5139,7 +5313,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ZigVar *payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol,
true, false, false, is_comptime);
Scope *child_scope = payload_var->child_scope;
- IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, LValPtr);
+ IrInstruction *maybe_val_ptr = ir_gen_node(irb, node->data.while_expr.condition, subexpr_scope,
+ LValPtr, nullptr);
if (maybe_val_ptr == irb->codegen->invalid_instruction)
return maybe_val_ptr;
IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);
@@ -5154,8 +5329,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, body_block);
IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
- var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value);
- ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
+ ir_build_ref(irb, child_scope, symbol_node, var_ptr_value, true, false) : var_ptr_value;
+ ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
ZigList incoming_values = {0};
ZigList incoming_blocks = {0};
@@ -5164,10 +5339,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
loop_scope->break_block = end_block;
loop_scope->continue_block = continue_block;
loop_scope->is_comptime = is_comptime;
+ loop_scope->result_loc = result_loc;
loop_scope->incoming_blocks = &incoming_blocks;
loop_scope->incoming_values = &incoming_values;
- IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base);
+ IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base,
+ LValNone, result_loc);
if (body_result == irb->codegen->invalid_instruction)
return body_result;
@@ -5178,7 +5355,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (continue_expr_node) {
ir_set_cursor_at_end_and_append_block(irb, continue_block);
- IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, child_scope);
+ IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, child_scope, LValNone, nullptr);
if (expr_result == irb->codegen->invalid_instruction)
return expr_result;
if (!instr_is_unreachable(expr_result))
@@ -5189,7 +5366,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (else_node) {
ir_set_cursor_at_end_and_append_block(irb, else_block);
- else_result = ir_gen_node(irb, else_node, scope);
+ else_result = ir_gen_node(irb, else_node, scope, LValNone, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
if (!instr_is_unreachable(else_result))
@@ -5208,7 +5385,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
} else {
ir_set_cursor_at_end_and_append_block(irb, cond_block);
- IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope);
+ IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope, LValNone, nullptr);
if (cond_val == irb->codegen->invalid_instruction)
return cond_val;
IrBasicBlock *after_cond_block = irb->current_basic_block;
@@ -5229,10 +5406,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
loop_scope->break_block = end_block;
loop_scope->continue_block = continue_block;
loop_scope->is_comptime = is_comptime;
+ loop_scope->result_loc = result_loc;
loop_scope->incoming_blocks = &incoming_blocks;
loop_scope->incoming_values = &incoming_values;
- IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base);
+ IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base,
+ LValNone, result_loc);
if (body_result == irb->codegen->invalid_instruction)
return body_result;
@@ -5243,7 +5422,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (continue_expr_node) {
ir_set_cursor_at_end_and_append_block(irb, continue_block);
- IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, subexpr_scope);
+ IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, subexpr_scope, LValNone, nullptr);
if (expr_result == irb->codegen->invalid_instruction)
return expr_result;
if (!instr_is_unreachable(expr_result))
@@ -5254,7 +5433,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (else_node) {
ir_set_cursor_at_end_and_append_block(irb, else_block);
- else_result = ir_gen_node(irb, else_node, subexpr_scope);
+ else_result = ir_gen_node(irb, else_node, subexpr_scope, LValNone, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
if (!instr_is_unreachable(else_result))
@@ -5274,7 +5453,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
}
}
-static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeForExpr);
AstNode *array_node = node->data.for_expr.array_expr;
@@ -5289,7 +5470,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
}
assert(elem_node->type == NodeTypeSymbol);
- IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPtr);
+ IrInstruction *array_val_ptr = ir_gen_node(irb, array_node, parent_scope, LValPtr, nullptr);
if (array_val_ptr == irb->codegen->invalid_instruction)
return array_val_ptr;
@@ -5311,9 +5492,8 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime);
Scope *child_scope = elem_var->child_scope;
- IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node);
- ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value);
- IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var);
+ IrInstruction *elem_alloca = ir_build_alloca(irb, child_scope, elem_node, elem_var_type);
+ ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, elem_alloca);
AstNode *index_var_source_node;
ZigVar *index_var;
@@ -5328,10 +5508,11 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
child_scope = index_var->child_scope;
IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize);
+ IrInstruction *index_alloca = ir_build_alloca(irb, child_scope, node, usize);
IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0);
IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1);
- ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero);
- IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var);
+ ir_build_store_ptr(irb, child_scope, index_var_source_node, index_alloca, zero);
+ ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, usize, nullptr, index_alloca);
IrBasicBlock *cond_block = ir_create_basic_block(irb, child_scope, "ForCond");
@@ -5344,7 +5525,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, cond_block);
- IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_ptr);
+ IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca);
IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
@@ -5358,7 +5539,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
} else {
elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr);
}
- ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val));
+ ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_alloca, elem_val));
ZigList incoming_values = {0};
ZigList incoming_blocks = {0};
@@ -5366,24 +5547,25 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
loop_scope->break_block = end_block;
loop_scope->continue_block = continue_block;
loop_scope->is_comptime = is_comptime;
+ loop_scope->result_loc = result_loc;
loop_scope->incoming_blocks = &incoming_blocks;
loop_scope->incoming_values = &incoming_values;
- IrInstruction *body_result = ir_gen_node(irb, body_node, &loop_scope->base);
+ IrInstruction *body_result = ir_gen_node(irb, body_node, &loop_scope->base, LValNone, result_loc);
if (!instr_is_unreachable(body_result))
ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, continue_block);
IrInstruction *new_index_val = ir_build_bin_op(irb, child_scope, node, IrBinOpAdd, index_val, one, false);
- ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val));
+ ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_alloca, new_index_val));
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
IrInstruction *else_result = nullptr;
if (else_node) {
ir_set_cursor_at_end_and_append_block(irb, else_block);
- else_result = ir_gen_node(irb, else_node, parent_scope);
+ else_result = ir_gen_node(irb, else_node, parent_scope, LValNone, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
if (!instr_is_unreachable(else_result))
@@ -5441,11 +5623,11 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
return irb->codegen->invalid_instruction;
}
- IrInstruction *size_value = ir_gen_node(irb, size_node, scope);
+ IrInstruction *size_value = ir_gen_node(irb, size_node, scope, LValNone, nullptr);
if (size_value == irb->codegen->invalid_instruction)
return size_value;
- IrInstruction *child_type = ir_gen_node(irb, child_type_node, scope);
+ IrInstruction *child_type = ir_gen_node(irb, child_type_node, scope, LValNone, nullptr);
if (child_type == irb->codegen->invalid_instruction)
return child_type;
@@ -5453,14 +5635,14 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
} else {
IrInstruction *align_value;
if (align_expr != nullptr) {
- align_value = ir_gen_node(irb, align_expr, scope);
+ align_value = ir_gen_node(irb, align_expr, scope, LValNone, nullptr);
if (align_value == irb->codegen->invalid_instruction)
return align_value;
} else {
align_value = nullptr;
}
- IrInstruction *child_type = ir_gen_node(irb, child_type_node, scope);
+ IrInstruction *child_type = ir_gen_node(irb, child_type_node, scope, LValNone, nullptr);
if (child_type == irb->codegen->invalid_instruction)
return child_type;
@@ -5475,7 +5657,7 @@ static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *payload_type_value = nullptr;
if (payload_type_node != nullptr) {
- payload_type_value = ir_gen_node(irb, payload_type_node, scope);
+ payload_type_value = ir_gen_node(irb, payload_type_node, scope, LValNone, nullptr);
if (payload_type_value == irb->codegen->invalid_instruction)
return payload_type_value;
@@ -5507,7 +5689,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
if (asm_output->return_type) {
return_count += 1;
- IrInstruction *return_type = ir_gen_node(irb, asm_output->return_type, scope);
+ IrInstruction *return_type = ir_gen_node(irb, asm_output->return_type, scope, LValNone, nullptr);
if (return_type == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
if (return_count > 1) {
@@ -5532,7 +5714,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
}
for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
- IrInstruction *input_value = ir_gen_node(irb, asm_input->expr, scope);
+ IrInstruction *input_value = ir_gen_node(irb, asm_input->expr, scope, LValNone, nullptr);
if (input_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -5542,7 +5724,9 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile);
}
-static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeTestExpr);
Buf *var_symbol = node->data.test_expr.var_symbol;
@@ -5551,7 +5735,7 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
AstNode *else_node = node->data.test_expr.else_node;
bool var_is_ptr = node->data.test_expr.var_is_ptr;
- IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
+ IrInstruction *maybe_val_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, nullptr);
if (maybe_val_ptr == irb->codegen->invalid_instruction)
return maybe_val_ptr;
@@ -5581,14 +5765,17 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, is_const, is_const, is_shadowable, is_comptime);
+ IrInstruction *payload_alloca = ir_build_alloca(irb, scope, node, nullptr);
IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
- IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value);
- ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+ IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_result(irb, subexpr_scope, node,
+ var_ptr_value, payload_alloca);
+ ir_build_store_result(irb, subexpr_scope, node, payload_alloca, var_value);
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, payload_alloca);
var_scope = var->child_scope;
} else {
var_scope = subexpr_scope;
}
- IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope);
+ IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope, LValNone, result_loc);
if (then_expr_result == irb->codegen->invalid_instruction)
return then_expr_result;
IrBasicBlock *after_then_block = irb->current_basic_block;
@@ -5598,7 +5785,7 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
ir_set_cursor_at_end_and_append_block(irb, else_block);
IrInstruction *else_expr_result;
if (else_node) {
- else_expr_result = ir_gen_node(irb, else_node, subexpr_scope);
+ else_expr_result = ir_gen_node(irb, else_node, subexpr_scope, LValNone, result_loc);
if (else_expr_result == irb->codegen->invalid_instruction)
return else_expr_result;
} else {
@@ -5619,7 +5806,7 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
}
-static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
assert(node->type == NodeTypeIfErrorExpr);
AstNode *target_node = node->data.if_err_expr.target_node;
@@ -5630,7 +5817,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
Buf *var_symbol = node->data.if_err_expr.var_symbol;
Buf *err_symbol = node->data.if_err_expr.err_symbol;
- IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr);
+ IrInstruction *err_val_ptr = ir_gen_node(irb, target_node, scope, LValPtr, nullptr);
if (err_val_ptr == irb->codegen->invalid_instruction)
return err_val_ptr;
@@ -5656,14 +5843,17 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);
+ IrInstruction *payload_alloca = ir_build_alloca(irb, scope, node, nullptr);
IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false);
- IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value);
- ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+ IrInstruction *var_value = var_is_ptr ?
+ var_ptr_value : ir_build_load_result(irb, subexpr_scope, node, var_ptr_value, payload_alloca);
+ ir_build_store_result(irb, subexpr_scope, node, payload_alloca, var_value);
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, payload_alloca);
var_scope = var->child_scope;
} else {
var_scope = subexpr_scope;
}
- IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope);
+ IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope, LValNone, result_loc);
if (then_expr_result == irb->codegen->invalid_instruction)
return then_expr_result;
IrBasicBlock *after_then_block = irb->current_basic_block;
@@ -5683,12 +5873,12 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
err_symbol, is_const, is_const, is_shadowable, is_comptime);
IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr);
- ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
err_var_scope = var->child_scope;
} else {
err_var_scope = subexpr_scope;
}
- else_expr_result = ir_gen_node(irb, else_node, err_var_scope);
+ else_expr_result = ir_gen_node(irb, else_node, err_var_scope, LValNone, result_loc);
if (else_expr_result == irb->codegen->invalid_instruction)
return else_expr_result;
} else {
@@ -5712,7 +5902,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node,
IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime,
IrInstruction *target_value_ptr, IrInstruction *prong_value,
- ZigList *incoming_blocks, ZigList *incoming_values)
+ ZigList *incoming_blocks, ZigList *incoming_values,
+ IrInstruction *result_loc)
{
assert(switch_node->type == NodeTypeSwitchExpr);
assert(prong_node->type == NodeTypeSwitchProng);
@@ -5731,19 +5922,23 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
var_name, is_const, is_const, is_shadowable, var_is_comptime);
child_scope = var->child_scope;
IrInstruction *var_value;
+ IrInstruction *payload_alloca = ir_build_alloca(irb, scope, var_symbol_node, nullptr);
if (prong_value) {
IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
- var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value);
+ var_value = var_is_ptr ?
+ var_ptr_value : ir_build_load_result(irb, scope, var_symbol_node, var_ptr_value, payload_alloca);
} else {
- var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr);
+ var_value = var_is_ptr ?
+ target_value_ptr : ir_build_load_result(irb, scope, var_symbol_node, target_value_ptr, payload_alloca);
}
IrInstruction *var_type = nullptr; // infer the type
- ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, nullptr, var_value);
+ ir_build_store_result(irb, scope, var_symbol_node, payload_alloca, var_value);
+ ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, payload_alloca);
} else {
child_scope = scope;
}
- IrInstruction *expr_result = ir_gen_node(irb, expr_node, child_scope);
+ IrInstruction *expr_result = ir_gen_node(irb, expr_node, child_scope, LValNone, result_loc);
if (expr_result == irb->codegen->invalid_instruction)
return false;
if (!instr_is_unreachable(expr_result))
@@ -5753,11 +5948,11 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
return true;
}
-static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
assert(node->type == NodeTypeSwitchExpr);
AstNode *target_node = node->data.switch_expr.expr;
- IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr);
+ IrInstruction *target_value_ptr = ir_gen_node(irb, target_node, scope, LValPtr, nullptr);
if (target_value_ptr == irb->codegen->invalid_instruction)
return target_value_ptr;
IrInstruction *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr);
@@ -5802,7 +5997,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
IrBasicBlock *prev_block = irb->current_basic_block;
ir_set_cursor_at_end_and_append_block(irb, else_block);
if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
- is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
+ is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values,
+ result_loc))
{
return irb->codegen->invalid_instruction;
}
@@ -5817,11 +6013,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
AstNode *start_node = item_node->data.switch_range.start;
AstNode *end_node = item_node->data.switch_range.end;
- IrInstruction *start_value = ir_gen_node(irb, start_node, comptime_scope);
+ IrInstruction *start_value = ir_gen_node(irb, start_node, comptime_scope, LValNone, nullptr);
if (start_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *end_value = ir_gen_node(irb, end_node, comptime_scope);
+ IrInstruction *end_value = ir_gen_node(irb, end_node, comptime_scope, LValNone, nullptr);
if (end_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -5841,7 +6037,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
ok_bit = both_ok;
}
} else {
- IrInstruction *item_value = ir_gen_node(irb, item_node, comptime_scope);
+ IrInstruction *item_value = ir_gen_node(irb, item_node, comptime_scope, LValNone, nullptr);
if (item_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -5869,7 +6065,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
ir_set_cursor_at_end_and_append_block(irb, range_block_yes);
if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
- is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
+ is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values,
+ result_loc))
{
return irb->codegen->invalid_instruction;
}
@@ -5894,7 +6091,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
assert(item_node->type != NodeTypeSwitchRange);
- IrInstruction *item_value = ir_gen_node(irb, item_node, comptime_scope);
+ IrInstruction *item_value = ir_gen_node(irb, item_node, comptime_scope, LValNone, nullptr);
if (item_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -5913,7 +6110,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
IrBasicBlock *prev_block = irb->current_basic_block;
ir_set_cursor_at_end_and_append_block(irb, prong_block);
if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
- is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values))
+ is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values,
+ result_loc))
{
return irb->codegen->invalid_instruction;
}
@@ -5945,14 +6143,18 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
}
}
-static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node,
+ LVal lval, IrInstruction *result_loc)
+{
assert(node->type == NodeTypeCompTime);
Scope *child_scope = create_comptime_scope(irb->codegen, node, parent_scope);
- return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval);
+ return ir_gen_node(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr);
}
-static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) {
+static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scope, AstNode *node,
+ ScopeBlock *block_scope)
+{
IrInstruction *is_comptime;
if (ir_should_inline(irb->exec, break_scope)) {
is_comptime = ir_build_const_bool(irb, break_scope, node, true);
@@ -5962,7 +6164,7 @@ static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scop
IrInstruction *result_value;
if (node->data.break_expr.expr) {
- result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope);
+ result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope, LValNone, block_scope->result_loc);
if (result_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
} else {
@@ -6032,7 +6234,7 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *
IrInstruction *result_value;
if (node->data.break_expr.expr) {
- result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope);
+ result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope, LValNone, loop_scope->result_loc);
if (result_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
} else {
@@ -6120,7 +6322,7 @@ static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode
return ir_build_const_void(irb, parent_scope, node);
}
-static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
assert(node->type == NodeTypeSliceExpr);
AstNodeSliceExpr *slice_expr = &node->data.slice_expr;
@@ -6128,27 +6330,27 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node)
AstNode *start_node = slice_expr->start;
AstNode *end_node = slice_expr->end;
- IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr);
+ IrInstruction *ptr_value = ir_gen_node(irb, array_node, scope, LValPtr, nullptr);
if (ptr_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *start_value = ir_gen_node(irb, start_node, scope);
+ IrInstruction *start_value = ir_gen_node(irb, start_node, scope, LValNone, nullptr);
if (start_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrInstruction *end_value;
if (end_node) {
- end_value = ir_gen_node(irb, end_node, scope);
+ end_value = ir_gen_node(irb, end_node, scope, LValNone, nullptr);
if (end_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
} else {
end_value = nullptr;
}
- return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true);
+ return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true, result_loc);
}
-static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node, IrInstruction *result_loc) {
assert(node->type == NodeTypeUnwrapErrorExpr);
AstNode *op1_node = node->data.unwrap_err_expr.op1;
@@ -6165,8 +6367,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LValNone);
}
-
- IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr);
+ IrInstruction *err_union_ptr = ir_gen_node(irb, op1_node, parent_scope, LValPtr, nullptr);
if (err_union_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -6180,9 +6381,9 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_err);
}
- IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrOk");
- IrBasicBlock *err_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrError");
- IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrEnd");
+ IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "CatchOk");
+ IrBasicBlock *err_block = ir_create_basic_block(irb, parent_scope, "CatchError");
+ IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "CatchEnd");
ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, err_block);
@@ -6196,11 +6397,11 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
is_const, is_const, is_shadowable, is_comptime);
err_scope = var->child_scope;
IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr);
- ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
+ ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
} else {
err_scope = parent_scope;
}
- IrInstruction *err_result = ir_gen_node(irb, op2_node, err_scope);
+ IrInstruction *err_result = ir_gen_node(irb, op2_node, err_scope, LValNone, result_loc);
if (err_result == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrBasicBlock *after_err_block = irb->current_basic_block;
@@ -6421,7 +6622,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
}
if (param_node->data.param_decl.var_token == nullptr) {
AstNode *type_node = param_node->data.param_decl.type;
- IrInstruction *type_value = ir_gen_node(irb, type_node, parent_scope);
+ IrInstruction *type_value = ir_gen_node(irb, type_node, parent_scope, LValNone, nullptr);
if (type_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
param_types[i] = type_value;
@@ -6432,7 +6633,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
IrInstruction *align_value = nullptr;
if (node->data.fn_proto.align_expr != nullptr) {
- align_value = ir_gen_node(irb, node->data.fn_proto.align_expr, parent_scope);
+ align_value = ir_gen_node(irb, node->data.fn_proto.align_expr, parent_scope, LValNone, nullptr);
if (align_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
}
@@ -6442,7 +6643,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
if (node->data.fn_proto.return_type == nullptr) {
return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
} else {
- return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
+ return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope, LValNone, nullptr);
if (return_type == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
}
@@ -6455,7 +6656,8 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
IrInstruction *async_allocator_type_value = nullptr;
if (node->data.fn_proto.async_allocator_type != nullptr) {
- async_allocator_type_value = ir_gen_node(irb, node->data.fn_proto.async_allocator_type, parent_scope);
+ async_allocator_type_value = ir_gen_node(irb, node->data.fn_proto.async_allocator_type, parent_scope,
+ LValNone, nullptr);
if (async_allocator_type_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
}
@@ -6538,7 +6740,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeCancel);
- IrInstruction *target_inst = ir_gen_node(irb, node->data.cancel_expr.expr, scope);
+ IrInstruction *target_inst = ir_gen_node(irb, node->data.cancel_expr.expr, scope, LValNone, nullptr);
if (target_inst == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -6597,7 +6799,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeResume);
- IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, scope);
+ IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, scope, LValNone, nullptr);
if (target_inst == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -6607,7 +6809,7 @@ static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node)
static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeAwaitExpr);
- IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, scope);
+ IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, scope, LValNone, nullptr);
if (target_inst == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -6665,7 +6867,6 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false);
- IrInstruction *undefined_value = ir_build_const_undefined(irb, scope, node);
IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
@@ -6679,9 +6880,9 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst);
IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type);
ir_build_await_bookkeeping(irb, scope, node, promise_result_type);
- ir_build_var_decl(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value);
- IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var);
- ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr);
+ IrInstruction *result_var_alloca = ir_build_alloca(irb, scope, node, promise_result_type);
+ ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, result_var_alloca);
+ ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, result_var_alloca);
IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle);
IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, scope, node, irb->exec->coro_handle);
@@ -6723,7 +6924,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
// If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to,
// because we're about to destroy the memory. So we store it into our result variable.
IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr);
- ir_build_store_ptr(irb, scope, node, my_result_var_ptr, no_suspend_result);
+ ir_build_store_ptr(irb, scope, node, result_var_alloca, no_suspend_result);
ir_build_cancel(irb, scope, node, target_inst);
ir_build_br(irb, scope, node, merge_block, const_bool_false);
@@ -6782,7 +6983,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_build_br(irb, scope, node, merge_block, const_bool_false);
ir_set_cursor_at_end_and_append_block(irb, merge_block);
- return ir_build_load_ptr(irb, scope, node, my_result_var_ptr);
+ return ir_build_load_ptr(irb, scope, node, result_var_alloca);
}
static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@@ -6875,7 +7076,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
suspend_scope->resume_block = resume_block;
child_scope = &suspend_scope->base;
IrInstruction *save_token = ir_build_coro_save(irb, child_scope, node, irb->exec->coro_handle);
- ir_gen_node(irb, node->data.suspend.block, child_scope);
+ ir_gen_node(irb, node->data.suspend.block, child_scope, LValNone, nullptr);
suspend_code = ir_mark_gen(ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false));
}
@@ -6902,8 +7103,8 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
}
-static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
- LVal lval)
+static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
+ IrInstruction *result_loc)
{
assert(scope);
switch (node->type) {
@@ -6918,11 +7119,11 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeTestDecl:
zig_unreachable();
case NodeTypeBlock:
- return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node, result_loc), lval);
case NodeTypeGroupedExpr:
- return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval);
+ return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_loc);
case NodeTypeBinOpExpr:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node, result_loc), lval);
case NodeTypeIntLiteral:
return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval);
case NodeTypeFloatLiteral:
@@ -6932,23 +7133,23 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeSymbol:
return ir_gen_symbol(irb, scope, node, lval);
case NodeTypeFnCallExpr:
- return ir_gen_fn_call(irb, scope, node, lval);
+ return ir_gen_fn_call(irb, scope, node, lval, result_loc);
case NodeTypeIfBoolExpr:
- return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node, result_loc), lval);
case NodeTypePrefixOpExpr:
return ir_gen_prefix_op_expr(irb, scope, node, lval);
case NodeTypeContainerInitExpr:
- return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node, result_loc), lval);
case NodeTypeVariableDeclaration:
return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval);
case NodeTypeWhileExpr:
- return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node, result_loc), lval);
case NodeTypeForExpr:
- return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node, result_loc), lval);
case NodeTypeArrayAccessExpr:
- return ir_gen_array_access(irb, scope, node, lval);
+ return ir_gen_array_access(irb, scope, node, lval, result_loc);
case NodeTypeReturnExpr:
- return ir_gen_return(irb, scope, node, lval);
+ return ir_gen_return(irb, scope, node, lval, result_loc);
case NodeTypeFieldAccessExpr:
{
IrInstruction *ptr_instruction = ir_gen_field_access(irb, scope, node);
@@ -6961,7 +7162,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
}
case NodeTypePtrDeref: {
AstNode *expr_node = node->data.ptr_deref_expr.target;
- IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
+ IrInstruction *value = ir_gen_node(irb, expr_node, scope, lval, nullptr);
if (value == irb->codegen->invalid_instruction)
return value;
@@ -6970,7 +7171,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeUnwrapOptional: {
AstNode *expr_node = node->data.unwrap_optional.expr;
- IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
+ IrInstruction *maybe_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, nullptr);
if (maybe_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -6997,13 +7198,13 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeNullLiteral:
return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval);
case NodeTypeIfErrorExpr:
- return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node, result_loc), lval);
case NodeTypeTestExpr:
- return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node, result_loc), lval);
case NodeTypeSwitchExpr:
- return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node, result_loc), lval);
case NodeTypeCompTime:
- return ir_gen_comptime(irb, scope, node, lval);
+ return ir_gen_comptime(irb, scope, node, lval, result_loc);
case NodeTypeErrorType:
return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval);
case NodeTypeBreak:
@@ -7015,9 +7216,9 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeDefer:
return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval);
case NodeTypeSliceExpr:
- return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node, result_loc), lval);
case NodeTypeUnwrapErrorExpr:
- return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval);
+ return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node, result_loc), lval);
case NodeTypeContainerDecl:
return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
case NodeTypeFnProto:
@@ -7036,16 +7237,14 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
zig_unreachable();
}
-static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval) {
- IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval);
+static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
+ IrInstruction *result_loc)
+{
+ IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc);
irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction);
return result;
}
-static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) {
- return ir_gen_node_extra(irb, node, scope, LValNone);
-}
-
static void invalidate_exec(IrExecutable *exec) {
if (exec->invalid)
return;
@@ -7076,6 +7275,9 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ir_ref_bb(irb->current_basic_block);
ZigFn *fn_entry = exec_fn_entry(irb->exec);
+
+ irb->exec->return_result_loc = ir_build_result_return(irb, scope, node);
+
bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
IrInstruction *coro_id;
IrInstruction *u8_ptr_type;
@@ -7096,15 +7298,17 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
// TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
- ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
- coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var);
+ coro_promise_ptr = ir_build_alloca(irb, coro_scope, node, coro_frame_type_value);
+ ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, coro_promise_ptr);
ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
- ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
- irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var);
+ irb->exec->await_handle_var_ptr = ir_build_alloca(irb, coro_scope, node, await_handle_type_val);
+ ir_build_store_ptr(irb, coro_scope, node, irb->exec->await_handle_var_ptr, null_value);
+ ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr,
+ irb->exec->await_handle_var_ptr);
u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
@@ -7112,11 +7316,16 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
- ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size);
+ IrInstruction *coro_size_var_alloca = ir_build_alloca(irb, coro_scope, node, nullptr);
+ ir_build_store_ptr(irb, coro_scope, node, coro_size_var_alloca, coro_size);
+ ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size_var_alloca);
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
ImplicitAllocatorIdArg);
irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
- ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
+ IrInstruction *coro_allocator_var_alloca = ir_build_alloca(irb, coro_scope, node, nullptr);
+ ir_build_store_ptr(irb, coro_scope, node, coro_allocator_var_alloca, implicit_allocator_ptr);
+ ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr,
+ coro_allocator_var_alloca);
Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr);
@@ -7162,8 +7371,9 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name);
- IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false);
- ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value);
+ IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero,
+ nullptr, false, addrs_slice_ptr);
+ ir_build_store_result(irb, scope, node, addrs_slice_ptr, slice_value);
}
@@ -7173,7 +7383,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
irb->exec->coro_final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup");
}
- IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone);
+ IrInstruction *result = ir_gen_node(irb, node, scope, LValNone, nullptr);
assert(result);
if (irb->exec->invalid)
return false;
@@ -7266,12 +7476,15 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
- IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false);
+ IrInstruction *mem_slice_alloca = ir_build_alloca(irb, scope, node, nullptr);
+ IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false,
+ mem_slice_alloca);
size_t arg_count = 2;
IrInstruction **args = allocate(arg_count);
args[0] = implicit_allocator_ptr; // self
args[1] = mem_slice; // old_mem
- ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr);
+ ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false,
+ nullptr, nullptr, nullptr);
IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
@@ -9068,15 +9281,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
}
}
-static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry) {
- if (type_has_bits(type_entry) && handle_is_ptr(type_entry)) {
- ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
- if (fn_entry != nullptr) {
- fn_entry->alloca_list.append(instruction);
- }
- }
-}
-
static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs) {
ConstGlobalRefs *global_refs = dest->global_refs;
*dest = *src;
@@ -9208,9 +9412,6 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
} else {
IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op);
result->value.type = wanted_type;
- if (need_alloca) {
- ir_add_alloca(ira, result, wanted_type);
- }
return result;
}
}
@@ -9289,7 +9490,6 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
wanted_type, value, CastOpPtrOfArrayToSlice);
result->value.type = wanted_type;
- ir_add_alloca(ira, result, wanted_type);
return result;
}
@@ -9580,7 +9780,9 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
return const_val->data.x_ptr.data.fn.fn_entry;
}
-static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) {
+static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
+ ZigType *wanted_type)
+{
assert(wanted_type->id == ZigTypeIdOptional);
if (instr_is_comptime(value)) {
@@ -9608,7 +9810,6 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc
IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
result->value.type = wanted_type;
result->value.data.rh_maybe = RuntimeHintOptionalNonNull;
- ir_add_alloca(ira, result, wanted_type);
return result;
}
@@ -9639,7 +9840,6 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
IrInstruction *result = ir_build_err_wrap_payload(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
result->value.type = wanted_type;
result->value.data.rh_error_union = RuntimeHintErrorUnionNonError;
- ir_add_alloca(ira, result, wanted_type);
return result;
}
@@ -9708,7 +9908,6 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
IrInstruction *result = ir_build_err_wrap_code(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
result->value.type = wanted_type;
result->value.data.rh_error_union = RuntimeHintErrorUnionError;
- ir_add_alloca(ira, result, wanted_type);
return result;
}
@@ -9756,11 +9955,6 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
source_instruction->source_node, value, is_const, is_volatile);
new_instruction->value.type = ptr_type;
new_instruction->value.data.rh_ptr = RuntimeHintPtrStack;
- if (type_has_bits(ptr_type)) {
- ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
- assert(fn_entry);
- fn_entry->alloca_list.append(new_instruction);
- }
return new_instruction;
}
@@ -9800,12 +9994,13 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false);
+ // TODO don't pass nullptr to ir_build_slice
+ BREAKPOINT;
IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,
- source_instr->source_node, array_ptr, start, end, false);
+ source_instr->source_node, array_ptr, start, end, false, nullptr);
result->value.type = wanted_type;
result->value.data.rh_slice.id = RuntimeHintSliceIdLen;
result->value.data.rh_slice.len = array_type->data.array.len;
- ir_add_alloca(ira, result, result->value.type);
return result;
}
@@ -12266,16 +12461,12 @@ static IrInstruction *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructio
zig_unreachable();
}
-static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) {
+static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
+ IrInstructionDeclVarSrc *decl_var_instruction)
+{
Error err;
ZigVar *var = decl_var_instruction->var;
- IrInstruction *init_value = decl_var_instruction->init_value->child;
- if (type_is_invalid(init_value->value.type)) {
- var->value->type = ira->codegen->builtin_types.entry_invalid;
- return ira->codegen->invalid_instruction;
- }
-
ZigType *explicit_type = nullptr;
IrInstruction *var_type = nullptr;
if (decl_var_instruction->var_type != nullptr) {
@@ -12290,12 +12481,11 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
AstNode *source_node = decl_var_instruction->base.source_node;
- IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, explicit_type);
bool is_comptime_var = ir_get_var_is_comptime(var);
bool var_class_requires_const = false;
- ZigType *result_type = casted_init_value->value.type;
+ ZigType *result_type = decl_var_instruction->ptr->value.type->data.pointer.child_type;
if (type_is_invalid(result_type)) {
result_type = ira->codegen->builtin_types.entry_invalid;
} else {
@@ -12319,20 +12509,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
buf_ptr(&result_type->name)));
result_type = ira->codegen->builtin_types.entry_invalid;
}
- } else {
- if (casted_init_value->value.special == ConstValSpecialStatic &&
- casted_init_value->value.type->id == ZigTypeIdFn &&
- casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
- {
- var_class_requires_const = true;
- if (!var->src_is_const && !is_comptime_var) {
- ErrorMsg *msg = ir_add_error_node(ira, source_node,
- buf_sprintf("functions marked inline must be stored in const or comptime var"));
- AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
- add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
- result_type = ira->codegen->builtin_types.entry_invalid;
- }
- }
}
}
@@ -12377,15 +12553,9 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
}
}
- if (casted_init_value->value.special != ConstValSpecialRuntime) {
- if (var->mem_slot_index != SIZE_MAX) {
- assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length);
- ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index);
- copy_const_val(mem_slot, &casted_init_value->value, !is_comptime_var || var->gen_is_const);
-
- if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
- return ir_const_void(ira, &decl_var_instruction->base);
- }
+ if (var->mem_slot_index != SIZE_MAX) {
+ if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
+ return ir_const_void(ira, &decl_var_instruction->base);
}
} else if (is_comptime_var) {
ir_add_error(ira, &decl_var_instruction->base,
@@ -12398,9 +12568,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
if (fn_entry)
fn_entry->variable_list.append(var);
- IrInstruction *result = ir_build_var_decl(&ira->new_irb,
- decl_var_instruction->base.scope, decl_var_instruction->base.source_node,
- var, var_type, nullptr, casted_init_value);
+ IrInstruction *result = ir_build_var_decl_gen(&ira->new_irb,
+ decl_var_instruction->base.scope, decl_var_instruction->base.source_node, var);
result->value.type = ira->codegen->builtin_types.entry_void;
return result;
}
@@ -12700,8 +12869,9 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c
ZigType *promise_type = get_promise_type(ira->codegen, return_type);
ZigType *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
- IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node,
- fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, nullptr);
+ IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope,
+ call_instruction->base.source_node, fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true,
+ async_allocator_inst, nullptr, nullptr);
result->value.type = async_return_type;
return result;
}
@@ -13345,7 +13515,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
if (call_instruction->is_async) {
IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
fn_ref, casted_args, impl_param_count, async_allocator_inst);
- ir_add_alloca(ira, result, result->value.type);
return ir_finish_anal(ira, result);
}
@@ -13353,10 +13522,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
call_instruction->base.scope, call_instruction->base.source_node,
impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
- call_instruction->is_async, nullptr, casted_new_stack);
+ call_instruction->is_async, nullptr, casted_new_stack, nullptr);
new_call_instruction->value.type = return_type;
- ir_add_alloca(ira, new_call_instruction, return_type);
return ir_finish_anal(ira, new_call_instruction);
}
@@ -13441,7 +13609,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref,
casted_args, call_param_count, async_allocator_inst);
- ir_add_alloca(ira, result, result->value.type);
return ir_finish_anal(ira, result);
}
@@ -13453,9 +13620,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
call_instruction->base.scope, call_instruction->base.source_node,
- fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, casted_new_stack);
+ fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
+ casted_new_stack, nullptr);
new_call_instruction->value.type = return_type;
- ir_add_alloca(ira, new_call_instruction, return_type);
return ir_finish_anal(ira, new_call_instruction);
}
@@ -14897,6 +15064,10 @@ static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruct
return ir_get_deref(ira, &load_ptr_instruction->base, ptr);
}
+static IrInstruction *ir_analyze_instruction_load_result(IrAnalyze *ira, IrInstructionLoadResult *instruction) {
+ zig_panic("TODO");
+}
+
static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) {
IrInstruction *ptr = store_ptr_instruction->ptr->child;
if (type_is_invalid(ptr->value.type))
@@ -14960,6 +15131,10 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
return result;
}
+static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInstructionStoreResult *instruction) {
+ zig_panic("TODO");
+}
+
static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
IrInstruction *expr_value = typeof_instruction->value->child;
ZigType *type_entry = expr_value->value.type;
@@ -16100,7 +16275,6 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI
instruction->scope, instruction->source_node,
container_type, type_field, casted_field_value);
new_instruction->value.type = container_type;
- ir_add_alloca(ira, new_instruction, container_type);
return new_instruction;
}
@@ -16224,7 +16398,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
instruction->scope, instruction->source_node,
container_type, actual_field_count, new_fields);
new_instruction->value.type = container_type;
- ir_add_alloca(ira, new_instruction, container_type);
return new_instruction;
}
@@ -16329,7 +16502,6 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
instruction->base.scope, instruction->base.source_node,
container_type_value, elem_count, new_items);
new_instruction->value.type = fixed_size_array_type;
- ir_add_alloca(ira, new_instruction, fixed_size_array_type);
return new_instruction;
} else if (container_type->id == ZigTypeIdVoid) {
if (elem_count != 0) {
@@ -16444,6 +16616,10 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
if (type_is_invalid(target->value.type))
return ira->codegen->invalid_instruction;
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
assert(target->value.type->id == ZigTypeIdEnum);
if (instr_is_comptime(target)) {
@@ -16457,7 +16633,7 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
}
IrInstruction *result = ir_build_tag_name(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, target);
+ instruction->base.source_node, target, result_loc);
ZigType *u8_ptr_type = get_pointer_to_type_extra(
ira->codegen, ira->codegen->builtin_types.entry_u8,
true, false, PtrLenUnknown,
@@ -17820,6 +17996,10 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
// TODO let this be volatile
ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr, ptr_type);
@@ -17885,9 +18065,8 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,
- operand_type, success_order, failure_order);
+ operand_type, success_order, failure_order, result_loc);
result->value.type = get_optional_type(ira->codegen, operand_type);
- ir_add_alloca(ira, result, result->value.type);
return result;
}
@@ -18061,124 +18240,6 @@ static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_ali
return ErrorNone;
}
-static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) {
- Error err;
-
- ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child);
- if (type_is_invalid(dest_child_type))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *target = instruction->target->child;
- if (type_is_invalid(target->value.type))
- return ira->codegen->invalid_instruction;
-
- bool src_ptr_const;
- bool src_ptr_volatile;
- uint32_t src_ptr_align;
- if (target->value.type->id == ZigTypeIdPointer) {
- src_ptr_const = target->value.type->data.pointer.is_const;
- src_ptr_volatile = target->value.type->data.pointer.is_volatile;
-
- if ((err = resolve_ptr_align(ira, target->value.type, &src_ptr_align)))
- return ira->codegen->invalid_instruction;
- } else if (is_slice(target->value.type)) {
- ZigType *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
- src_ptr_const = src_ptr_type->data.pointer.is_const;
- src_ptr_volatile = src_ptr_type->data.pointer.is_volatile;
-
- if ((err = resolve_ptr_align(ira, src_ptr_type, &src_ptr_align)))
- return ira->codegen->invalid_instruction;
- } else {
- src_ptr_const = true;
- src_ptr_volatile = false;
-
- if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusAlignmentKnown)))
- return ira->codegen->invalid_instruction;
-
- src_ptr_align = get_abi_alignment(ira->codegen, target->value.type);
- }
-
- if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown)))
- return ira->codegen->invalid_instruction;
-
- ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,
- src_ptr_const, src_ptr_volatile, PtrLenUnknown,
- src_ptr_align, 0, 0);
- ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
-
- ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
- src_ptr_const, src_ptr_volatile, PtrLenUnknown,
- src_ptr_align, 0, 0);
- ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
-
- IrInstruction *casted_value = ir_implicit_cast(ira, target, u8_slice);
- if (type_is_invalid(casted_value->value.type))
- return ira->codegen->invalid_instruction;
-
- bool have_known_len = false;
- uint64_t known_len;
-
- if (instr_is_comptime(casted_value)) {
- ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad);
- if (!val)
- return ira->codegen->invalid_instruction;
-
- ConstExprValue *len_val = &val->data.x_struct.fields[slice_len_index];
- if (value_is_comptime(len_val)) {
- known_len = bigint_as_unsigned(&len_val->data.x_bigint);
- have_known_len = true;
- }
- }
-
- if (casted_value->value.data.rh_slice.id == RuntimeHintSliceIdLen) {
- known_len = casted_value->value.data.rh_slice.len;
- have_known_len = true;
- }
-
- if (have_known_len) {
- uint64_t child_type_size = type_size(ira->codegen, dest_child_type);
- uint64_t remainder = known_len % child_type_size;
- if (remainder != 0) {
- ErrorMsg *msg = ir_add_error(ira, &instruction->base,
- buf_sprintf("unable to convert [%" ZIG_PRI_u64 "]u8 to %s: size mismatch",
- known_len, buf_ptr(&dest_slice_type->name)));
- add_error_note(ira->codegen, msg, instruction->dest_child_type->source_node,
- buf_sprintf("%s has size %" ZIG_PRI_u64 "; remaining bytes: %" ZIG_PRI_u64,
- buf_ptr(&dest_child_type->name), child_type_size, remainder));
- return ira->codegen->invalid_instruction;
- }
- }
-
- return ir_resolve_cast(ira, &instruction->base, casted_value, dest_slice_type, CastOpResizeSlice, true);
-}
-
-static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) {
- Error err;
-
- IrInstruction *target = instruction->target->child;
- if (type_is_invalid(target->value.type))
- return ira->codegen->invalid_instruction;
-
- if (!is_slice(target->value.type)) {
- ir_add_error(ira, instruction->target,
- buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- ZigType *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
-
- uint32_t alignment;
- if ((err = resolve_ptr_align(ira, src_ptr_type, &alignment)))
- return ira->codegen->invalid_instruction;
-
- ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
- src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown,
- alignment, 0, 0);
- ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
-
- return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true);
-}
-
static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) {
ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);
if (type_is_invalid(dest_type))
@@ -18565,6 +18626,10 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
if (type_is_invalid(ptr_ptr->value.type))
return ira->codegen->invalid_instruction;
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
ZigType *ptr_type = ptr_ptr->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *array_type = ptr_type->data.pointer.child_type;
@@ -18824,9 +18889,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
IrInstruction *new_instruction = ir_build_slice(&ira->new_irb,
instruction->base.scope, instruction->base.source_node,
- ptr_ptr, casted_start, end, instruction->safety_check_on);
+ ptr_ptr, casted_start, end, instruction->safety_check_on,
+ result_loc);
new_instruction->value.type = return_type;
- ir_add_alloca(ira, new_instruction, return_type);
return new_instruction;
}
@@ -20844,6 +20909,24 @@ static IrInstruction *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira,
return ir_const_void(ira, &instruction->base);
}
+static IrInstruction *ir_analyze_instruction_result_error_union_payload(IrAnalyze *ira,
+ IrInstructionResultErrorUnionPayload *instruction)
+{
+ zig_panic("TODO");
+}
+
+static IrInstruction *ir_analyze_instruction_result_return(IrAnalyze *ira, IrInstructionResultReturn *instruction) {
+ zig_panic("TODO");
+}
+
+static IrInstruction *ir_analyze_instruction_result_param(IrAnalyze *ira, IrInstructionResultParam *instruction) {
+ zig_panic("TODO");
+}
+
+static IrInstruction *ir_analyze_instruction_result_ptr_cast(IrAnalyze *ira, IrInstructionResultPtrCast *instruction) {
+ zig_panic("TODO");
+}
+
static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -20856,6 +20939,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdErrWrapCode:
case IrInstructionIdErrWrapPayload:
case IrInstructionIdCast:
+ case IrInstructionIdDeclVarGen:
zig_unreachable();
case IrInstructionIdReturn:
@@ -20866,12 +20950,16 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction);
case IrInstructionIdBinOp:
return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction);
- case IrInstructionIdDeclVar:
- return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction);
+ case IrInstructionIdDeclVarSrc:
+ return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVarSrc *)instruction);
case IrInstructionIdLoadPtr:
return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction);
case IrInstructionIdStorePtr:
return ir_analyze_instruction_store_ptr(ira, (IrInstructionStorePtr *)instruction);
+ case IrInstructionIdLoadResult:
+ return ir_analyze_instruction_load_result(ira, (IrInstructionLoadResult *)instruction);
+ case IrInstructionIdStoreResult:
+ return ir_analyze_instruction_store_result(ira, (IrInstructionStoreResult *)instruction);
case IrInstructionIdElemPtr:
return ir_analyze_instruction_elem_ptr(ira, (IrInstructionElemPtr *)instruction);
case IrInstructionIdVarPtr:
@@ -20968,10 +21056,6 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_float_cast(ira, (IrInstructionFloatCast *)instruction);
case IrInstructionIdErrSetCast:
return ir_analyze_instruction_err_set_cast(ira, (IrInstructionErrSetCast *)instruction);
- case IrInstructionIdFromBytes:
- return ir_analyze_instruction_from_bytes(ira, (IrInstructionFromBytes *)instruction);
- case IrInstructionIdToBytes:
- return ir_analyze_instruction_to_bytes(ira, (IrInstructionToBytes *)instruction);
case IrInstructionIdIntToFloat:
return ir_analyze_instruction_int_to_float(ira, (IrInstructionIntToFloat *)instruction);
case IrInstructionIdFloatToInt:
@@ -21120,6 +21204,20 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);
case IrInstructionIdCheckRuntimeScope:
return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction);
+ case IrInstructionIdResultErrorUnionPayload:
+ return ir_analyze_instruction_result_error_union_payload(ira, (IrInstructionResultErrorUnionPayload *)instruction);
+ case IrInstructionIdResultReturn:
+ return ir_analyze_instruction_result_return(ira, (IrInstructionResultReturn *)instruction);
+ case IrInstructionIdResultParam:
+ return ir_analyze_instruction_result_param(ira, (IrInstructionResultParam *)instruction);
+ case IrInstructionIdResultPtrCast:
+ return ir_analyze_instruction_result_ptr_cast(ira, (IrInstructionResultPtrCast *)instruction);
+ case IrInstructionIdResultBytesToSlice:
+ zig_panic("TODO");
+ case IrInstructionIdResultSliceToBytes:
+ zig_panic("TODO");
+ case IrInstructionIdAlloca:
+ zig_panic("TODO");
}
zig_unreachable();
}
@@ -21204,7 +21302,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdBr:
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
- case IrInstructionIdDeclVar:
+ case IrInstructionIdDeclVarSrc:
+ case IrInstructionIdDeclVarGen:
case IrInstructionIdStorePtr:
case IrInstructionIdCall:
case IrInstructionIdReturn:
@@ -21247,6 +21346,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdMergeErrRetTraces:
case IrInstructionIdMarkErrRetTracePtr:
case IrInstructionIdAtomicRmw:
+ case IrInstructionIdLoadResult:
+ case IrInstructionIdStoreResult:
return true;
case IrInstructionIdPhi:
@@ -21338,9 +21439,14 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdIntToFloat:
case IrInstructionIdFloatToInt:
case IrInstructionIdBoolToInt:
- case IrInstructionIdFromBytes:
- case IrInstructionIdToBytes:
case IrInstructionIdEnumToInt:
+ case IrInstructionIdResultErrorUnionPayload:
+ case IrInstructionIdResultReturn:
+ case IrInstructionIdResultParam:
+ case IrInstructionIdResultPtrCast:
+ case IrInstructionIdResultSliceToBytes:
+ case IrInstructionIdResultBytesToSlice:
+ case IrInstructionIdAlloca:
return false;
case IrInstructionIdAsm:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 8e51d1c6f369..489bac8bd4eb 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -172,7 +172,12 @@ static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction
}
}
-static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instruction) {
+static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVarSrc *decl_var_instruction) {
+ if (decl_var_instruction->var->is_comptime != nullptr) {
+ fprintf(irp->f, "comptime<");
+ ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime);
+ fprintf(irp->f, "> ");
+ }
const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var";
const char *name = buf_ptr(&decl_var_instruction->var->name);
if (decl_var_instruction->var_type) {
@@ -188,11 +193,7 @@ static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instr
fprintf(irp->f, " ");
}
fprintf(irp->f, "= ");
- ir_print_other_instruction(irp, decl_var_instruction->init_value);
- if (decl_var_instruction->var->is_comptime != nullptr) {
- fprintf(irp->f, " // comptime = ");
- ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime);
- }
+ ir_print_other_instruction(irp, decl_var_instruction->ptr);
}
static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
@@ -670,20 +671,6 @@ static void ir_print_err_set_cast(IrPrint *irp, IrInstructionErrSetCast *instruc
fprintf(irp->f, ")");
}
-static void ir_print_from_bytes(IrPrint *irp, IrInstructionFromBytes *instruction) {
- fprintf(irp->f, "@bytesToSlice(");
- ir_print_other_instruction(irp, instruction->dest_child_type);
- fprintf(irp->f, ", ");
- ir_print_other_instruction(irp, instruction->target);
- fprintf(irp->f, ")");
-}
-
-static void ir_print_to_bytes(IrPrint *irp, IrInstructionToBytes *instruction) {
- fprintf(irp->f, "@sliceToBytes(");
- ir_print_other_instruction(irp, instruction->target);
- fprintf(irp->f, ")");
-}
-
static void ir_print_int_to_float(IrPrint *irp, IrInstructionIntToFloat *instruction) {
fprintf(irp->f, "@intToFloat(");
ir_print_other_instruction(irp, instruction->dest_type);
@@ -1328,6 +1315,46 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *instruction) {
+ fprintf(irp->f, "DeclVarGen");
+}
+
+static void ir_print_result_error_union_payload(IrPrint *irp, IrInstructionResultErrorUnionPayload *instruction) {
+ fprintf(irp->f, "ResultErrorUnionPayload");
+}
+
+static void ir_print_result_return(IrPrint *irp, IrInstructionResultReturn *instruction) {
+ fprintf(irp->f, "ResultReturn");
+}
+
+static void ir_print_result_bytes_to_slice(IrPrint *irp, IrInstructionResultBytesToSlice *instruction) {
+ fprintf(irp->f, "ResultBytesToSlice");
+}
+
+static void ir_print_result_slice_to_bytes(IrPrint *irp, IrInstructionResultSliceToBytes *instruction) {
+ fprintf(irp->f, "ResultSliceToBytes");
+}
+
+static void ir_print_result_param(IrPrint *irp, IrInstructionResultParam *instruction) {
+ fprintf(irp->f, "ResultParam");
+}
+
+static void ir_print_result_ptr_cast(IrPrint *irp, IrInstructionResultPtrCast *instruction) {
+ fprintf(irp->f, "ResultPtrCast");
+}
+
+static void ir_print_load_result(IrPrint *irp, IrInstructionLoadResult *instruction) {
+ fprintf(irp->f, "LoadResult");
+}
+
+static void ir_print_store_result(IrPrint *irp, IrInstructionStoreResult *instruction) {
+ fprintf(irp->f, "StoreResult");
+}
+
+static void ir_print_alloca(IrPrint *irp, IrInstructionAlloca *instruction) {
+ fprintf(irp->f, "Alloca");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1342,8 +1369,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdBinOp:
ir_print_bin_op(irp, (IrInstructionBinOp *)instruction);
break;
- case IrInstructionIdDeclVar:
- ir_print_decl_var(irp, (IrInstructionDeclVar *)instruction);
+ case IrInstructionIdDeclVarSrc:
+ ir_print_decl_var(irp, (IrInstructionDeclVarSrc *)instruction);
break;
case IrInstructionIdCast:
ir_print_cast(irp, (IrInstructionCast *)instruction);
@@ -1510,12 +1537,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdErrSetCast:
ir_print_err_set_cast(irp, (IrInstructionErrSetCast *)instruction);
break;
- case IrInstructionIdFromBytes:
- ir_print_from_bytes(irp, (IrInstructionFromBytes *)instruction);
- break;
- case IrInstructionIdToBytes:
- ir_print_to_bytes(irp, (IrInstructionToBytes *)instruction);
- break;
case IrInstructionIdIntToFloat:
ir_print_int_to_float(irp, (IrInstructionIntToFloat *)instruction);
break;
@@ -1753,6 +1774,36 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdCheckRuntimeScope:
ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction);
break;
+ case IrInstructionIdDeclVarGen:
+ ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction);
+ break;
+ case IrInstructionIdResultErrorUnionPayload:
+ ir_print_result_error_union_payload(irp, (IrInstructionResultErrorUnionPayload *)instruction);
+ break;
+ case IrInstructionIdResultReturn:
+ ir_print_result_return(irp, (IrInstructionResultReturn *)instruction);
+ break;
+ case IrInstructionIdResultBytesToSlice:
+ ir_print_result_bytes_to_slice(irp, (IrInstructionResultBytesToSlice *)instruction);
+ break;
+ case IrInstructionIdResultSliceToBytes:
+ ir_print_result_slice_to_bytes(irp, (IrInstructionResultSliceToBytes *)instruction);
+ break;
+ case IrInstructionIdResultParam:
+ ir_print_result_param(irp, (IrInstructionResultParam *)instruction);
+ break;
+ case IrInstructionIdResultPtrCast:
+ ir_print_result_ptr_cast(irp, (IrInstructionResultPtrCast *)instruction);
+ break;
+ case IrInstructionIdLoadResult:
+ ir_print_load_result(irp, (IrInstructionLoadResult *)instruction);
+ break;
+ case IrInstructionIdStoreResult:
+ ir_print_store_result(irp, (IrInstructionStoreResult *)instruction);
+ break;
+ case IrInstructionIdAlloca:
+ ir_print_alloca(irp, (IrInstructionAlloca *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
From 3037be186718938cca68807c9544e22dbcd94d01 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 25 Oct 2018 16:10:13 -0400
Subject: [PATCH 002/190] copy elision: test case: scalar variable declaration
```zig
export fn entry() void {
var x: i32 = 1234;
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca i32, align 4
store i32 1234, i32* %x, align 4, !dbg !48
call void @llvm.dbg.declare(metadata i32* %x, metadata !45, metadata !DIExpression()), !dbg !48
ret void, !dbg !49
}
```
---
src/all_types.hpp | 4 +-
src/codegen.cpp | 33 ++++++-----
src/ir.cpp | 136 ++++++++++++++++++++++++++++++++--------------
src/ir_print.cpp | 14 ++++-
4 files changed, 125 insertions(+), 62 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index c05c48f95f51..239bf8d992d4 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2215,6 +2215,7 @@ struct IrInstructionDeclVarGen {
IrInstruction base;
ZigVar *var;
+ IrInstruction *var_ptr;
};
struct IrInstructionCondBr {
@@ -3324,7 +3325,8 @@ struct IrInstructionResultPtrCast {
struct IrInstructionAlloca {
IrInstruction base;
- IrInstruction *ty;
+ IrInstruction *child_type;
+ const char *name_hint;
};
static const size_t slice_ptr_index = 0;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index e4df2de81572..0b54ae5c6315 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -1844,12 +1844,12 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
return nullptr;
}
-static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
+static void gen_var_debug_decl(CodeGen *g, ZigVar *var, LLVMValueRef value_ref) {
assert(var->di_loc_var != nullptr);
AstNode *source_node = var->decl_node;
ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1,
(unsigned)source_node->column + 1, get_di_scope(g, var->parent_scope));
- ZigLLVMInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc,
+ ZigLLVMInsertDeclareAtEnd(g->dbuilder, value_ref, var->di_loc_var, debug_loc,
LLVMGetInsertBlock(g->builder));
}
@@ -2000,7 +2000,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
clear_debug_source_node(g);
gen_store_untyped(g, LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i), var->value_ref, var->align_bytes, false);
if (var->decl_node) {
- gen_var_debug_decl(g, var);
+ gen_var_debug_decl(g, var, var->value_ref);
}
fn_walk->data.inits.gen_i += 1;
break;
@@ -2035,7 +2035,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
}
case FnWalkIdInits:
if (var->decl_node) {
- gen_var_debug_decl(g, var);
+ gen_var_debug_decl(g, var, var->value_ref);
}
fn_walk->data.inits.gen_i += 1;
break;
@@ -2073,7 +2073,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
}
case FnWalkIdInits:
if (var->decl_node) {
- gen_var_debug_decl(g, var);
+ gen_var_debug_decl(g, var, var->value_ref);
}
fn_walk->data.inits.gen_i += 1;
break;
@@ -2111,7 +2111,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
if (var->decl_node) {
- gen_var_debug_decl(g, var);
+ gen_var_debug_decl(g, var, var->value_ref);
}
fn_walk->data.inits.gen_i += 1;
break;
@@ -2206,7 +2206,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
}
if (variable->decl_node) {
- gen_var_debug_decl(g, variable);
+ gen_var_debug_decl(g, variable, variable->value_ref);
}
break;
}
@@ -3175,10 +3175,8 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI
return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, "");
}
-static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
- IrInstructionDeclVarGen *decl_var_instruction)
-{
- ZigVar *var = decl_var_instruction->var;
+static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) {
+ ZigVar *var = instruction->var;
if (!type_has_bits(var->value->type))
return nullptr;
@@ -3186,7 +3184,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
if (var->ref_count == 0 && g->build_mode != BuildModeDebug)
return nullptr;
- gen_var_debug_decl(g, var);
+ gen_var_debug_decl(g, var, ir_llvm_value(g, instruction->var_ptr));
return nullptr;
}
@@ -5304,7 +5302,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdStoreResult:
zig_panic("TODO");
case IrInstructionIdAlloca:
- zig_panic("TODO");
+ return instruction->llvm_value; // handled before function code generation
}
zig_unreachable();
}
@@ -6194,8 +6192,11 @@ static void do_code_gen(CodeGen *g) {
// allocate temporary stack data
for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
IrInstructionAlloca *instruction = fn_table_entry->alloca_list.at(alloca_i);
- ZigType *slot_type = instruction->base.value.type;
- instruction->base.llvm_value = build_alloca(g, slot_type, "", get_abi_alignment(g, slot_type));
+ ZigType *ptr_type = instruction->base.value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+ ZigType *child_type = ptr_type->data.pointer.child_type;
+ instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
+ get_ptr_align(g, ptr_type));
}
ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
@@ -6221,8 +6222,6 @@ static void do_code_gen(CodeGen *g) {
continue;
if (var->src_arg_index == SIZE_MAX) {
- var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
-
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
var->value->type->di_type, !g->strip_debug_symbols, 0);
diff --git a/src/ir.cpp b/src/ir.cpp
index dbb2554ba03b..9e5d672c95e3 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1394,11 +1394,16 @@ static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNod
return &decl_var_instruction->base;
}
-static IrInstruction *ir_build_var_decl_gen(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var) {
+static IrInstruction *ir_build_var_decl_gen(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var,
+ IrInstruction *var_ptr)
+{
IrInstructionDeclVarGen *decl_var_instruction = ir_build_instruction(irb, scope, source_node);
decl_var_instruction->base.value.special = ConstValSpecialStatic;
decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
decl_var_instruction->var = var;
+ decl_var_instruction->var_ptr = var_ptr;
+
+ ir_ref_instruction(var_ptr, irb->current_basic_block);
return &decl_var_instruction->base;
}
@@ -2841,11 +2846,14 @@ static IrInstruction *ir_build_result_bytes_to_slice(IrBuilder *irb, Scope *scop
return &instruction->base;
}
-static IrInstruction *ir_build_alloca(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ty) {
+static IrInstruction *ir_build_alloca(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *child_type, const char *name_hint)
+{
IrInstructionAlloca *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->ty = ty;
+ instruction->child_type = child_type;
+ instruction->name_hint = name_hint;
- if (ty != nullptr) ir_ref_instruction(ty, irb->current_basic_block);
+ if (child_type != nullptr) ir_ref_instruction(child_type, irb->current_basic_block);
return &instruction->base;
}
@@ -5172,7 +5180,8 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol)));
}
- IrInstruction *alloca = ir_build_alloca(irb, scope, node, type_instruction);
+ IrInstruction *alloca = ir_build_alloca(irb, scope, node, type_instruction,
+ buf_ptr(variable_declaration->symbol));
// Temporarily set the name of the IrExecutable to the VariableDeclaration
// so that the struct or enum from the init expression inherits the name.
@@ -5492,7 +5501,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime);
Scope *child_scope = elem_var->child_scope;
- IrInstruction *elem_alloca = ir_build_alloca(irb, child_scope, elem_node, elem_var_type);
+ IrInstruction *elem_alloca = ir_build_alloca(irb, child_scope, elem_node, elem_var_type, "for_elem");
ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, elem_alloca);
AstNode *index_var_source_node;
@@ -5508,7 +5517,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
child_scope = index_var->child_scope;
IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize);
- IrInstruction *index_alloca = ir_build_alloca(irb, child_scope, node, usize);
+ IrInstruction *index_alloca = ir_build_alloca(irb, child_scope, node, usize, "for_index");
IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0);
IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1);
ir_build_store_ptr(irb, child_scope, index_var_source_node, index_alloca, zero);
@@ -5765,7 +5774,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, is_const, is_const, is_shadowable, is_comptime);
- IrInstruction *payload_alloca = ir_build_alloca(irb, scope, node, nullptr);
+ IrInstruction *payload_alloca = ir_build_alloca(irb, scope, node, nullptr, "optional_payload");
IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_result(irb, subexpr_scope, node,
var_ptr_value, payload_alloca);
@@ -5843,7 +5852,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);
- IrInstruction *payload_alloca = ir_build_alloca(irb, scope, node, nullptr);
+ IrInstruction *payload_alloca = ir_build_alloca(irb, scope, node, nullptr, "errunion_payload");
IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false);
IrInstruction *var_value = var_is_ptr ?
var_ptr_value : ir_build_load_result(irb, subexpr_scope, node, var_ptr_value, payload_alloca);
@@ -5922,7 +5931,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
var_name, is_const, is_const, is_shadowable, var_is_comptime);
child_scope = var->child_scope;
IrInstruction *var_value;
- IrInstruction *payload_alloca = ir_build_alloca(irb, scope, var_symbol_node, nullptr);
+ IrInstruction *payload_alloca = ir_build_alloca(irb, scope, var_symbol_node, nullptr, "switch_payload");
if (prong_value) {
IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
var_value = var_is_ptr ?
@@ -6880,7 +6889,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst);
IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type);
ir_build_await_bookkeeping(irb, scope, node, promise_result_type);
- IrInstruction *result_var_alloca = ir_build_alloca(irb, scope, node, promise_result_type);
+ IrInstruction *result_var_alloca = ir_build_alloca(irb, scope, node, promise_result_type, "");
ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, result_var_alloca);
ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, result_var_alloca);
IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle);
@@ -7298,14 +7307,14 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
// TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
- coro_promise_ptr = ir_build_alloca(irb, coro_scope, node, coro_frame_type_value);
+ coro_promise_ptr = ir_build_alloca(irb, coro_scope, node, coro_frame_type_value, "");
ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, coro_promise_ptr);
ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
- irb->exec->await_handle_var_ptr = ir_build_alloca(irb, coro_scope, node, await_handle_type_val);
+ irb->exec->await_handle_var_ptr = ir_build_alloca(irb, coro_scope, node, await_handle_type_val, "");
ir_build_store_ptr(irb, coro_scope, node, irb->exec->await_handle_var_ptr, null_value);
ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr,
irb->exec->await_handle_var_ptr);
@@ -7316,13 +7325,13 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
- IrInstruction *coro_size_var_alloca = ir_build_alloca(irb, coro_scope, node, nullptr);
+ IrInstruction *coro_size_var_alloca = ir_build_alloca(irb, coro_scope, node, nullptr, "");
ir_build_store_ptr(irb, coro_scope, node, coro_size_var_alloca, coro_size);
ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size_var_alloca);
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
ImplicitAllocatorIdArg);
irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
- IrInstruction *coro_allocator_var_alloca = ir_build_alloca(irb, coro_scope, node, nullptr);
+ IrInstruction *coro_allocator_var_alloca = ir_build_alloca(irb, coro_scope, node, nullptr, "");
ir_build_store_ptr(irb, coro_scope, node, coro_allocator_var_alloca, implicit_allocator_ptr);
ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr,
coro_allocator_var_alloca);
@@ -7476,7 +7485,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
- IrInstruction *mem_slice_alloca = ir_build_alloca(irb, scope, node, nullptr);
+ IrInstruction *mem_slice_alloca = ir_build_alloca(irb, scope, node, nullptr, "");
IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false,
mem_slice_alloca);
size_t arg_count = 2;
@@ -12485,7 +12494,14 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
bool var_class_requires_const = false;
- ZigType *result_type = decl_var_instruction->ptr->value.type->data.pointer.child_type;
+ IrInstruction *var_ptr = decl_var_instruction->ptr->child;
+ if (type_is_invalid(var_ptr->value.type)) {
+ var->value->type = ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
+ }
+
+ assert(var_ptr->value.type->id == ZigTypeIdPointer);
+ ZigType *result_type = var_ptr->value.type->data.pointer.child_type;
if (type_is_invalid(result_type)) {
result_type = ira->codegen->builtin_types.entry_invalid;
} else {
@@ -12568,8 +12584,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
if (fn_entry)
fn_entry->variable_list.append(var);
- IrInstruction *result = ir_build_var_decl_gen(&ira->new_irb,
- decl_var_instruction->base.scope, decl_var_instruction->base.source_node, var);
+ IrInstruction *result = ir_build_var_decl_gen(&ira->new_irb, decl_var_instruction->base.scope,
+ decl_var_instruction->base.source_node, var, var_ptr);
result->value.type = ira->codegen->builtin_types.entry_void;
return result;
}
@@ -15068,15 +15084,9 @@ static IrInstruction *ir_analyze_instruction_load_result(IrAnalyze *ira, IrInstr
zig_panic("TODO");
}
-static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) {
- IrInstruction *ptr = store_ptr_instruction->ptr->child;
- if (type_is_invalid(ptr->value.type))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *value = store_ptr_instruction->value->child;
- if (type_is_invalid(value->value.type))
- return ira->codegen->invalid_instruction;
-
+static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *ptr, IrInstruction *value)
+{
if (ptr->value.type->id != ZigTypeIdPointer) {
ir_add_error(ira, ptr,
buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
@@ -15084,11 +15094,11 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
}
if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
- return ir_const_void(ira, &store_ptr_instruction->base);
+ return ir_const_void(ira, source_instr);
}
- if (ptr->value.type->data.pointer.is_const && !store_ptr_instruction->base.is_gen) {
- ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant"));
+ if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
+ ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
return ira->codegen->invalid_instruction;
}
@@ -15099,23 +15109,23 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
- ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant"));
+ ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
return ira->codegen->invalid_instruction;
}
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
if (instr_is_comptime(casted_value)) {
- ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, store_ptr_instruction->base.source_node);
+ ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, source_instr->source_node);
if (dest_val == nullptr)
return ira->codegen->invalid_instruction;
if (dest_val->special != ConstValSpecialRuntime) {
*dest_val = casted_value->value;
if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
- ira->new_irb.current_basic_block->must_be_comptime_source_instr = &store_ptr_instruction->base;
+ ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
}
- return ir_const_void(ira, &store_ptr_instruction->base);
+ return ir_const_void(ira, source_instr);
}
}
- ir_add_error(ira, &store_ptr_instruction->base,
+ ir_add_error(ira, source_instr,
buf_sprintf("cannot store runtime value in compile time variable"));
ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
dest_val->type = ira->codegen->builtin_types.entry_invalid;
@@ -15124,15 +15134,40 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
}
}
- IrInstruction *result = ir_build_store_ptr(&ira->new_irb,
- store_ptr_instruction->base.scope, store_ptr_instruction->base.source_node,
+ IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
ptr, casted_value);
result->value.type = ira->codegen->builtin_types.entry_void;
return result;
}
+static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) {
+ IrInstruction *ptr = instruction->ptr->child;
+ if (type_is_invalid(ptr->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *value = instruction->value->child;
+ if (type_is_invalid(value->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
+}
+
static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInstructionStoreResult *instruction) {
- zig_panic("TODO");
+ IrInstruction *value = instruction->value->child;
+ if (type_is_invalid(value->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ // If the type is a scalar value, treat this instruction as a normal store pointer instruction.
+ if (!type_has_bits(value->value.type) || !handle_is_ptr(value->value.type)) {
+ return ir_analyze_store_ptr(ira, &instruction->base, result_loc, value);
+ }
+
+ // Otherwise, trust that the result location was populated by the expression that computed value.
+ return ir_const_void(ira, &instruction->base);
}
static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
@@ -20927,6 +20962,25 @@ static IrInstruction *ir_analyze_instruction_result_ptr_cast(IrAnalyze *ira, IrI
zig_panic("TODO");
}
+static IrInstruction *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAlloca *instruction) {
+ ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child);
+ if (type_is_invalid(child_type))
+ return ira->codegen->invalid_instruction;
+
+ // TODO alignment
+ ZigType *pointer_type = get_pointer_to_type(ira->codegen, child_type, false);
+
+ IrInstruction *result = ir_build_alloca(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
+ nullptr, instruction->name_hint);
+ result->value.type = pointer_type;
+
+ ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
+ if (fn_entry != nullptr) {
+ fn_entry->alloca_list.append(reinterpret_cast(result));
+ }
+ return result;
+}
+
static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -21212,12 +21266,12 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_result_param(ira, (IrInstructionResultParam *)instruction);
case IrInstructionIdResultPtrCast:
return ir_analyze_instruction_result_ptr_cast(ira, (IrInstructionResultPtrCast *)instruction);
+ case IrInstructionIdAlloca:
+ return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction);
case IrInstructionIdResultBytesToSlice:
zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
zig_panic("TODO");
- case IrInstructionIdAlloca:
- zig_panic("TODO");
}
zig_unreachable();
}
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 489bac8bd4eb..640bf9102290 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1316,7 +1316,9 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
}
static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *instruction) {
- fprintf(irp->f, "DeclVarGen");
+ fprintf(irp->f, "DeclVarGen(name=%s,ptr=", buf_ptr(&instruction->var->name));
+ ir_print_other_instruction(irp, instruction->var_ptr);
+ fprintf(irp->f, ")");
}
static void ir_print_result_error_union_payload(IrPrint *irp, IrInstructionResultErrorUnionPayload *instruction) {
@@ -1348,11 +1350,17 @@ static void ir_print_load_result(IrPrint *irp, IrInstructionLoadResult *instruct
}
static void ir_print_store_result(IrPrint *irp, IrInstructionStoreResult *instruction) {
- fprintf(irp->f, "StoreResult");
+ fprintf(irp->f, "StoreResult(result_loc=");
+ ir_print_other_instruction(irp, instruction->result_loc);
+ fprintf(irp->f, ",value=");
+ ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ")");
}
static void ir_print_alloca(IrPrint *irp, IrInstructionAlloca *instruction) {
- fprintf(irp->f, "Alloca");
+ fprintf(irp->f, "Alloca(");
+ ir_print_other_instruction(irp, instruction->child_type);
+ fprintf(irp->f, ")");
}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
From 1dfca202ad27674d38361e6238d75ffe0037a992 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 25 Oct 2018 16:26:52 -0400
Subject: [PATCH 003/190] copy elision: test case: initialize scalar undefined
```zig
export fn entry() void {
var x: i32 = undefined;
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca i32, align 4
%0 = bitcast i32* %x to i8*, !dbg !48
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 -86, i64 4, i1 false), !dbg !48
call void @llvm.dbg.declare(metadata i32* %x, metadata !45, metadata !DIExpression()), !dbg !48
ret void, !dbg !49
}
```
---
src/codegen.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 45 insertions(+), 5 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 0b54ae5c6315..90c801f17127 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3218,14 +3218,54 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
}
-static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
- LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
- LLVMValueRef value = ir_llvm_value(g, instruction->value);
+static bool value_is_all_undef(ConstExprValue *const_val) {
+ switch (const_val->special) {
+ case ConstValSpecialRuntime:
+ return false;
+ case ConstValSpecialUndef:
+ return true;
+ case ConstValSpecialStatic:
+ if (const_val->type->id == ZigTypeIdStruct) {
+ for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) {
+ if (!value_is_all_undef(&const_val->data.x_struct.fields[i]))
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+ zig_unreachable();
+}
+
+static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) {
+ ZigType *usize = g->builtin_types.entry_usize;
+ uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref);
+ assert(size_bytes > 0);
+ assert(ptr_align_bytes > 0);
+ // memset uninitialized memory to 0xaa
+ LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
+ LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
+ LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, "");
+ LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
+ ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false);
+}
- assert(instruction->ptr->value.type->id == ZigTypeIdPointer);
+static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
ZigType *ptr_type = instruction->ptr->value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+
+ bool have_init_expr = !value_is_all_undef(&instruction->value->value);
+ if (have_init_expr) {
+ LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
+ LLVMValueRef value = ir_llvm_value(g, instruction->value);
- gen_assign_raw(g, ptr, ptr_type, value);
+ gen_assign_raw(g, ptr, ptr_type, value);
+ }
+ if (ir_want_runtime_safety(g, &instruction->base)) {
+ gen_undef_init(g, get_ptr_align(g, ptr_type), instruction->value->value.type,
+ ir_llvm_value(g, instruction->ptr));
+ }
return nullptr;
}
From dd320eea83ecdc04c0a72e0c7d2fb10ecb4a173d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 26 Oct 2018 16:55:20 -0400
Subject: [PATCH 004/190] copy elision: scalar variable decl with type
inference
```zig
export fn entry() void {
var x = i32(1234);
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca i32, align 4
store i32 1234, i32* %x, align 4, !dbg !48
%0 = bitcast i32* %x to i8*, !dbg !48
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 -86, i64 4, i1 false), !dbg !48
call void @llvm.dbg.declare(metadata i32* %x, metadata !45, metadata !DIExpression()), !dbg !48
ret void, !dbg !49
}
```
---
src/all_types.hpp | 1 +
src/codegen.cpp | 3 +++
src/ir.cpp | 38 +++++++++++++++++++++++++++++---------
3 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 239bf8d992d4..866c9347bff1 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1645,6 +1645,7 @@ struct CodeGen {
ZigType *entry_c_int[CIntTypeCount];
ZigType *entry_c_longdouble;
ZigType *entry_c_void;
+ ZigType *entry_infer;
ZigType *entry_u8;
ZigType *entry_u16;
ZigType *entry_u32;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 90c801f17127..24066b17dd59 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -6597,6 +6597,9 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void");
g->primitive_type_table.put(&g->builtin_types.entry_c_void->name, g->builtin_types.entry_c_void);
}
+ {
+ g->builtin_types.entry_infer = get_opaque_type(g, nullptr, nullptr, "(infer)");
+ }
{
ZigType *entry = new_type_table_entry(ZigTypeIdErrorSet);
diff --git a/src/ir.cpp b/src/ir.cpp
index 9e5d672c95e3..3d8cb6085b53 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -15152,6 +15152,19 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
}
+static void resolve_alloca_inference(IrAnalyze *ira, IrInstructionAlloca *alloca, ZigType *child_type) {
+ // TODO alignment
+ alloca->base.value.type = get_pointer_to_type(ira->codegen, child_type, false);
+}
+
+static void resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type) {
+ assert(base->value.type->id == ZigTypeIdPointer);
+ ZigType *infer_child = base->value.type->data.pointer.child_type;
+ if (base->id == IrInstructionIdAlloca && infer_child == ira->codegen->builtin_types.entry_infer) {
+ resolve_alloca_inference(ira, reinterpret_cast(base), child_type);
+ }
+}
+
static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInstructionStoreResult *instruction) {
IrInstruction *value = instruction->value->child;
if (type_is_invalid(value->value.type))
@@ -15161,6 +15174,8 @@ static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInst
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
+ resolve_possible_alloca_inference(ira, result_loc, value->value.type);
+
// If the type is a scalar value, treat this instruction as a normal store pointer instruction.
if (!type_has_bits(value->value.type) || !handle_is_ptr(value->value.type)) {
return ir_analyze_store_ptr(ira, &instruction->base, result_loc, value);
@@ -20963,20 +20978,25 @@ static IrInstruction *ir_analyze_instruction_result_ptr_cast(IrAnalyze *ira, IrI
}
static IrInstruction *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAlloca *instruction) {
- ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child);
- if (type_is_invalid(child_type))
- return ira->codegen->invalid_instruction;
-
- // TODO alignment
- ZigType *pointer_type = get_pointer_to_type(ira->codegen, child_type, false);
-
IrInstruction *result = ir_build_alloca(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
nullptr, instruction->name_hint);
- result->value.type = pointer_type;
+ IrInstructionAlloca *alloca_result = reinterpret_cast(result);
+
+ if (instruction->child_type == nullptr) {
+ // We use a pointer to a special opaque type to signal that we want type inference.
+ // TODO alignment
+ result->value.type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_infer, false);
+ } else {
+ ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child);
+ if (type_is_invalid(child_type))
+ return ira->codegen->invalid_instruction;
+
+ resolve_alloca_inference(ira, alloca_result, child_type);
+ }
ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
if (fn_entry != nullptr) {
- fn_entry->alloca_list.append(reinterpret_cast(result));
+ fn_entry->alloca_list.append(alloca_result);
}
return result;
}
From 29ce2b68564ccabe1c93fd7e0612caf06680448c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 27 Oct 2018 10:42:09 -0400
Subject: [PATCH 005/190] copy elision: handle alignment
---
src/all_types.hpp | 17 ++++++---
src/codegen.cpp | 6 ++--
src/ir.cpp | 92 +++++++++++++++++++++++++++++------------------
src/ir_print.cpp | 17 ++++++---
4 files changed, 87 insertions(+), 45 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 866c9347bff1..b533f1426a92 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -33,7 +33,7 @@ struct TypeStructField;
struct CodeGen;
struct ConstExprValue;
struct IrInstruction;
-struct IrInstructionAlloca;
+struct IrInstructionAllocaGen;
struct IrBasicBlock;
struct ScopeDecls;
struct ZigWindowsSDK;
@@ -1322,7 +1322,7 @@ struct ZigFn {
AstNode *fn_no_inline_set_node;
AstNode *fn_static_eval_set_node;
- ZigList alloca_list;
+ ZigList alloca_list;
ZigList variable_list;
Buf *section_name;
@@ -2181,7 +2181,8 @@ enum IrInstructionId {
IrInstructionIdResultPtrCast,
IrInstructionIdLoadResult,
IrInstructionIdStoreResult,
- IrInstructionIdAlloca,
+ IrInstructionIdAllocaSrc,
+ IrInstructionIdAllocaGen,
};
struct IrInstruction {
@@ -3323,10 +3324,18 @@ struct IrInstructionResultPtrCast {
IrInstruction *prev_result_loc;
};
-struct IrInstructionAlloca {
+struct IrInstructionAllocaSrc {
IrInstruction base;
IrInstruction *child_type;
+ IrInstruction *align;
+ const char *name_hint;
+};
+
+struct IrInstructionAllocaGen {
+ IrInstruction base;
+
+ uint32_t align;
const char *name_hint;
};
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 24066b17dd59..438abba71956 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5163,6 +5163,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdEnumToInt:
case IrInstructionIdCheckRuntimeScope:
case IrInstructionIdDeclVarSrc:
+ case IrInstructionIdAllocaSrc:
+ case IrInstructionIdAllocaGen:
zig_unreachable();
case IrInstructionIdDeclVarGen:
@@ -5341,8 +5343,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
zig_panic("TODO");
case IrInstructionIdStoreResult:
zig_panic("TODO");
- case IrInstructionIdAlloca:
- return instruction->llvm_value; // handled before function code generation
}
zig_unreachable();
}
@@ -6231,7 +6231,7 @@ static void do_code_gen(CodeGen *g) {
// allocate temporary stack data
for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
- IrInstructionAlloca *instruction = fn_table_entry->alloca_list.at(alloca_i);
+ IrInstructionAllocaGen *instruction = fn_table_entry->alloca_list.at(alloca_i);
ZigType *ptr_type = instruction->base.value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *child_type = ptr_type->data.pointer.child_type;
diff --git a/src/ir.cpp b/src/ir.cpp
index 3d8cb6085b53..8a9f3a11d6cc 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -883,8 +883,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResultBytesToSli
return IrInstructionIdResultBytesToSlice;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) {
- return IrInstructionIdAlloca;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAllocaSrc *) {
+ return IrInstructionIdAllocaSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAllocaGen *) {
+ return IrInstructionIdAllocaGen;
}
template
@@ -2846,18 +2850,30 @@ static IrInstruction *ir_build_result_bytes_to_slice(IrBuilder *irb, Scope *scop
return &instruction->base;
}
-static IrInstruction *ir_build_alloca(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *child_type, const char *name_hint)
+static IrInstruction *ir_build_alloca_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *child_type, IrInstruction *align, const char *name_hint)
{
- IrInstructionAlloca *instruction = ir_build_instruction(irb, scope, source_node);
+ IrInstructionAllocaSrc *instruction = ir_build_instruction(irb, scope, source_node);
instruction->child_type = child_type;
+ instruction->align = align;
instruction->name_hint = name_hint;
if (child_type != nullptr) ir_ref_instruction(child_type, irb->current_basic_block);
+ if (align != nullptr) ir_ref_instruction(align, irb->current_basic_block);
return &instruction->base;
}
+static IrInstructionAllocaGen *ir_create_alloca_gen(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ uint32_t align, const char *name_hint)
+{
+ IrInstructionAllocaGen *instruction = ir_create_instruction(irb, scope, source_node);
+ instruction->align = align;
+ instruction->name_hint = name_hint;
+
+ return instruction;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -5180,7 +5196,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol)));
}
- IrInstruction *alloca = ir_build_alloca(irb, scope, node, type_instruction,
+ IrInstruction *alloca = ir_build_alloca_src(irb, scope, node, type_instruction, align_value,
buf_ptr(variable_declaration->symbol));
// Temporarily set the name of the IrExecutable to the VariableDeclaration
@@ -5501,7 +5517,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime);
Scope *child_scope = elem_var->child_scope;
- IrInstruction *elem_alloca = ir_build_alloca(irb, child_scope, elem_node, elem_var_type, "for_elem");
+ IrInstruction *elem_alloca = ir_build_alloca_src(irb, child_scope, elem_node, elem_var_type, nullptr, "for_elem");
ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, elem_alloca);
AstNode *index_var_source_node;
@@ -5517,7 +5533,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
child_scope = index_var->child_scope;
IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize);
- IrInstruction *index_alloca = ir_build_alloca(irb, child_scope, node, usize, "for_index");
+ IrInstruction *index_alloca = ir_build_alloca_src(irb, child_scope, node, usize, nullptr, "for_index");
IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0);
IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1);
ir_build_store_ptr(irb, child_scope, index_var_source_node, index_alloca, zero);
@@ -5774,7 +5790,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, is_const, is_const, is_shadowable, is_comptime);
- IrInstruction *payload_alloca = ir_build_alloca(irb, scope, node, nullptr, "optional_payload");
+ IrInstruction *payload_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "optional_payload");
IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_result(irb, subexpr_scope, node,
var_ptr_value, payload_alloca);
@@ -5852,7 +5868,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);
- IrInstruction *payload_alloca = ir_build_alloca(irb, scope, node, nullptr, "errunion_payload");
+ IrInstruction *payload_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "errunion_payload");
IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false);
IrInstruction *var_value = var_is_ptr ?
var_ptr_value : ir_build_load_result(irb, subexpr_scope, node, var_ptr_value, payload_alloca);
@@ -5931,7 +5947,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
var_name, is_const, is_const, is_shadowable, var_is_comptime);
child_scope = var->child_scope;
IrInstruction *var_value;
- IrInstruction *payload_alloca = ir_build_alloca(irb, scope, var_symbol_node, nullptr, "switch_payload");
+ IrInstruction *payload_alloca = ir_build_alloca_src(irb, scope, var_symbol_node, nullptr, nullptr, "switch_payload");
if (prong_value) {
IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
var_value = var_is_ptr ?
@@ -6889,7 +6905,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst);
IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type);
ir_build_await_bookkeeping(irb, scope, node, promise_result_type);
- IrInstruction *result_var_alloca = ir_build_alloca(irb, scope, node, promise_result_type, "");
+ IrInstruction *result_var_alloca = ir_build_alloca_src(irb, scope, node, promise_result_type, nullptr, "");
ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, result_var_alloca);
ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, result_var_alloca);
IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle);
@@ -7307,14 +7323,14 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
// TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
- coro_promise_ptr = ir_build_alloca(irb, coro_scope, node, coro_frame_type_value, "");
+ coro_promise_ptr = ir_build_alloca_src(irb, coro_scope, node, coro_frame_type_value, nullptr, "");
ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, coro_promise_ptr);
ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
- irb->exec->await_handle_var_ptr = ir_build_alloca(irb, coro_scope, node, await_handle_type_val, "");
+ irb->exec->await_handle_var_ptr = ir_build_alloca_src(irb, coro_scope, node, await_handle_type_val, nullptr, "");
ir_build_store_ptr(irb, coro_scope, node, irb->exec->await_handle_var_ptr, null_value);
ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr,
irb->exec->await_handle_var_ptr);
@@ -7325,13 +7341,13 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
- IrInstruction *coro_size_var_alloca = ir_build_alloca(irb, coro_scope, node, nullptr, "");
+ IrInstruction *coro_size_var_alloca = ir_build_alloca_src(irb, coro_scope, node, nullptr, nullptr, "");
ir_build_store_ptr(irb, coro_scope, node, coro_size_var_alloca, coro_size);
ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size_var_alloca);
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
ImplicitAllocatorIdArg);
irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
- IrInstruction *coro_allocator_var_alloca = ir_build_alloca(irb, coro_scope, node, nullptr, "");
+ IrInstruction *coro_allocator_var_alloca = ir_build_alloca_src(irb, coro_scope, node, nullptr, nullptr, "");
ir_build_store_ptr(irb, coro_scope, node, coro_allocator_var_alloca, implicit_allocator_ptr);
ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr,
coro_allocator_var_alloca);
@@ -7485,7 +7501,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
- IrInstruction *mem_slice_alloca = ir_build_alloca(irb, scope, node, nullptr, "");
+ IrInstruction *mem_slice_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false,
mem_slice_alloca);
size_t arg_count = 2;
@@ -15152,16 +15168,16 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
}
-static void resolve_alloca_inference(IrAnalyze *ira, IrInstructionAlloca *alloca, ZigType *child_type) {
- // TODO alignment
- alloca->base.value.type = get_pointer_to_type(ira->codegen, child_type, false);
+static void resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *alloca, ZigType *child_type) {
+ alloca->base.value.type = get_pointer_to_type_extra(ira->codegen, child_type, false, false,
+ PtrLenSingle, alloca->align, 0, 0);
}
static void resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type) {
assert(base->value.type->id == ZigTypeIdPointer);
ZigType *infer_child = base->value.type->data.pointer.child_type;
- if (base->id == IrInstructionIdAlloca && infer_child == ira->codegen->builtin_types.entry_infer) {
- resolve_alloca_inference(ira, reinterpret_cast(base), child_type);
+ if (base->id == IrInstructionIdAllocaGen && infer_child == ira->codegen->builtin_types.entry_infer) {
+ resolve_alloca_inference(ira, reinterpret_cast(base), child_type);
}
}
@@ -20977,28 +20993,34 @@ static IrInstruction *ir_analyze_instruction_result_ptr_cast(IrAnalyze *ira, IrI
zig_panic("TODO");
}
-static IrInstruction *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAlloca *instruction) {
- IrInstruction *result = ir_build_alloca(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
- nullptr, instruction->name_hint);
- IrInstructionAlloca *alloca_result = reinterpret_cast(result);
+static IrInstruction *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAllocaSrc *instruction) {
+ uint32_t align = 0;
+ if (instruction->align != nullptr) {
+ if (!ir_resolve_align(ira, instruction->align->child, &align)) {
+ return ira->codegen->invalid_instruction;
+ }
+ }
+
+ IrInstructionAllocaGen *result = ir_create_alloca_gen(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, align, instruction->name_hint);
if (instruction->child_type == nullptr) {
// We use a pointer to a special opaque type to signal that we want type inference.
- // TODO alignment
- result->value.type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_infer, false);
+ result->base.value.type = get_pointer_to_type_extra(ira->codegen,
+ ira->codegen->builtin_types.entry_infer, false, false, PtrLenSingle, align, 0, 0);
} else {
ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child);
if (type_is_invalid(child_type))
return ira->codegen->invalid_instruction;
- resolve_alloca_inference(ira, alloca_result, child_type);
+ resolve_alloca_inference(ira, result, child_type);
}
ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
if (fn_entry != nullptr) {
- fn_entry->alloca_list.append(alloca_result);
+ fn_entry->alloca_list.append(result);
}
- return result;
+ return &result->base;
}
static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
@@ -21014,6 +21036,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdErrWrapPayload:
case IrInstructionIdCast:
case IrInstructionIdDeclVarGen:
+ case IrInstructionIdAllocaGen:
zig_unreachable();
case IrInstructionIdReturn:
@@ -21286,8 +21309,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_result_param(ira, (IrInstructionResultParam *)instruction);
case IrInstructionIdResultPtrCast:
return ir_analyze_instruction_result_ptr_cast(ira, (IrInstructionResultPtrCast *)instruction);
- case IrInstructionIdAlloca:
- return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction);
+ case IrInstructionIdAllocaSrc:
+ return ir_analyze_instruction_alloca(ira, (IrInstructionAllocaSrc *)instruction);
case IrInstructionIdResultBytesToSlice:
zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
@@ -21520,7 +21543,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdResultPtrCast:
case IrInstructionIdResultSliceToBytes:
case IrInstructionIdResultBytesToSlice:
- case IrInstructionIdAlloca:
+ case IrInstructionIdAllocaSrc:
+ case IrInstructionIdAllocaGen:
return false;
case IrInstructionIdAsm:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 640bf9102290..56dcc00c8665 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1357,12 +1357,18 @@ static void ir_print_store_result(IrPrint *irp, IrInstructionStoreResult *instru
fprintf(irp->f, ")");
}
-static void ir_print_alloca(IrPrint *irp, IrInstructionAlloca *instruction) {
- fprintf(irp->f, "Alloca(");
+static void ir_print_alloca_src(IrPrint *irp, IrInstructionAllocaSrc *instruction) {
+ fprintf(irp->f, "AllocaSrc(ty=");
ir_print_other_instruction(irp, instruction->child_type);
+ fprintf(irp->f, ",align=");
+ ir_print_other_instruction(irp, instruction->align);
fprintf(irp->f, ")");
}
+static void ir_print_alloca_gen(IrPrint *irp, IrInstructionAllocaGen *instruction) {
+ fprintf(irp->f, "AllocaGen(align=%" PRIu32 ",name=%s)", instruction->align, instruction->name_hint);
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1809,8 +1815,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdStoreResult:
ir_print_store_result(irp, (IrInstructionStoreResult *)instruction);
break;
- case IrInstructionIdAlloca:
- ir_print_alloca(irp, (IrInstructionAlloca *)instruction);
+ case IrInstructionIdAllocaSrc:
+ ir_print_alloca_src(irp, (IrInstructionAllocaSrc *)instruction);
+ break;
+ case IrInstructionIdAllocaGen:
+ ir_print_alloca_gen(irp, (IrInstructionAllocaGen *)instruction);
break;
}
fprintf(irp->f, "\n");
From 9a60a65b248e0234e2c9b822f3c1ad4ee85fa684 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 27 Oct 2018 11:00:33 -0400
Subject: [PATCH 006/190] copy elision: initialization of variable to constant
```zig
export fn entry() void {
var x = Foo.{
.x = 1,
.y = 2,
};
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca %Foo, align 4
%0 = bitcast %Foo* %x to i8*, !dbg !52
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%Foo* @0 to i8*), i64 8, i1 false), !dbg !52
call void @llvm.dbg.declare(metadata %Foo* %x, metadata !45, metadata !DIExpression()), !dbg !52
ret void, !dbg !53
}
```
---
src/codegen.cpp | 3 +--
src/ir.cpp | 4 +++-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 438abba71956..a09594448017 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3261,8 +3261,7 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir
LLVMValueRef value = ir_llvm_value(g, instruction->value);
gen_assign_raw(g, ptr, ptr_type, value);
- }
- if (ir_want_runtime_safety(g, &instruction->base)) {
+ } else if (ir_want_runtime_safety(g, &instruction->base)) {
gen_undef_init(g, get_ptr_align(g, ptr_type), instruction->value->value.type,
ir_llvm_value(g, instruction->ptr));
}
diff --git a/src/ir.cpp b/src/ir.cpp
index 8a9f3a11d6cc..10776e36339b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -15193,7 +15193,9 @@ static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInst
resolve_possible_alloca_inference(ira, result_loc, value->value.type);
// If the type is a scalar value, treat this instruction as a normal store pointer instruction.
- if (!type_has_bits(value->value.type) || !handle_is_ptr(value->value.type)) {
+ // Or if the value is comptime known, analyze it as a store pointer, so that the
+ // const can be memcpy'd.
+ if (!type_has_bits(value->value.type) || !handle_is_ptr(value->value.type) || instr_is_comptime(value)) {
return ir_analyze_store_ptr(ira, &instruction->base, result_loc, value);
}
From c7c3cfcc6ca59c68fc1b0bb61d2eef92fd7a8415 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 27 Oct 2018 12:04:21 -0400
Subject: [PATCH 007/190] copy elision - var decl init to aggregate fn call
```zig
export fn entry() void {
var y = foo();
}
fn foo() Foo {
return Foo.{
.x = 1,
.y = 2,
};
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%y = alloca %Foo, align 4
call fastcc void @foo(%Foo* sret %y), !dbg !52
call void @llvm.dbg.declare(metadata %Foo* %y, metadata !45, metadata !DIExpression()), !dbg !53
ret void, !dbg !54
}
define internal fastcc void @foo(%Foo* nonnull sret) unnamed_addr #2 !dbg !55 {
Entry:
%1 = bitcast %Foo* %0 to i8*, !dbg !60
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 bitcast (%Foo* @0 to i8*), i64 8, i1 false), !dbg !60
ret void, !dbg !60
}
```
---
src/ir.cpp | 77 ++++++++++++++++++++++++++++++++----------------
src/ir_print.cpp | 3 +-
2 files changed, 54 insertions(+), 26 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 10776e36339b..00f67c549e9e 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1211,16 +1211,12 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
call_instruction->new_stack = new_stack;
call_instruction->result_loc = result_loc;
- if (fn_ref)
- ir_ref_instruction(fn_ref, irb->current_basic_block);
+ if (fn_ref) ir_ref_instruction(fn_ref, irb->current_basic_block);
for (size_t i = 0; i < arg_count; i += 1)
ir_ref_instruction(args[i], irb->current_basic_block);
- if (async_allocator)
- ir_ref_instruction(async_allocator, irb->current_basic_block);
- if (new_stack != nullptr)
- ir_ref_instruction(new_stack, irb->current_basic_block);
-
- ir_ref_instruction(result_loc, irb->current_basic_block);
+ if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block);
+ if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &call_instruction->base;
}
@@ -13108,6 +13104,26 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
return var_ptr_instruction;
}
+static Error resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *alloca, ZigType *child_type) {
+ Error err;
+ if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
+ return err;
+ alloca->base.value.type = get_pointer_to_type_extra(ira->codegen, child_type, false, false,
+ PtrLenSingle, alloca->align, 0, 0);
+ return ErrorNone;
+}
+
+static Error resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type) {
+ Error err;
+ assert(base->value.type->id == ZigTypeIdPointer);
+ ZigType *infer_child = base->value.type->data.pointer.child_type;
+ if (base->id == IrInstructionIdAllocaGen && infer_child == ira->codegen->builtin_types.entry_infer) {
+ if ((err = resolve_alloca_inference(ira, reinterpret_cast(base), child_type)))
+ return err;
+ }
+ return ErrorNone;
+}
+
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref,
IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline)
@@ -13650,10 +13666,20 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
return ira->codegen->invalid_instruction;
}
+ IrInstruction *result_loc = nullptr;
+
+ if (handle_is_ptr(return_type)) {
+ result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if ((err = resolve_possible_alloca_inference(ira, result_loc, return_type)))
+ return ira->codegen->invalid_instruction;
+ }
+
IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
call_instruction->base.scope, call_instruction->base.source_node,
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
- casted_new_stack, nullptr);
+ casted_new_stack, result_loc);
new_call_instruction->value.type = return_type;
return ir_finish_anal(ira, new_call_instruction);
}
@@ -15168,20 +15194,9 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
}
-static void resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *alloca, ZigType *child_type) {
- alloca->base.value.type = get_pointer_to_type_extra(ira->codegen, child_type, false, false,
- PtrLenSingle, alloca->align, 0, 0);
-}
-
-static void resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type) {
- assert(base->value.type->id == ZigTypeIdPointer);
- ZigType *infer_child = base->value.type->data.pointer.child_type;
- if (base->id == IrInstructionIdAllocaGen && infer_child == ira->codegen->builtin_types.entry_infer) {
- resolve_alloca_inference(ira, reinterpret_cast(base), child_type);
- }
-}
-
static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInstructionStoreResult *instruction) {
+ Error err;
+
IrInstruction *value = instruction->value->child;
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
@@ -15190,7 +15205,8 @@ static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInst
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
- resolve_possible_alloca_inference(ira, result_loc, value->value.type);
+ if ((err = resolve_possible_alloca_inference(ira, result_loc, value->value.type)))
+ return ira->codegen->invalid_instruction;
// If the type is a scalar value, treat this instruction as a normal store pointer instruction.
// Or if the value is comptime known, analyze it as a store pointer, so that the
@@ -20984,7 +21000,15 @@ static IrInstruction *ir_analyze_instruction_result_error_union_payload(IrAnalyz
}
static IrInstruction *ir_analyze_instruction_result_return(IrAnalyze *ira, IrInstructionResultReturn *instruction) {
- zig_panic("TODO");
+ ZigFn *fn = exec_fn_entry(ira->new_irb.exec);
+ if (fn == nullptr) {
+ ir_add_error(ira, &instruction->base, buf_sprintf("return outside function"));
+ return ira->codegen->invalid_instruction;
+ }
+ ZigType *result_type = get_pointer_to_type(ira->codegen, fn->type_entry->data.fn.fn_type_id.return_type, false);
+ IrInstruction *result = ir_build_result_return(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
+ result->value.type = result_type;
+ return result;
}
static IrInstruction *ir_analyze_instruction_result_param(IrAnalyze *ira, IrInstructionResultParam *instruction) {
@@ -20996,6 +21020,8 @@ static IrInstruction *ir_analyze_instruction_result_ptr_cast(IrAnalyze *ira, IrI
}
static IrInstruction *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAllocaSrc *instruction) {
+ Error err;
+
uint32_t align = 0;
if (instruction->align != nullptr) {
if (!ir_resolve_align(ira, instruction->align->child, &align)) {
@@ -21015,7 +21041,8 @@ static IrInstruction *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructio
if (type_is_invalid(child_type))
return ira->codegen->invalid_instruction;
- resolve_alloca_inference(ira, result, child_type);
+ if ((err = resolve_alloca_inference(ira, result, child_type)))
+ return ira->codegen->invalid_instruction;
}
ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 56dcc00c8665..24c73c17b226 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -225,7 +225,8 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
fprintf(irp->f, ", ");
ir_print_other_instruction(irp, arg);
}
- fprintf(irp->f, ")");
+ fprintf(irp->f, ") result=");
+ ir_print_other_instruction(irp, call_instruction->result_loc);
}
static void ir_print_cond_br(IrPrint *irp, IrInstructionCondBr *cond_br_instruction) {
From c6dea5fa7c99da7e00c0a90928c40b0cd5b77732 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 27 Oct 2018 12:18:55 -0400
Subject: [PATCH 008/190] copy elision - fn returning result of other fn
```zig
fn bar() Foo {
return foo();
}
```
```llvm
define internal fastcc void @bar(%Foo* nonnull sret) unnamed_addr #2 !dbg !55 {
Entry:
call fastcc void @foo(%Foo* sret %0), !dbg !60
ret void, !dbg !62
}
```
---
src/codegen.cpp | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index a09594448017..8839c71a688f 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -2242,8 +2242,12 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
ZigType *return_type = return_instruction->value->value.type;
if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {
- assert(g->cur_ret_ptr);
- gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
+ // Assume that the result location mechanism populated the value,
+ // unless the value is a comptime const.
+ if (return_instruction->value->value.special == ConstValSpecialStatic) {
+ assert(g->cur_ret_ptr);
+ gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
+ }
LLVMBuildRetVoid(g->builder);
} else if (handle_is_ptr(return_type)) {
LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
@@ -5087,6 +5091,13 @@ static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstr
return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
}
+static LLVMValueRef ir_render_result_return(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultReturn *instruction)
+{
+ assert(g->cur_ret_ptr != nullptr);
+ return g->cur_ret_ptr;
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -5326,9 +5337,9 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
case IrInstructionIdSqrt:
return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
- case IrInstructionIdResultErrorUnionPayload:
- zig_panic("TODO");
case IrInstructionIdResultReturn:
+ return ir_render_result_return(g, executable, (IrInstructionResultReturn *)instruction);
+ case IrInstructionIdResultErrorUnionPayload:
zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
zig_panic("TODO");
From ca69d477f00f4a8b529915e08a6ca0d50508ffaf Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 29 Oct 2018 14:52:54 -0400
Subject: [PATCH 009/190] copy elision - var decl initializing to aggregate
runtime var
```zig
export fn entry() void {
var x = bar();
var y = x;
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca %Foo, align 4
%y = alloca %Foo, align 4
call fastcc void @bar(%Foo* sret %x), !dbg !54
call void @llvm.dbg.declare(metadata %Foo* %x, metadata !45, metadata !DIExpression()), !dbg !55
%0 = bitcast %Foo* %x to i8*, !dbg !56
%1 = bitcast %Foo* %y to i8*, !dbg !56
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 %0, i64 8, i1 false), !dbg !56
call void @llvm.dbg.declare(metadata %Foo* %y, metadata !52, metadata !DIExpression()), !dbg !57
ret void, !dbg !58
}
```
---
src/all_types.hpp | 1 +
src/codegen.cpp | 17 +++---
src/ir.cpp | 130 ++++++++++++++++++++++++++++------------------
src/ir_print.cpp | 7 ++-
4 files changed, 95 insertions(+), 60 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index b533f1426a92..e7e22d814445 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2337,6 +2337,7 @@ struct IrInstructionLoadPtr {
IrInstruction base;
IrInstruction *ptr;
+ IrInstruction *result_loc;
};
struct IrInstructionStorePtr {
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 8839c71a688f..856b567f2392 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -1844,12 +1844,12 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
return nullptr;
}
-static void gen_var_debug_decl(CodeGen *g, ZigVar *var, LLVMValueRef value_ref) {
+static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
assert(var->di_loc_var != nullptr);
AstNode *source_node = var->decl_node;
ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1,
(unsigned)source_node->column + 1, get_di_scope(g, var->parent_scope));
- ZigLLVMInsertDeclareAtEnd(g->dbuilder, value_ref, var->di_loc_var, debug_loc,
+ ZigLLVMInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc,
LLVMGetInsertBlock(g->builder));
}
@@ -2000,7 +2000,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
clear_debug_source_node(g);
gen_store_untyped(g, LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i), var->value_ref, var->align_bytes, false);
if (var->decl_node) {
- gen_var_debug_decl(g, var, var->value_ref);
+ gen_var_debug_decl(g, var);
}
fn_walk->data.inits.gen_i += 1;
break;
@@ -2035,7 +2035,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
}
case FnWalkIdInits:
if (var->decl_node) {
- gen_var_debug_decl(g, var, var->value_ref);
+ gen_var_debug_decl(g, var);
}
fn_walk->data.inits.gen_i += 1;
break;
@@ -2073,7 +2073,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
}
case FnWalkIdInits:
if (var->decl_node) {
- gen_var_debug_decl(g, var, var->value_ref);
+ gen_var_debug_decl(g, var);
}
fn_walk->data.inits.gen_i += 1;
break;
@@ -2111,7 +2111,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
if (var->decl_node) {
- gen_var_debug_decl(g, var, var->value_ref);
+ gen_var_debug_decl(g, var);
}
fn_walk->data.inits.gen_i += 1;
break;
@@ -2206,7 +2206,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
}
if (variable->decl_node) {
- gen_var_debug_decl(g, variable, variable->value_ref);
+ gen_var_debug_decl(g, variable);
}
break;
}
@@ -3188,7 +3188,8 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrI
if (var->ref_count == 0 && g->build_mode != BuildModeDebug)
return nullptr;
- gen_var_debug_decl(g, var, ir_llvm_value(g, instruction->var_ptr));
+ var->value_ref = ir_llvm_value(g, instruction->var_ptr);
+ gen_var_debug_decl(g, var);
return nullptr;
}
diff --git a/src/ir.cpp b/src/ir.cpp
index 00f67c549e9e..4bdbfd3c9c70 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1426,11 +1426,15 @@ static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *sou
return &export_instruction->base;
}
-static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) {
+static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr,
+ IrInstruction *result_loc)
+{
IrInstructionLoadPtr *instruction = ir_build_instruction(irb, scope, source_node);
instruction->ptr = ptr;
+ instruction->result_loc = result_loc;
ir_ref_instruction(ptr, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -3151,7 +3155,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
IrInstruction *err_union_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, new_result_loc);
if (err_union_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr);
+ IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr, nullptr);
IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_val);
IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
@@ -3179,7 +3183,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
if (lval == LValPtr)
return unwrapped_ptr;
else
- return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
+ return ir_build_load_ptr(irb, scope, node, unwrapped_ptr, nullptr);
}
}
zig_unreachable();
@@ -3370,7 +3374,7 @@ static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *no
IrInstruction *lvalue = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
if (lvalue == irb->codegen->invalid_instruction)
return lvalue;
- IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue);
+ IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue, nullptr);
IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
if (op2 == irb->codegen->invalid_instruction)
return op2;
@@ -3473,7 +3477,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode
if (maybe_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr);
+ IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr, nullptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_val);
IrInstruction *is_comptime;
@@ -3651,7 +3655,9 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, Scope *scope, AstNode
return ir_build_const_null(irb, scope, node);
}
-static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeSymbol);
Buf *variable_name = node->data.symbol_expr.symbol;
@@ -3682,7 +3688,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
if (lval == LValPtr)
return var_ptr;
else
- return ir_build_load_ptr(irb, scope, node, var_ptr);
+ return ir_build_load_ptr(irb, scope, node, var_ptr, result_loc);
}
Tld *tld = find_decl(irb->codegen, scope, variable_name);
@@ -5052,7 +5058,7 @@ static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode
if (lval == LValPtr)
return payload_ptr;
- return ir_build_load_ptr(irb, scope, source_node, payload_ptr);
+ return ir_build_load_ptr(irb, scope, source_node, payload_ptr, nullptr);
}
static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -5248,7 +5254,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
LValPtr, nullptr);
if (err_val_ptr == irb->codegen->invalid_instruction)
return err_val_ptr;
- IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
+ IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr, nullptr);
IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
@@ -5338,7 +5344,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
LValPtr, nullptr);
if (maybe_val_ptr == irb->codegen->invalid_instruction)
return maybe_val_ptr;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);
+ IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr, nullptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
@@ -5495,7 +5501,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
if (array_val_ptr == irb->codegen->invalid_instruction)
return array_val_ptr;
- IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr);
+ IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr, nullptr);
IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val);
IrInstruction *elem_var_type;
@@ -5546,7 +5552,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, cond_block);
- IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca);
+ IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca, nullptr);
IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
@@ -5558,7 +5564,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
if (node->data.for_expr.elem_is_ptr) {
elem_val = elem_ptr;
} else {
- elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr);
+ elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr, nullptr);
}
ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_alloca, elem_val));
@@ -5760,7 +5766,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
if (maybe_val_ptr == irb->codegen->invalid_instruction)
return maybe_val_ptr;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
+ IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr, nullptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val);
IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "OptionalThen");
@@ -5842,7 +5848,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
if (err_val_ptr == irb->codegen->invalid_instruction)
return err_val_ptr;
- IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
+ IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr, nullptr);
IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val);
IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");
@@ -6392,7 +6398,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
if (err_union_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr);
+ IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr, nullptr);
IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val);
IrInstruction *is_comptime;
@@ -6431,7 +6437,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
ir_set_cursor_at_end_and_append_block(irb, ok_block);
IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, parent_scope, node, err_union_ptr, false);
- IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr);
+ IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr, nullptr);
IrBasicBlock *after_ok_block = irb->current_basic_block;
ir_build_br(irb, parent_scope, node, end_block, is_comptime);
@@ -6944,7 +6950,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
// If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to,
// because we're about to destroy the memory. So we store it into our result variable.
- IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr);
+ IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr, nullptr);
ir_build_store_ptr(irb, scope, node, result_var_alloca, no_suspend_result);
ir_build_cancel(irb, scope, node, target_inst);
ir_build_br(irb, scope, node, merge_block, const_bool_false);
@@ -7004,7 +7010,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_build_br(irb, scope, node, merge_block, const_bool_false);
ir_set_cursor_at_end_and_append_block(irb, merge_block);
- return ir_build_load_ptr(irb, scope, node, result_var_alloca);
+ return ir_build_load_ptr(irb, scope, node, result_var_alloca, nullptr);
}
static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@@ -7152,7 +7158,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeCharLiteral:
return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval);
case NodeTypeSymbol:
- return ir_gen_symbol(irb, scope, node, lval);
+ return ir_gen_symbol(irb, scope, node, lval, result_loc);
case NodeTypeFnCallExpr:
return ir_gen_fn_call(irb, scope, node, lval, result_loc);
case NodeTypeIfBoolExpr:
@@ -7179,7 +7185,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
if (lval == LValPtr)
return ptr_instruction;
- return ir_build_load_ptr(irb, scope, node, ptr_instruction);
+ return ir_build_load_ptr(irb, scope, node, ptr_instruction, result_loc);
}
case NodeTypePtrDeref: {
AstNode *expr_node = node->data.ptr_deref_expr.target;
@@ -7200,7 +7206,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
if (lval == LValPtr)
return unwrapped_ptr;
- return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
+ return ir_build_load_ptr(irb, scope, node, unwrapped_ptr, result_loc);
}
case NodeTypeBoolLiteral:
return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);
@@ -7349,7 +7355,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
coro_allocator_var_alloca);
Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
- IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr);
+ IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr, nullptr);
IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size);
IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
@@ -7440,7 +7446,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
- IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
+ IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, nullptr);
IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len,
irb->exec->coro_result_field_ptr);
@@ -7452,7 +7458,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
if (irb->codegen->have_err_ret_tracing) {
Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
- IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
+ IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, nullptr);
ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
}
// Before we destroy the coroutine frame, we need to load the target promise into
@@ -7460,7 +7466,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
// otherwise llvm tries to access memory inside the destroyed frame.
IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
irb->exec->await_handle_var_ptr, false);
- IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
+ IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr, nullptr);
ir_build_br(irb, scope, node, check_free_block, const_bool_false);
ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
@@ -7487,7 +7493,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
ImplicitAllocatorIdLocalVar);
IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, free_field_name);
- IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr);
+ IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr, nullptr);
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
@@ -7496,7 +7502,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
- IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
+ IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr, nullptr);
IrInstruction *mem_slice_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false,
mem_slice_alloca);
@@ -11061,7 +11067,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
}
// TODO if the instruction is a const ref instruction we can skip it
IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, ptr);
+ source_instruction->source_node, ptr, nullptr);
load_ptr_instruction->value.type = child_type;
return load_ptr_instruction;
} else {
@@ -15115,13 +15121,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
}
}
-static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) {
- IrInstruction *ptr = load_ptr_instruction->ptr->child;
- if (type_is_invalid(ptr->value.type))
- return ira->codegen->invalid_instruction;
- return ir_get_deref(ira, &load_ptr_instruction->base, ptr);
-}
-
static IrInstruction *ir_analyze_instruction_load_result(IrAnalyze *ira, IrInstructionLoadResult *instruction) {
zig_panic("TODO");
}
@@ -15194,9 +15193,26 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
}
-static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInstructionStoreResult *instruction) {
+static IrInstruction *ir_analyze_store_result(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
+ IrInstruction *result_loc)
+{
Error err;
+ if ((err = resolve_possible_alloca_inference(ira, result_loc, value->value.type)))
+ return ira->codegen->invalid_instruction;
+
+ // If the type is a scalar value, treat this instruction as a normal store pointer instruction.
+ // Or if the value is comptime known, analyze it as a store pointer, so that the
+ // const can be memcpy'd.
+ if (!type_has_bits(value->value.type) || !handle_is_ptr(value->value.type) || instr_is_comptime(value)) {
+ return ir_analyze_store_ptr(ira, source_instr, result_loc, value);
+ }
+
+ // Otherwise, trust that the result location was populated by the expression that computed value.
+ return ir_const_void(ira, source_instr);
+}
+
+static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInstructionStoreResult *instruction) {
IrInstruction *value = instruction->value->child;
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
@@ -15205,18 +15221,32 @@ static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInst
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
- if ((err = resolve_possible_alloca_inference(ira, result_loc, value->value.type)))
+ return ir_analyze_store_result(ira, &instruction->base, value, result_loc);
+}
+
+static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) {
+ Error err;
+
+ IrInstruction *ptr = instruction->ptr->child;
+ if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
- // If the type is a scalar value, treat this instruction as a normal store pointer instruction.
- // Or if the value is comptime known, analyze it as a store pointer, so that the
- // const can be memcpy'd.
- if (!type_has_bits(value->value.type) || !handle_is_ptr(value->value.type) || instr_is_comptime(value)) {
- return ir_analyze_store_ptr(ira, &instruction->base, result_loc, value);
+ IrInstruction *deref = ir_get_deref(ira, &instruction->base, ptr);
+ if (instruction->result_loc == nullptr)
+ return deref;
+
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ if ((err = resolve_possible_alloca_inference(ira, result_loc, deref->value.type)))
+ return ira->codegen->invalid_instruction;
+
+ if (handle_is_ptr(deref->value.type)) {
+ ir_analyze_store_ptr(ira, &instruction->base, result_loc, deref);
}
-
- // Otherwise, trust that the result location was populated by the expression that computed value.
- return ir_const_void(ira, &instruction->base);
+
+ return deref;
}
static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
@@ -16055,7 +16085,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
IrInstruction *result = ir_build_load_ptr(&ira->new_irb,
switch_target_instruction->base.scope, switch_target_instruction->base.source_node,
- target_value_ptr);
+ target_value_ptr, nullptr);
result->value.type = target_type;
return result;
}
@@ -16086,7 +16116,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
}
IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr);
+ switch_target_instruction->base.source_node, target_value_ptr, nullptr);
union_value->value.type = target_type;
IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope,
@@ -16111,7 +16141,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
}
IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr);
+ switch_target_instruction->base.source_node, target_value_ptr, nullptr);
enum_value->value.type = target_type;
return enum_value;
}
@@ -16278,7 +16308,7 @@ static IrInstruction *ir_analyze_instruction_array_len(IrAnalyze *ira,
array_len_instruction->base.source_node, array_value, field);
len_ptr->value.type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_usize, true);
IrInstruction *result = ir_build_load_ptr(&ira->new_irb,
- array_len_instruction->base.scope, array_len_instruction->base.source_node, len_ptr);
+ array_len_instruction->base.scope, array_len_instruction->base.source_node, len_ptr, nullptr);
result->value.type = ira->codegen->builtin_types.entry_usize;
return result;
} else {
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 24c73c17b226..eb0054a20886 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -334,8 +334,11 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {
}
static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
- fprintf(irp->f, "*");
+ fprintf(irp->f, "LoadPtr(ptr=");
ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ",result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
+ fprintf(irp->f, ")");
}
static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
@@ -1351,7 +1354,7 @@ static void ir_print_load_result(IrPrint *irp, IrInstructionLoadResult *instruct
}
static void ir_print_store_result(IrPrint *irp, IrInstructionStoreResult *instruction) {
- fprintf(irp->f, "StoreResult(result_loc=");
+ fprintf(irp->f, "StoreResult(result=");
ir_print_other_instruction(irp, instruction->result_loc);
fprintf(irp->f, ",value=");
ir_print_other_instruction(irp, instruction->value);
From dcf1a5799b184dcd27e28689fe4d9d761a83b557 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 29 Oct 2018 17:14:41 -0400
Subject: [PATCH 010/190] copy elision: implicit cast optional wrap aggregate
```zig
export fn entry() void {
var x: ?Foo = foo();
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca { %Foo, i1 }, align 4
%0 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !57
store i1 true, i1* %0, align 1, !dbg !57
%1 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !57
call fastcc void @foo(%Foo* sret %1), !dbg !58
call void @llvm.dbg.declare(metadata { %Foo, i1 }* %x, metadata !45, metadata !DIExpression()), !dbg !57
ret void, !dbg !59
}
```
---
src/all_types.hpp | 7 ++
src/codegen.cpp | 11 +++
src/ir.cpp | 200 +++++++++++++++++++++++++++++++++-------------
src/ir_print.cpp | 9 +++
4 files changed, 173 insertions(+), 54 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index e7e22d814445..91259cc79f0a 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2173,6 +2173,7 @@ enum IrInstructionId {
IrInstructionIdSqrt,
IrInstructionIdErrSetCast,
IrInstructionIdCheckRuntimeScope,
+ IrInstructionIdResultOptionalPayload,
IrInstructionIdResultErrorUnionPayload,
IrInstructionIdResultReturn,
IrInstructionIdResultBytesToSlice,
@@ -3294,6 +3295,12 @@ struct IrInstructionResultErrorUnionPayload {
IrInstruction *prev_result_loc;
};
+struct IrInstructionResultOptionalPayload {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+};
+
struct IrInstructionResultBytesToSlice {
IrInstruction base;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 856b567f2392..f3aa5eb103f1 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5099,6 +5099,15 @@ static LLVMValueRef ir_render_result_return(CodeGen *g, IrExecutable *executable
return g->cur_ret_ptr;
}
+static LLVMValueRef ir_render_result_optional_payload(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultOptionalPayload *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ LLVMValueRef nonnull_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_null_index, "");
+ gen_store_untyped(g, LLVMConstInt(LLVMInt1Type(), 1, false), nonnull_ptr, 0, false);
+ return LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_child_index, "");
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -5340,6 +5349,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
case IrInstructionIdResultReturn:
return ir_render_result_return(g, executable, (IrInstructionResultReturn *)instruction);
+ case IrInstructionIdResultOptionalPayload:
+ return ir_render_result_optional_payload(g, executable, (IrInstructionResultOptionalPayload *)instruction);
case IrInstructionIdResultErrorUnionPayload:
zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
diff --git a/src/ir.cpp b/src/ir.cpp
index 4bdbfd3c9c70..421d1b27302b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -863,6 +863,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResultErrorUnion
return IrInstructionIdResultErrorUnionPayload;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultOptionalPayload *) {
+ return IrInstructionIdResultOptionalPayload;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionResultReturn *) {
return IrInstructionIdResultReturn;
}
@@ -2797,6 +2801,17 @@ static IrInstruction *ir_build_result_error_union_payload(IrBuilder *irb, Scope
return &instruction->base;
}
+static IrInstruction *ir_build_result_optional_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc)
+{
+ IrInstructionResultOptionalPayload *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_result_return(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionResultReturn *instruction = ir_build_instruction(irb, scope, source_node);
return &instruction->base;
@@ -9807,7 +9822,27 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
return const_val->data.x_ptr.data.fn.fn_entry;
}
-static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
+static IrInstruction *ir_analyze_result_optional_payload(IrAnalyze *ira, IrInstruction *result_loc,
+ ZigType *needed_child_type)
+{
+ if (instr_is_comptime(result_loc)) {
+ zig_panic("TODO comptime ir_analyze_result_optional_payload");
+ }
+ ZigType *old_ptr_type = result_loc->value.type;
+ assert(old_ptr_type->id == ZigTypeIdPointer);
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
+ old_ptr_type->data.pointer.is_const,
+ old_ptr_type->data.pointer.is_volatile,
+ old_ptr_type->data.pointer.ptr_len,
+ 0, 0, 0);
+
+ IrInstruction *result = ir_build_result_optional_payload(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc);
+ result->value.type = new_ptr_type;
+ return result;
+}
+
+static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
ZigType *wanted_type)
{
assert(wanted_type->id == ZigTypeIdOptional);
@@ -10730,12 +10765,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node,
false).id == ConstCastResultIdOk)
{
- return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
+ return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type);
} else if (actual_type->id == ZigTypeIdComptimeInt ||
actual_type->id == ZigTypeIdComptimeFloat)
{
if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) {
- return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
+ return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type);
} else {
return ira->codegen->invalid_instruction;
}
@@ -10772,7 +10807,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
wanted_child_type);
if (type_is_invalid(cast1->value.type))
return ira->codegen->invalid_instruction;
- return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type);
+ return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type);
}
}
}
@@ -11028,6 +11063,110 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig
return ir_analyze_cast(ira, value, expected_type, value);
}
+static Error resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *alloca, ZigType *child_type) {
+ Error err;
+ if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
+ return err;
+ alloca->base.value.type = get_pointer_to_type_extra(ira->codegen, child_type, false, false,
+ PtrLenSingle, alloca->align, 0, 0);
+ return ErrorNone;
+}
+
+static Error resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type) {
+ Error err;
+ assert(base->value.type->id == ZigTypeIdPointer);
+ ZigType *infer_child = base->value.type->data.pointer.child_type;
+ if (base->id == IrInstructionIdAllocaGen && infer_child == ira->codegen->builtin_types.entry_infer) {
+ if ((err = resolve_alloca_inference(ira, reinterpret_cast(base), child_type)))
+ return err;
+ }
+ return ErrorNone;
+}
+
+static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) {
+ assert(ptr_type->id == ZigTypeIdPointer);
+ return get_pointer_to_type_extra(g,
+ ptr_type->data.pointer.child_type,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ ptr_type->data.pointer.ptr_len,
+ new_align,
+ ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
+}
+
+static ZigType *adjust_ptr_child(CodeGen *g, ZigType *ptr_type, ZigType *new_child) {
+ assert(ptr_type->id == ZigTypeIdPointer);
+ return get_pointer_to_type_extra(g,
+ new_child,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ ptr_type->data.pointer.ptr_len,
+ ptr_type->data.pointer.explicit_alignment,
+ ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
+}
+
+static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) {
+ assert(is_slice(slice_type));
+ ZigType *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index].type_entry,
+ new_align);
+ return get_slice_type(g, ptr_type);
+}
+
+static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
+ assert(ptr_type->id == ZigTypeIdPointer);
+ return get_pointer_to_type_extra(g,
+ ptr_type->data.pointer.child_type,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ ptr_len,
+ ptr_type->data.pointer.explicit_alignment,
+ ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
+}
+
+static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *result_loc,
+ ZigType *needed_child_type)
+{
+ Error err;
+ if (type_is_invalid(result_loc->value.type) || type_is_invalid(needed_child_type))
+ return ira->codegen->invalid_instruction;
+ if ((err = resolve_possible_alloca_inference(ira, result_loc, needed_child_type)))
+ return ira->codegen->invalid_instruction;
+
+ if (needed_child_type == nullptr)
+ return result_loc;
+
+ assert(result_loc->value.type->id == ZigTypeIdPointer);
+ ZigType *have_child_type = result_loc->value.type->data.pointer.child_type;
+ if (have_child_type == needed_child_type)
+ return result_loc;
+
+ IrInstruction *source_instr = result_loc;
+ AstNode *source_node = source_instr->source_node;
+
+ // perfect match or non-const to const
+ ConstCastOnly const_cast_result = types_match_const_cast_only(ira, needed_child_type, have_child_type,
+ source_node, false);
+ if (const_cast_result.id == ConstCastResultIdInvalid)
+ return ira->codegen->invalid_instruction;
+ if (const_cast_result.id == ConstCastResultIdOk) {
+ ZigType *new_ptr_type = adjust_ptr_child(ira->codegen, result_loc->value.type, needed_child_type);
+ return ir_analyze_ptr_cast(ira, result_loc, result_loc, new_ptr_type, result_loc);
+ }
+
+ // cast from T to ?T
+ if (have_child_type->id == ZigTypeIdOptional) {
+ if (types_match_const_cast_only(ira, needed_child_type, have_child_type->data.maybe.child_type, source_node,
+ false).id == ConstCastResultIdOk)
+ {
+ return ir_analyze_result_optional_payload(ira, result_loc, needed_child_type);
+ }
+ }
+
+ ErrorMsg *parent_msg = ir_add_error_node(ira, source_node,
+ buf_sprintf("expected type '%s', found '%s'",
+ buf_ptr(&needed_child_type->name),
+ buf_ptr(&have_child_type->name)));
+ report_recursive_error(ira, source_node, &const_cast_result, parent_msg);
+ return ira->codegen->invalid_instruction;
+}
+
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
Error err;
ZigType *type_entry = ptr->value.type;
@@ -13110,26 +13249,6 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
return var_ptr_instruction;
}
-static Error resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *alloca, ZigType *child_type) {
- Error err;
- if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
- return err;
- alloca->base.value.type = get_pointer_to_type_extra(ira->codegen, child_type, false, false,
- PtrLenSingle, alloca->align, 0, 0);
- return ErrorNone;
-}
-
-static Error resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type) {
- Error err;
- assert(base->value.type->id == ZigTypeIdPointer);
- ZigType *infer_child = base->value.type->data.pointer.child_type;
- if (base->id == IrInstructionIdAllocaGen && infer_child == ira->codegen->builtin_types.entry_infer) {
- if ((err = resolve_alloca_inference(ira, reinterpret_cast(base), child_type)))
- return err;
- }
- return ErrorNone;
-}
-
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref,
IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline)
@@ -13675,11 +13794,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
IrInstruction *result_loc = nullptr;
if (handle_is_ptr(return_type)) {
- result_loc = call_instruction->result_loc->child;
+ result_loc = ir_implicit_cast_result(ira, call_instruction->result_loc->child, return_type);
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
- if ((err = resolve_possible_alloca_inference(ira, result_loc, return_type)))
- return ira->codegen->invalid_instruction;
}
IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
@@ -14149,33 +14266,6 @@ static IrInstruction *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructi
return result;
}
-static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) {
- assert(ptr_type->id == ZigTypeIdPointer);
- return get_pointer_to_type_extra(g,
- ptr_type->data.pointer.child_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
- ptr_type->data.pointer.ptr_len,
- new_align,
- ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
-}
-
-static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) {
- assert(is_slice(slice_type));
- ZigType *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index].type_entry,
- new_align);
- return get_slice_type(g, ptr_type);
-}
-
-static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
- assert(ptr_type->id == ZigTypeIdPointer);
- return get_pointer_to_type_extra(g,
- ptr_type->data.pointer.child_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
- ptr_len,
- ptr_type->data.pointer.explicit_alignment,
- ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
-}
-
static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
Error err;
IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->child;
@@ -21096,6 +21186,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdCast:
case IrInstructionIdDeclVarGen:
case IrInstructionIdAllocaGen:
+ case IrInstructionIdResultOptionalPayload:
zig_unreachable();
case IrInstructionIdReturn:
@@ -21596,6 +21687,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdFloatToInt:
case IrInstructionIdBoolToInt:
case IrInstructionIdEnumToInt:
+ case IrInstructionIdResultOptionalPayload:
case IrInstructionIdResultErrorUnionPayload:
case IrInstructionIdResultReturn:
case IrInstructionIdResultParam:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index eb0054a20886..98d29fa79e5e 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1325,6 +1325,12 @@ static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *instruc
fprintf(irp->f, ")");
}
+static void ir_print_result_optional_payload(IrPrint *irp, IrInstructionResultOptionalPayload *instruction) {
+ fprintf(irp->f, "ResultOptionalPayload(");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_result_error_union_payload(IrPrint *irp, IrInstructionResultErrorUnionPayload *instruction) {
fprintf(irp->f, "ResultErrorUnionPayload");
}
@@ -1795,6 +1801,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdDeclVarGen:
ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction);
break;
+ case IrInstructionIdResultOptionalPayload:
+ ir_print_result_optional_payload(irp, (IrInstructionResultOptionalPayload *)instruction);
+ break;
case IrInstructionIdResultErrorUnionPayload:
ir_print_result_error_union_payload(irp, (IrInstructionResultErrorUnionPayload *)instruction);
break;
From ff943d918ffdd49406ec8897bc992f4aadde6fdf Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 29 Oct 2018 18:57:29 -0400
Subject: [PATCH 011/190] copy elision: implicit cast optional wrap when
payload is integer
```zig
export fn entry() void {
var a: i32 = 1234;
var b: ?i32 = a;
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%a = alloca i32, align 4
%b = alloca { i32, i1 }, align 4
store i32 1234, i32* %a, align 4, !dbg !55
call void @llvm.dbg.declare(metadata i32* %a, metadata !45, metadata !DIExpression()), !dbg !55
%0 = load i32, i32* %a, align 4, !dbg !56
%1 = getelementptr inbounds { i32, i1 }, { i32, i1 }* %b, i32 0, i32 1, !dbg !57
store i1 true, i1* %1, align 1, !dbg !57
%2 = getelementptr inbounds { i32, i1 }, { i32, i1 }* %b, i32 0, i32 0, !dbg !57
store i32 %0, i32* %2, align 4, !dbg !57
call void @llvm.dbg.declare(metadata { i32, i1 }* %b, metadata !48, metadata !DIExpression()), !dbg !57
ret void, !dbg !58
}
```
---
src/all_types.hpp | 1 -
src/ir.cpp | 116 +++++++++++++++++++---------------------------
src/ir_print.cpp | 2 -
3 files changed, 48 insertions(+), 71 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 91259cc79f0a..3d004be788eb 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2338,7 +2338,6 @@ struct IrInstructionLoadPtr {
IrInstruction base;
IrInstruction *ptr;
- IrInstruction *result_loc;
};
struct IrInstructionStorePtr {
diff --git a/src/ir.cpp b/src/ir.cpp
index 48448bdfdc4e..08646d908582 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1430,15 +1430,11 @@ static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *sou
return &export_instruction->base;
}
-static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr,
- IrInstruction *result_loc)
-{
+static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) {
IrInstructionLoadPtr *instruction = ir_build_instruction(irb, scope, source_node);
instruction->ptr = ptr;
- instruction->result_loc = result_loc;
ir_ref_instruction(ptr, irb->current_basic_block);
- if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -3170,7 +3166,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
IrInstruction *err_union_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, new_result_loc);
if (err_union_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr, nullptr);
+ IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr);
IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_val);
IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
@@ -3198,7 +3194,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
if (lval == LValPtr)
return unwrapped_ptr;
else
- return ir_build_load_ptr(irb, scope, node, unwrapped_ptr, nullptr);
+ return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
}
}
zig_unreachable();
@@ -3389,7 +3385,7 @@ static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *no
IrInstruction *lvalue = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
if (lvalue == irb->codegen->invalid_instruction)
return lvalue;
- IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue, nullptr);
+ IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue);
IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
if (op2 == irb->codegen->invalid_instruction)
return op2;
@@ -3492,7 +3488,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode
if (maybe_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr, nullptr);
+ IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_val);
IrInstruction *is_comptime;
@@ -3703,7 +3699,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
if (lval == LValPtr)
return var_ptr;
else
- return ir_build_load_ptr(irb, scope, node, var_ptr, result_loc);
+ return ir_build_load_ptr(irb, scope, node, var_ptr);
}
Tld *tld = find_decl(irb->codegen, scope, variable_name);
@@ -5073,7 +5069,7 @@ static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode
if (lval == LValPtr)
return payload_ptr;
- return ir_build_load_ptr(irb, scope, source_node, payload_ptr, nullptr);
+ return ir_build_load_ptr(irb, scope, source_node, payload_ptr);
}
static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -5269,7 +5265,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
LValPtr, nullptr);
if (err_val_ptr == irb->codegen->invalid_instruction)
return err_val_ptr;
- IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr, nullptr);
+ IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
@@ -5359,7 +5355,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
LValPtr, nullptr);
if (maybe_val_ptr == irb->codegen->invalid_instruction)
return maybe_val_ptr;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr, nullptr);
+ IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
@@ -5516,7 +5512,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
if (array_val_ptr == irb->codegen->invalid_instruction)
return array_val_ptr;
- IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr, nullptr);
+ IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr);
IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val);
IrInstruction *elem_var_type;
@@ -5567,7 +5563,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, cond_block);
- IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca, nullptr);
+ IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca);
IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
@@ -5579,7 +5575,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
if (node->data.for_expr.elem_is_ptr) {
elem_val = elem_ptr;
} else {
- elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr, nullptr);
+ elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr);
}
ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_alloca, elem_val));
@@ -5781,7 +5777,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
if (maybe_val_ptr == irb->codegen->invalid_instruction)
return maybe_val_ptr;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr, nullptr);
+ IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val);
IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "OptionalThen");
@@ -5863,7 +5859,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
if (err_val_ptr == irb->codegen->invalid_instruction)
return err_val_ptr;
- IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr, nullptr);
+ IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val);
IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");
@@ -6413,7 +6409,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
if (err_union_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr, nullptr);
+ IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr);
IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val);
IrInstruction *is_comptime;
@@ -6452,7 +6448,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
ir_set_cursor_at_end_and_append_block(irb, ok_block);
IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, parent_scope, node, err_union_ptr, false);
- IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr, nullptr);
+ IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr);
IrBasicBlock *after_ok_block = irb->current_basic_block;
ir_build_br(irb, parent_scope, node, end_block, is_comptime);
@@ -6965,7 +6961,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
// If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to,
// because we're about to destroy the memory. So we store it into our result variable.
- IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr, nullptr);
+ IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr);
ir_build_store_ptr(irb, scope, node, result_var_alloca, no_suspend_result);
ir_build_cancel(irb, scope, node, target_inst);
ir_build_br(irb, scope, node, merge_block, const_bool_false);
@@ -7025,7 +7021,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_build_br(irb, scope, node, merge_block, const_bool_false);
ir_set_cursor_at_end_and_append_block(irb, merge_block);
- return ir_build_load_ptr(irb, scope, node, result_var_alloca, nullptr);
+ return ir_build_load_ptr(irb, scope, node, result_var_alloca);
}
static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@@ -7200,7 +7196,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
if (lval == LValPtr)
return ptr_instruction;
- return ir_build_load_ptr(irb, scope, node, ptr_instruction, result_loc);
+ return ir_build_load_ptr(irb, scope, node, ptr_instruction);
}
case NodeTypePtrDeref: {
AstNode *expr_node = node->data.ptr_deref_expr.target;
@@ -7221,7 +7217,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
if (lval == LValPtr)
return unwrapped_ptr;
- return ir_build_load_ptr(irb, scope, node, unwrapped_ptr, result_loc);
+ return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
}
case NodeTypeBoolLiteral:
return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);
@@ -7370,7 +7366,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
coro_allocator_var_alloca);
Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
- IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr, nullptr);
+ IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr);
IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size);
IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
@@ -7461,7 +7457,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
- IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, nullptr);
+ IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len,
irb->exec->coro_result_field_ptr);
@@ -7473,7 +7469,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
if (irb->codegen->have_err_ret_tracing) {
Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
- IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, nullptr);
+ IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
}
// Before we destroy the coroutine frame, we need to load the target promise into
@@ -7481,7 +7477,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
// otherwise llvm tries to access memory inside the destroyed frame.
IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
irb->exec->await_handle_var_ptr, false);
- IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr, nullptr);
+ IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
ir_build_br(irb, scope, node, check_free_block, const_bool_false);
ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
@@ -7508,7 +7504,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
ImplicitAllocatorIdLocalVar);
IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, free_field_name);
- IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr, nullptr);
+ IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr);
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
@@ -7517,7 +7513,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
- IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr, nullptr);
+ IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
IrInstruction *mem_slice_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false,
mem_slice_alloca);
@@ -11139,7 +11135,7 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
// cast from T to ?T
if (have_child_type->id == ZigTypeIdOptional) {
- if (types_match_const_cast_only(ira, needed_child_type, have_child_type->data.maybe.child_type, source_node,
+ if (types_match_const_cast_only(ira, have_child_type->data.maybe.child_type, needed_child_type, source_node,
false).id == ConstCastResultIdOk)
{
return ir_analyze_result_optional_payload(ira, result_loc, needed_child_type);
@@ -11148,8 +11144,8 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
ErrorMsg *parent_msg = ir_add_error_node(ira, source_node,
buf_sprintf("expected type '%s', found '%s'",
- buf_ptr(&needed_child_type->name),
- buf_ptr(&have_child_type->name)));
+ buf_ptr(&have_child_type->name),
+ buf_ptr(&needed_child_type->name)));
report_recursive_error(ira, source_node, &const_cast_result, parent_msg);
return ira->codegen->invalid_instruction;
}
@@ -11193,7 +11189,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
}
// TODO if the instruction is a const ref instruction we can skip it
IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, ptr, nullptr);
+ source_instruction->source_node, ptr);
load_ptr_instruction->value.type = child_type;
return load_ptr_instruction;
} else {
@@ -15271,22 +15267,23 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
}
static IrInstruction *ir_analyze_store_result(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
- IrInstruction *result_loc)
+ IrInstruction *uncasted_result_loc)
{
- Error err;
+ if (instr_is_comptime(value)) {
+ // No need for the ir_implicit_cast_result for comptime values.
+ return ir_analyze_store_ptr(ira, source_instr, uncasted_result_loc, value);
+ }
+
+ if (value->id == IrInstructionIdCall && handle_is_ptr(value->value.type)) {
+ // Elide this copy because it was the sret pointer in the function call.
+ return ir_const_void(ira, source_instr);
+ }
- if ((err = resolve_possible_alloca_inference(ira, result_loc, value->value.type)))
+ IrInstruction *result_loc = ir_implicit_cast_result(ira, uncasted_result_loc, value->value.type);
+ if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
- // If the type is a scalar value, treat this instruction as a normal store pointer instruction.
- // Or if the value is comptime known, analyze it as a store pointer, so that the
- // const can be memcpy'd.
- if (!type_has_bits(value->value.type) || !handle_is_ptr(value->value.type) || instr_is_comptime(value)) {
- return ir_analyze_store_ptr(ira, source_instr, result_loc, value);
- }
-
- // Otherwise, trust that the result location was populated by the expression that computed value.
- return ir_const_void(ira, source_instr);
+ return ir_analyze_store_ptr(ira, source_instr, result_loc, value);
}
static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInstructionStoreResult *instruction) {
@@ -15302,28 +15299,11 @@ static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInst
}
static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) {
- Error err;
-
IrInstruction *ptr = instruction->ptr->child;
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
- IrInstruction *deref = ir_get_deref(ira, &instruction->base, ptr);
- if (instruction->result_loc == nullptr)
- return deref;
-
- IrInstruction *result_loc = instruction->result_loc->child;
- if (type_is_invalid(result_loc->value.type))
- return ira->codegen->invalid_instruction;
-
- if ((err = resolve_possible_alloca_inference(ira, result_loc, deref->value.type)))
- return ira->codegen->invalid_instruction;
-
- if (handle_is_ptr(deref->value.type)) {
- ir_analyze_store_ptr(ira, &instruction->base, result_loc, deref);
- }
-
- return deref;
+ return ir_get_deref(ira, &instruction->base, ptr);
}
static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
@@ -16162,7 +16142,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
IrInstruction *result = ir_build_load_ptr(&ira->new_irb,
switch_target_instruction->base.scope, switch_target_instruction->base.source_node,
- target_value_ptr, nullptr);
+ target_value_ptr);
result->value.type = target_type;
return result;
}
@@ -16193,7 +16173,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
}
IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr, nullptr);
+ switch_target_instruction->base.source_node, target_value_ptr);
union_value->value.type = target_type;
IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope,
@@ -16218,7 +16198,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
}
IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr, nullptr);
+ switch_target_instruction->base.source_node, target_value_ptr);
enum_value->value.type = target_type;
return enum_value;
}
@@ -16385,7 +16365,7 @@ static IrInstruction *ir_analyze_instruction_array_len(IrAnalyze *ira,
array_len_instruction->base.source_node, array_value, field);
len_ptr->value.type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_usize, true);
IrInstruction *result = ir_build_load_ptr(&ira->new_irb,
- array_len_instruction->base.scope, array_len_instruction->base.source_node, len_ptr, nullptr);
+ array_len_instruction->base.scope, array_len_instruction->base.source_node, len_ptr);
result->value.type = ira->codegen->builtin_types.entry_usize;
return result;
} else {
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 98d29fa79e5e..b02381d08673 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -336,8 +336,6 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {
static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
fprintf(irp->f, "LoadPtr(ptr=");
ir_print_other_instruction(irp, instruction->ptr);
- fprintf(irp->f, ",result=");
- ir_print_other_instruction(irp, instruction->result_loc);
fprintf(irp->f, ")");
}
From d0dcfea68a3cfa96f34b26c9eefe76f1b2ca94de Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 00:43:06 -0400
Subject: [PATCH 012/190] copy elision: if bool expression with aggregate
```zig
export fn entry() void {
var y = true;
var z = bar();
var x = if (y) foo() else z;
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%y = alloca i1, align 1
%z = alloca %Foo, align 4
%x = alloca %Foo, align 4
store i1 true, i1* %y, align 1, !dbg !57
call void @llvm.dbg.declare(metadata i1* %y, metadata !45, metadata !DIExpression()), !dbg !58
call fastcc void @bar(%Foo* sret %z), !dbg !59
call void @llvm.dbg.declare(metadata %Foo* %z, metadata !48, metadata !DIExpression()), !dbg !60
%0 = load i1, i1* %y, align 1, !dbg !61
br i1 %0, label %Then, label %Else, !dbg !61
Then: ; preds = %Entry
call fastcc void @foo(%Foo* sret %x), !dbg !62
br label %EndIf, !dbg !63
Else: ; preds = %Entry
%1 = bitcast %Foo* %z to i8*, !dbg !64
%2 = bitcast %Foo* %x to i8*, !dbg !64
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %1, i64 8, i1 false), !dbg !64
br label %EndIf, !dbg !63
EndIf: ; preds = %Else, %Then
call void @llvm.dbg.declare(metadata %Foo* %x, metadata !55, metadata !DIExpression()), !dbg !65
ret void, !dbg !66
}
```
---
src/all_types.hpp | 10 ++
src/codegen.cpp | 22 +++
src/ir.cpp | 375 +++++++++++++++++++++++++---------------------
src/ir_print.cpp | 13 +-
4 files changed, 247 insertions(+), 173 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 3d004be788eb..ae411793ecca 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2184,6 +2184,7 @@ enum IrInstructionId {
IrInstructionIdStoreResult,
IrInstructionIdAllocaSrc,
IrInstructionIdAllocaGen,
+ IrInstructionIdAssertNonError,
};
struct IrInstruction {
@@ -2338,6 +2339,7 @@ struct IrInstructionLoadPtr {
IrInstruction base;
IrInstruction *ptr;
+ IrInstruction *result_loc;
};
struct IrInstructionStorePtr {
@@ -3011,6 +3013,8 @@ struct IrInstructionTypeName {
enum LVal {
LValNone,
LValPtr,
+ LValErrorUnion,
+ LValOptional,
};
struct IrInstructionDeclRef {
@@ -3346,6 +3350,12 @@ struct IrInstructionAllocaGen {
const char *name_hint;
};
+struct IrInstructionAssertNonError {
+ IrInstruction base;
+
+ IrInstruction *err_code;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index f3aa5eb103f1..2d2dc4c7a03b 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5108,6 +5108,26 @@ static LLVMValueRef ir_render_result_optional_payload(CodeGen *g, IrExecutable *
return LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_child_index, "");
}
+static LLVMValueRef ir_render_assert_non_error(CodeGen *g, IrExecutable *executable,
+ IrInstructionAssertNonError *instruction)
+{
+ if (!ir_want_runtime_safety(g, &instruction->base) || g->errors_by_index.length <= 1) {
+ return nullptr;
+ }
+ LLVMValueRef err_val = ir_llvm_value(g, instruction->err_code);
+ 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_val, "UnwrapErrError");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");
+ LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, err_block);
+ gen_safety_crash_for_err(g, err_val, instruction->base.scope);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ return nullptr;
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -5351,6 +5371,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_result_return(g, executable, (IrInstructionResultReturn *)instruction);
case IrInstructionIdResultOptionalPayload:
return ir_render_result_optional_payload(g, executable, (IrInstructionResultOptionalPayload *)instruction);
+ case IrInstructionIdAssertNonError:
+ return ir_render_assert_non_error(g, executable, (IrInstructionAssertNonError *)instruction);
case IrInstructionIdResultErrorUnionPayload:
zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
diff --git a/src/ir.cpp b/src/ir.cpp
index 08646d908582..7a1f76b3fb8b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -895,6 +895,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAllocaGen *) {
return IrInstructionIdAllocaGen;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonError *) {
+ return IrInstructionIdAssertNonError;
+}
+
template
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate(1);
@@ -1430,11 +1434,15 @@ static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *sou
return &export_instruction->base;
}
-static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) {
+static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr,
+ IrInstruction *result_loc)
+{
IrInstructionLoadPtr *instruction = ir_build_instruction(irb, scope, source_node);
instruction->ptr = ptr;
+ instruction->result_loc = result_loc;
ir_ref_instruction(ptr, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -2786,17 +2794,6 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope,
return &instruction->base;
}
-static IrInstruction *ir_build_result_error_union_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *prev_result_loc)
-{
- IrInstructionResultErrorUnionPayload *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->prev_result_loc = prev_result_loc;
-
- ir_ref_instruction(prev_result_loc, irb->current_basic_block);
-
- return &instruction->base;
-}
-
static IrInstruction *ir_build_result_optional_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *prev_result_loc)
{
@@ -2885,6 +2882,17 @@ static IrInstructionAllocaGen *ir_create_alloca_gen(IrBuilder *irb, Scope *scope
return instruction;
}
+static IrInstruction *ir_build_assert_non_error(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *err_code)
+{
+ IrInstructionAssertNonError *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->err_code = err_code;
+
+ ir_ref_instruction(err_code, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -3074,6 +3082,34 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime);
}
+static IrInstruction *ir_gen_lval_ptr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
+ switch (lval) {
+ case LValNone:
+ return ir_build_load_ptr(irb, scope, node, result_loc, nullptr);
+ case LValPtr:
+ return result_loc;
+ case LValErrorUnion:
+ case LValOptional:
+ zig_unreachable();
+ }
+ zig_unreachable();
+}
+
+static IrInstruction *ir_gen_value(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc, IrInstruction *value)
+{
+ if (result_loc != nullptr) {
+ ir_build_store_ptr(irb, scope, node, result_loc, value);
+ if (lval != LValNone) {
+ assert(lval != LValPtr);
+ return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
+ }
+ }
+ return ir_lval_wrap(irb, scope, value, lval);
+}
+
static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc)
{
@@ -3162,12 +3198,10 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
case ReturnKindError:
{
assert(expr_node);
- IrInstruction *new_result_loc = ir_build_result_error_union_payload(irb, scope, node, result_loc);
- IrInstruction *err_union_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, new_result_loc);
- if (err_union_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *err_val = ir_gen_node(irb, expr_node, scope, LValErrorUnion, result_loc);
+ if (err_val == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr);
- IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_val);
+ IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_val);
IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
@@ -3182,7 +3216,6 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
ir_set_cursor_at_end_and_append_block(irb, return_block);
if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
- IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
if (irb->codegen->have_err_ret_tracing && !should_inline) {
ir_build_save_err_ret_addr(irb, scope, node);
}
@@ -3190,11 +3223,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
}
ir_set_cursor_at_end_and_append_block(irb, continue_block);
- IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);
- if (lval == LValPtr)
- return unwrapped_ptr;
- else
- return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
+ return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
}
}
zig_unreachable();
@@ -3375,7 +3404,6 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node)
if (lvalue == irb->codegen->invalid_instruction || rvalue == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- ir_build_store_result(irb, scope, node, lvalue, rvalue);
return ir_build_const_void(irb, scope, node);
}
@@ -3385,7 +3413,7 @@ static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *no
IrInstruction *lvalue = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
if (lvalue == irb->codegen->invalid_instruction)
return lvalue;
- IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue);
+ IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue, nullptr);
IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
if (op2 == irb->codegen->invalid_instruction)
return op2;
@@ -3478,19 +3506,18 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
}
-static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node, IrInstruction *result_loc) {
+static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeBinOpExpr);
AstNode *op1_node = node->data.bin_op_expr.op1;
AstNode *op2_node = node->data.bin_op_expr.op2;
- IrInstruction *maybe_ptr = ir_gen_node(irb, op1_node, parent_scope, LValPtr, nullptr);
- if (maybe_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *is_non_null = ir_gen_node(irb, op1_node, parent_scope, LValOptional, result_loc);
+ if (is_non_null == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr);
- IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_val);
-
IrInstruction *is_comptime;
if (ir_should_inline(irb->exec, parent_scope)) {
is_comptime = ir_build_const_bool(irb, parent_scope, node, true);
@@ -3498,33 +3525,19 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode
is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_non_null);
}
- IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "OptionalNonNull");
- IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "OptionalNull");
- IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OptionalEnd");
- ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime);
+ IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "OrElseNull");
+ IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OrElseEnd");
+ ir_build_cond_br(irb, parent_scope, node, is_non_null, end_block, null_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, null_block);
IrInstruction *null_result = ir_gen_node(irb, op2_node, parent_scope, LValNone, result_loc);
if (null_result == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrBasicBlock *after_null_block = irb->current_basic_block;
if (!instr_is_unreachable(null_result))
ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime));
- ir_set_cursor_at_end_and_append_block(irb, ok_block);
- IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, parent_scope, node, maybe_ptr, false);
- IrInstruction *unwrapped_payload = ir_build_load_result(irb, parent_scope, node, unwrapped_ptr, result_loc);
- IrBasicBlock *after_ok_block = irb->current_basic_block;
- ir_build_br(irb, parent_scope, node, end_block, is_comptime);
-
ir_set_cursor_at_end_and_append_block(irb, end_block);
- IrInstruction **incoming_values = allocate(2);
- incoming_values[0] = null_result;
- incoming_values[1] = unwrapped_payload;
- IrBasicBlock **incoming_blocks = allocate(2);
- incoming_blocks[0] = after_null_block;
- incoming_blocks[1] = after_ok_block;
- return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
+ return ir_gen_lval_ptr(irb, parent_scope, node, lval, result_loc);
}
static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@@ -3544,7 +3557,9 @@ static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, As
return ir_build_error_union(irb, parent_scope, node, err_set, payload);
}
-static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
+static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeBinOpExpr);
BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
@@ -3552,87 +3567,87 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node,
case BinOpTypeInvalid:
zig_unreachable();
case BinOpTypeAssign:
- return ir_gen_assign(irb, scope, node);
+ return ir_lval_wrap(irb, scope, ir_gen_assign(irb, scope, node), lval);
case BinOpTypeAssignTimes:
- return ir_gen_assign_op(irb, scope, node, IrBinOpMult);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMult), lval);
case BinOpTypeAssignTimesWrap:
- return ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap), lval);
case BinOpTypeAssignDiv:
- return ir_gen_assign_op(irb, scope, node, IrBinOpDivUnspecified);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpDivUnspecified), lval);
case BinOpTypeAssignMod:
- return ir_gen_assign_op(irb, scope, node, IrBinOpRemUnspecified);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpRemUnspecified), lval);
case BinOpTypeAssignPlus:
- return ir_gen_assign_op(irb, scope, node, IrBinOpAdd);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpAdd), lval);
case BinOpTypeAssignPlusWrap:
- return ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap), lval);
case BinOpTypeAssignMinus:
- return ir_gen_assign_op(irb, scope, node, IrBinOpSub);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpSub), lval);
case BinOpTypeAssignMinusWrap:
- return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap), lval);
case BinOpTypeAssignBitShiftLeft:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy), lval);
case BinOpTypeAssignBitShiftRight:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy), lval);
case BinOpTypeAssignBitAnd:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd), lval);
case BinOpTypeAssignBitXor:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinXor), lval);
case BinOpTypeAssignBitOr:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinOr), lval);
case BinOpTypeAssignMergeErrorSets:
- return ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets);
+ return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets), lval);
case BinOpTypeBoolOr:
- return ir_gen_bool_or(irb, scope, node);
+ return ir_lval_wrap(irb, scope, ir_gen_bool_or(irb, scope, node), lval);
case BinOpTypeBoolAnd:
- return ir_gen_bool_and(irb, scope, node);
+ return ir_lval_wrap(irb, scope, ir_gen_bool_and(irb, scope, node), lval);
case BinOpTypeCmpEq:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq), lval);
case BinOpTypeCmpNotEq:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq), lval);
case BinOpTypeCmpLessThan:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan), lval);
case BinOpTypeCmpGreaterThan:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan), lval);
case BinOpTypeCmpLessOrEq:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq), lval);
case BinOpTypeCmpGreaterOrEq:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq), lval);
case BinOpTypeBinOr:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr), lval);
case BinOpTypeBinXor:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor), lval);
case BinOpTypeBinAnd:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd), lval);
case BinOpTypeBitShiftLeft:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy), lval);
case BinOpTypeBitShiftRight:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy), lval);
case BinOpTypeAdd:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd), lval);
case BinOpTypeAddWrap:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap), lval);
case BinOpTypeSub:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpSub);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpSub), lval);
case BinOpTypeSubWrap:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap), lval);
case BinOpTypeMult:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpMult);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMult), lval);
case BinOpTypeMultWrap:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap), lval);
case BinOpTypeDiv:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpDivUnspecified);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpDivUnspecified), lval);
case BinOpTypeMod:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpRemUnspecified);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpRemUnspecified), lval);
case BinOpTypeArrayCat:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat), lval);
case BinOpTypeArrayMult:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult), lval);
case BinOpTypeMergeErrorSets:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
+ return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets), lval);
case BinOpTypeUnwrapOptional:
- return ir_gen_orelse(irb, scope, node, result_loc);
+ return ir_gen_orelse(irb, scope, node, lval, result_loc);
case BinOpTypeErrorUnion:
- return ir_gen_error_union(irb, scope, node);
+ return ir_lval_wrap(irb, scope, ir_gen_error_union(irb, scope, node), lval);
}
zig_unreachable();
}
@@ -3685,11 +3700,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
ZigType *primitive_type = get_primitive_type(irb->codegen, variable_name);
if (primitive_type != nullptr) {
IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type);
- if (lval == LValPtr) {
- return ir_build_ref(irb, scope, node, value, false, false);
- } else {
- return value;
- }
+ return ir_lval_wrap(irb, scope, value, lval);
}
ScopeFnDef *crossed_fndef_scope;
@@ -3698,8 +3709,8 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
IrInstruction *var_ptr = ir_build_var_ptr_x(irb, scope, node, var, crossed_fndef_scope);
if (lval == LValPtr)
return var_ptr;
- else
- return ir_build_load_ptr(irb, scope, node, var_ptr);
+ IrInstruction *loaded = ir_build_load_ptr(irb, scope, node, var_ptr, result_loc);
+ return ir_lval_wrap(irb, scope, loaded, lval);
}
Tld *tld = find_decl(irb->codegen, scope, variable_name);
@@ -4949,7 +4960,6 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope, LValNone, result_loc);
if (then_expr_result == irb->codegen->invalid_instruction)
return then_expr_result;
- IrBasicBlock *after_then_block = irb->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
@@ -4962,19 +4972,11 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
} else {
else_expr_result = ir_build_const_void(irb, scope, node);
}
- IrBasicBlock *after_else_block = irb->current_basic_block;
if (!instr_is_unreachable(else_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, endif_block);
- IrInstruction **incoming_values = allocate(2);
- incoming_values[0] = then_expr_result;
- incoming_values[1] = else_expr_result;
- IrBasicBlock **incoming_blocks = allocate(2);
- incoming_blocks[0] = after_then_block;
- incoming_blocks[1] = after_else_block;
-
- return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
+ return ir_build_load_ptr(irb, scope, node, result_loc, nullptr);
}
static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id) {
@@ -5055,21 +5057,16 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
ptr_len, align_value, bit_offset_start, host_int_bytes);
}
-static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node,
- LVal lval)
+static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ AstNode *expr_node, LVal lval, IrInstruction *result_loc)
{
- IrInstruction *err_union_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, nullptr);
- if (err_union_ptr == irb->codegen->invalid_instruction)
- return irb->codegen->invalid_instruction;
-
- IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, source_node, err_union_ptr, true);
- if (payload_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *err_val = ir_gen_node(irb, expr_node, scope, LValErrorUnion, result_loc);
+ if (err_val == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- if (lval == LValPtr)
- return payload_ptr;
+ ir_build_assert_non_error(irb, scope, source_node, err_val);
- return ir_build_load_ptr(irb, scope, source_node, payload_ptr);
+ return ir_gen_lval_ptr(irb, scope, source_node, lval, result_loc);
}
static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -5222,7 +5219,6 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
if (init_value == irb->codegen->invalid_instruction)
return init_value;
- ir_build_store_result(irb, scope, node, alloca, init_value);
return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, alloca);
}
@@ -5265,7 +5261,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
LValPtr, nullptr);
if (err_val_ptr == irb->codegen->invalid_instruction)
return err_val_ptr;
- IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
+ IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr, nullptr);
IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
@@ -5355,7 +5351,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
LValPtr, nullptr);
if (maybe_val_ptr == irb->codegen->invalid_instruction)
return maybe_val_ptr;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);
+ IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr, nullptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
@@ -5512,7 +5508,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
if (array_val_ptr == irb->codegen->invalid_instruction)
return array_val_ptr;
- IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr);
+ IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr, nullptr);
IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val);
IrInstruction *elem_var_type;
@@ -5563,7 +5559,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, cond_block);
- IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca);
+ IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca, nullptr);
IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
@@ -5575,7 +5571,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
if (node->data.for_expr.elem_is_ptr) {
elem_val = elem_ptr;
} else {
- elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr);
+ elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr, nullptr);
}
ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_alloca, elem_val));
@@ -5623,9 +5619,12 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
return ir_build_phi(irb, parent_scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
}
-static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeBoolLiteral);
- return ir_build_const_bool(irb, scope, node, node->data.bool_literal.value);
+ IrInstruction *const_bool_val = ir_build_const_bool(irb, scope, node, node->data.bool_literal.value);
+ return ir_gen_value(irb, scope, node, lval, result_loc, const_bool_val);
}
static IrInstruction *ir_gen_string_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -5777,7 +5776,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
if (maybe_val_ptr == irb->codegen->invalid_instruction)
return maybe_val_ptr;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
+ IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr, nullptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val);
IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "OptionalThen");
@@ -5859,7 +5858,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
if (err_val_ptr == irb->codegen->invalid_instruction)
return err_val_ptr;
- IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
+ IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr, nullptr);
IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val);
IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");
@@ -6388,7 +6387,9 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node,
return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true, result_loc);
}
-static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node, IrInstruction *result_loc) {
+static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeUnwrapErrorExpr);
AstNode *op1_node = node->data.unwrap_err_expr.op1;
@@ -6402,15 +6403,14 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name)));
return irb->codegen->invalid_instruction;
}
- return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LValNone);
+ return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, lval, result_loc);
}
- IrInstruction *err_union_ptr = ir_gen_node(irb, op1_node, parent_scope, LValPtr, nullptr);
- if (err_union_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *err_val = ir_gen_node(irb, op1_node, parent_scope, LValErrorUnion, result_loc);
+ if (err_val == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr);
- IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val);
+ IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_val);
IrInstruction *is_comptime;
if (ir_should_inline(irb->exec, parent_scope)) {
@@ -6419,10 +6419,9 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_err);
}
- IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "CatchOk");
IrBasicBlock *err_block = ir_create_basic_block(irb, parent_scope, "CatchError");
IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "CatchEnd");
- ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, is_comptime);
+ ir_build_cond_br(irb, parent_scope, node, is_err, err_block, end_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, err_block);
Scope *err_scope;
@@ -6434,7 +6433,6 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
ZigVar *var = ir_create_var(irb, node, parent_scope, var_name,
is_const, is_const, is_shadowable, is_comptime);
err_scope = var->child_scope;
- IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr);
ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
} else {
err_scope = parent_scope;
@@ -6442,24 +6440,11 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
IrInstruction *err_result = ir_gen_node(irb, op2_node, err_scope, LValNone, result_loc);
if (err_result == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrBasicBlock *after_err_block = irb->current_basic_block;
if (!instr_is_unreachable(err_result))
ir_mark_gen(ir_build_br(irb, err_scope, node, end_block, is_comptime));
- ir_set_cursor_at_end_and_append_block(irb, ok_block);
- IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, parent_scope, node, err_union_ptr, false);
- IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr);
- IrBasicBlock *after_ok_block = irb->current_basic_block;
- ir_build_br(irb, parent_scope, node, end_block, is_comptime);
-
ir_set_cursor_at_end_and_append_block(irb, end_block);
- IrInstruction **incoming_values = allocate(2);
- incoming_values[0] = err_result;
- incoming_values[1] = unwrapped_payload;
- IrBasicBlock **incoming_blocks = allocate(2);
- incoming_blocks[0] = after_err_block;
- incoming_blocks[1] = after_ok_block;
- return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
+ return ir_gen_lval_ptr(irb, parent_scope, node, lval, result_loc);
}
static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *outer_scope, Scope *inner_scope) {
@@ -6961,7 +6946,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
// If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to,
// because we're about to destroy the memory. So we store it into our result variable.
- IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr);
+ IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr, nullptr);
ir_build_store_ptr(irb, scope, node, result_var_alloca, no_suspend_result);
ir_build_cancel(irb, scope, node, target_inst);
ir_build_br(irb, scope, node, merge_block, const_bool_false);
@@ -7021,7 +7006,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_build_br(irb, scope, node, merge_block, const_bool_false);
ir_set_cursor_at_end_and_append_block(irb, merge_block);
- return ir_build_load_ptr(irb, scope, node, result_var_alloca);
+ return ir_build_load_ptr(irb, scope, node, result_var_alloca, nullptr);
}
static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@@ -7161,7 +7146,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeGroupedExpr:
return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_loc);
case NodeTypeBinOpExpr:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node, result_loc), lval);
+ return ir_gen_bin_op(irb, scope, node, lval, result_loc);
case NodeTypeIntLiteral:
return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval);
case NodeTypeFloatLiteral:
@@ -7196,7 +7181,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
if (lval == LValPtr)
return ptr_instruction;
- return ir_build_load_ptr(irb, scope, node, ptr_instruction);
+ return ir_build_load_ptr(irb, scope, node, ptr_instruction, nullptr);
}
case NodeTypePtrDeref: {
AstNode *expr_node = node->data.ptr_deref_expr.target;
@@ -7217,10 +7202,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
if (lval == LValPtr)
return unwrapped_ptr;
- return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
+ return ir_build_load_ptr(irb, scope, node, unwrapped_ptr, nullptr);
}
case NodeTypeBoolLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);
+ return ir_gen_bool_literal(irb, scope, node, lval, result_loc);
case NodeTypeArrayType:
return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval);
case NodeTypePointerType:
@@ -7256,7 +7241,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeSliceExpr:
return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node, result_loc), lval);
case NodeTypeUnwrapErrorExpr:
- return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node, result_loc), lval);
+ return ir_gen_catch(irb, scope, node, lval, result_loc);
case NodeTypeContainerDecl:
return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
case NodeTypeFnProto:
@@ -7366,7 +7351,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
coro_allocator_var_alloca);
Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
- IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr);
+ IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr, nullptr);
IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size);
IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
@@ -7457,7 +7442,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
- IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
+ IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, nullptr);
IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len,
irb->exec->coro_result_field_ptr);
@@ -7469,7 +7454,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
if (irb->codegen->have_err_ret_tracing) {
Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
- IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
+ IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, nullptr);
ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
}
// Before we destroy the coroutine frame, we need to load the target promise into
@@ -7477,7 +7462,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
// otherwise llvm tries to access memory inside the destroyed frame.
IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
irb->exec->await_handle_var_ptr, false);
- IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
+ IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr, nullptr);
ir_build_br(irb, scope, node, check_free_block, const_bool_false);
ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
@@ -7504,7 +7489,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
ImplicitAllocatorIdLocalVar);
IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, free_field_name);
- IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr);
+ IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr, nullptr);
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
@@ -7513,7 +7498,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
- IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
+ IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr, nullptr);
IrInstruction *mem_slice_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false,
mem_slice_alloca);
@@ -11189,7 +11174,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
}
// TODO if the instruction is a const ref instruction we can skip it
IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, ptr);
+ source_instruction->source_node, ptr, nullptr);
load_ptr_instruction->value.type = child_type;
return load_ptr_instruction;
} else {
@@ -15201,6 +15186,10 @@ static IrInstruction *ir_analyze_instruction_load_result(IrAnalyze *ira, IrInstr
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *ptr, IrInstruction *value)
{
+ Error err;
+ if ((err = resolve_possible_alloca_inference(ira, ptr, value->value.type)))
+ return ira->codegen->invalid_instruction;
+
if (ptr->value.type->id != ZigTypeIdPointer) {
ir_add_error(ira, ptr,
buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
@@ -15303,7 +15292,17 @@ static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruct
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
- return ir_get_deref(ira, &instruction->base, ptr);
+ IrInstruction *deref = ir_get_deref(ira, &instruction->base, ptr);
+ if (instruction->result_loc == nullptr)
+ return deref;
+
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ ir_analyze_store_ptr(ira, &instruction->base, result_loc, deref);
+
+ return deref;
}
static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
@@ -16142,7 +16141,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
IrInstruction *result = ir_build_load_ptr(&ira->new_irb,
switch_target_instruction->base.scope, switch_target_instruction->base.source_node,
- target_value_ptr);
+ target_value_ptr, nullptr);
result->value.type = target_type;
return result;
}
@@ -16173,7 +16172,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
}
IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr);
+ switch_target_instruction->base.source_node, target_value_ptr, nullptr);
union_value->value.type = target_type;
IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope,
@@ -16198,7 +16197,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
}
IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr);
+ switch_target_instruction->base.source_node, target_value_ptr, nullptr);
enum_value->value.type = target_type;
return enum_value;
}
@@ -16365,7 +16364,7 @@ static IrInstruction *ir_analyze_instruction_array_len(IrAnalyze *ira,
array_len_instruction->base.source_node, array_value, field);
len_ptr->value.type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_usize, true);
IrInstruction *result = ir_build_load_ptr(&ira->new_irb,
- array_len_instruction->base.scope, array_len_instruction->base.source_node, len_ptr);
+ array_len_instruction->base.scope, array_len_instruction->base.source_node, len_ptr, nullptr);
result->value.type = ira->codegen->builtin_types.entry_usize;
return result;
} else {
@@ -19532,6 +19531,33 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
}
+static IrInstruction *ir_analyze_instruction_assert_non_error(IrAnalyze *ira,
+ IrInstructionAssertNonError *instruction)
+{
+ IrInstruction *err_code = instruction->err_code->child;
+ if (type_is_invalid(err_code->value.type))
+ return ira->codegen->invalid_instruction;
+
+ assert(err_code->value.type->id == ZigTypeIdErrorSet);
+
+ if (instr_is_comptime(err_code)) {
+ ConstExprValue *err_val = ir_resolve_const(ira, err_code, UndefBad);
+ if (err_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ ErrorTableEntry *err = err_val->data.x_err_set;
+ if (err != nullptr) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
+ return ira->codegen->invalid_instruction;
+ }
+ return ir_const_void(ira, &instruction->base);
+ }
+
+ ir_build_assert_non_error(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, err_code);
+ return ir_const_void(ira, &instruction->base);
+}
+
static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) {
Error err;
AstNode *proto_node = instruction->base.source_node;
@@ -21310,6 +21336,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_unwrap_err_code(ira, (IrInstructionUnwrapErrCode *)instruction);
case IrInstructionIdUnwrapErrPayload:
return ir_analyze_instruction_unwrap_err_payload(ira, (IrInstructionUnwrapErrPayload *)instruction);
+ case IrInstructionIdAssertNonError:
+ return ir_analyze_instruction_assert_non_error(ira, (IrInstructionAssertNonError *)instruction);
case IrInstructionIdFnProto:
return ir_analyze_instruction_fn_proto(ira, (IrInstructionFnProto *)instruction);
case IrInstructionIdTestComptime:
@@ -21562,12 +21590,12 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdAtomicRmw:
case IrInstructionIdLoadResult:
case IrInstructionIdStoreResult:
+ case IrInstructionIdAssertNonError:
return true;
case IrInstructionIdPhi:
case IrInstructionIdUnOp:
case IrInstructionIdBinOp:
- case IrInstructionIdLoadPtr:
case IrInstructionIdConst:
case IrInstructionIdCast:
case IrInstructionIdContainerInitList:
@@ -21665,6 +21693,9 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdAllocaGen:
return false;
+ case IrInstructionIdLoadPtr:
+ return reinterpret_cast(instruction)->result_loc != nullptr;
+
case IrInstructionIdAsm:
{
IrInstructionAsm *asm_instruction = (IrInstructionAsm *)instruction;
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index b02381d08673..7fa77445a4cd 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -336,6 +336,8 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {
static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
fprintf(irp->f, "LoadPtr(ptr=");
ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ",result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
fprintf(irp->f, ")");
}
@@ -1370,13 +1372,19 @@ static void ir_print_alloca_src(IrPrint *irp, IrInstructionAllocaSrc *instructio
ir_print_other_instruction(irp, instruction->child_type);
fprintf(irp->f, ",align=");
ir_print_other_instruction(irp, instruction->align);
- fprintf(irp->f, ")");
+ fprintf(irp->f, ",name=%s)", instruction->name_hint);
}
static void ir_print_alloca_gen(IrPrint *irp, IrInstructionAllocaGen *instruction) {
fprintf(irp->f, "AllocaGen(align=%" PRIu32 ",name=%s)", instruction->align, instruction->name_hint);
}
+static void ir_print_assert_non_error(IrPrint *irp, IrInstructionAssertNonError *instruction) {
+ fprintf(irp->f, "AssertNonError(");
+ ir_print_other_instruction(irp, instruction->err_code);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1832,6 +1840,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdAllocaGen:
ir_print_alloca_gen(irp, (IrInstructionAllocaGen *)instruction);
break;
+ case IrInstructionIdAssertNonError:
+ ir_print_assert_non_error(irp, (IrInstructionAssertNonError *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
From 7608505c5709b3403ecfc0173bff5f7c038f7423 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 01:06:00 -0400
Subject: [PATCH 013/190] copy elision: implicit cast payload to error union
```zig
export fn entry() void {
var x: error!Foo = foo();
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca { i16, %Foo }, align 4
%0 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 0, !dbg !56
store i16 0, i16* %0, align 2, !dbg !56
%1 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 1, !dbg !56
call fastcc void @foo(%Foo* sret %1), !dbg !57
call void @llvm.dbg.declare(metadata { i16, %Foo }* %x, metadata !45, metadata !DIExpression()), !dbg !56
ret void, !dbg !58
}
```
---
src/codegen.cpp | 14 ++++++++++++--
src/ir.cpp | 44 +++++++++++++++++++++++++++++++++++++++-----
src/ir_print.cpp | 4 +++-
3 files changed, 54 insertions(+), 8 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 2d2dc4c7a03b..8e5a0b20f711 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5108,6 +5108,16 @@ static LLVMValueRef ir_render_result_optional_payload(CodeGen *g, IrExecutable *
return LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_child_index, "");
}
+static LLVMValueRef ir_render_result_error_union_payload(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultErrorUnionPayload *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, err_union_err_index, "");
+ LLVMTypeRef err_type_ref = g->builtin_types.entry_global_error_set->type_ref;
+ gen_store_untyped(g, LLVMConstInt(err_type_ref, 0, false), err_val_ptr, 0, false);
+ return LLVMBuildStructGEP(g->builder, prev_result_loc, err_union_payload_index, "");
+}
+
static LLVMValueRef ir_render_assert_non_error(CodeGen *g, IrExecutable *executable,
IrInstructionAssertNonError *instruction)
{
@@ -5371,10 +5381,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_result_return(g, executable, (IrInstructionResultReturn *)instruction);
case IrInstructionIdResultOptionalPayload:
return ir_render_result_optional_payload(g, executable, (IrInstructionResultOptionalPayload *)instruction);
+ case IrInstructionIdResultErrorUnionPayload:
+ return ir_render_result_error_union_payload(g, executable, (IrInstructionResultErrorUnionPayload *)instruction);
case IrInstructionIdAssertNonError:
return ir_render_assert_non_error(g, executable, (IrInstructionAssertNonError *)instruction);
- case IrInstructionIdResultErrorUnionPayload:
- zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
zig_panic("TODO");
case IrInstructionIdResultBytesToSlice:
diff --git a/src/ir.cpp b/src/ir.cpp
index 7a1f76b3fb8b..d401770629ab 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -2805,6 +2805,17 @@ static IrInstruction *ir_build_result_optional_payload(IrBuilder *irb, Scope *sc
return &instruction->base;
}
+static IrInstruction *ir_build_result_error_union_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc)
+{
+ IrInstructionResultErrorUnionPayload *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_result_return(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionResultReturn *instruction = ir_build_instruction(irb, scope, source_node);
return &instruction->base;
@@ -9812,10 +9823,7 @@ static IrInstruction *ir_analyze_result_optional_payload(IrAnalyze *ira, IrInstr
ZigType *old_ptr_type = result_loc->value.type;
assert(old_ptr_type->id == ZigTypeIdPointer);
ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
- old_ptr_type->data.pointer.is_const,
- old_ptr_type->data.pointer.is_volatile,
- old_ptr_type->data.pointer.ptr_len,
- 0, 0, 0);
+ false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
IrInstruction *result = ir_build_result_optional_payload(&ira->new_irb, result_loc->scope,
result_loc->source_node, result_loc);
@@ -9823,6 +9831,23 @@ static IrInstruction *ir_analyze_result_optional_payload(IrAnalyze *ira, IrInstr
return result;
}
+static IrInstruction *ir_analyze_result_error_union_payload(IrAnalyze *ira, IrInstruction *result_loc,
+ ZigType *needed_child_type)
+{
+ if (instr_is_comptime(result_loc)) {
+ zig_panic("TODO comptime ir_analyze_result_error_union_payload");
+ }
+ ZigType *old_ptr_type = result_loc->value.type;
+ assert(old_ptr_type->id == ZigTypeIdPointer);
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
+ false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+
+ IrInstruction *result = ir_build_result_error_union_payload(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc);
+ result->value.type = new_ptr_type;
+ return result;
+}
+
static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
ZigType *wanted_type)
{
@@ -10787,7 +10812,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);
}
- // cast from child type of error type to error type
+ // cast from T to E!T
if (wanted_type->id == ZigTypeIdErrorUnion) {
if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,
source_node, false).id == ConstCastResultIdOk)
@@ -11127,6 +11152,15 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
}
}
+ // cast from T to E!T
+ if (have_child_type->id == ZigTypeIdErrorUnion) {
+ if (types_match_const_cast_only(ira, have_child_type->data.error_union.payload_type, needed_child_type,
+ source_node, false).id == ConstCastResultIdOk)
+ {
+ return ir_analyze_result_error_union_payload(ira, result_loc, needed_child_type);
+ }
+ }
+
ErrorMsg *parent_msg = ir_add_error_node(ira, source_node,
buf_sprintf("expected type '%s', found '%s'",
buf_ptr(&have_child_type->name),
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 7fa77445a4cd..647e77d2a04f 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1332,7 +1332,9 @@ static void ir_print_result_optional_payload(IrPrint *irp, IrInstructionResultOp
}
static void ir_print_result_error_union_payload(IrPrint *irp, IrInstructionResultErrorUnionPayload *instruction) {
- fprintf(irp->f, "ResultErrorUnionPayload");
+ fprintf(irp->f, "ResultErrorUnionPayload(");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ")");
}
static void ir_print_result_return(IrPrint *irp, IrInstructionResultReturn *instruction) {
From 5106eac6dc0bc6fc4cf565acddd5441e98b3da6b Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 01:28:55 -0400
Subject: [PATCH 014/190] copy elision: implicit cast error set to error union
```zig
export fn entry() void {
var x: error!Foo = fail();
}
```
```llvm
define void @entry() #2 !dbg !42 {
Entry:
%x = alloca { i16, %Foo }, align 4
%0 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 0, !dbg !57
%1 = call fastcc i16 @fail(), !dbg !58
store i16 %1, i16* %0, align 2, !dbg !58
ret void, !dbg !59
}
```
---
src/all_types.hpp | 7 ++
src/codegen.cpp | 10 +++
src/ir.cpp | 178 ++++++++++++++++++++++++++++------------------
src/ir_print.cpp | 9 +++
4 files changed, 135 insertions(+), 69 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index ae411793ecca..0cfd27899933 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2175,6 +2175,7 @@ enum IrInstructionId {
IrInstructionIdCheckRuntimeScope,
IrInstructionIdResultOptionalPayload,
IrInstructionIdResultErrorUnionPayload,
+ IrInstructionIdResultErrorUnionCode,
IrInstructionIdResultReturn,
IrInstructionIdResultBytesToSlice,
IrInstructionIdResultSliceToBytes,
@@ -3298,6 +3299,12 @@ struct IrInstructionResultErrorUnionPayload {
IrInstruction *prev_result_loc;
};
+struct IrInstructionResultErrorUnionCode {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+};
+
struct IrInstructionResultOptionalPayload {
IrInstruction base;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 8e5a0b20f711..0f0166be1670 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5118,6 +5118,14 @@ static LLVMValueRef ir_render_result_error_union_payload(CodeGen *g, IrExecutabl
return LLVMBuildStructGEP(g->builder, prev_result_loc, err_union_payload_index, "");
}
+static LLVMValueRef ir_render_result_error_union_code(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultErrorUnionCode *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ // TODO write 0xaa in debug mode to the undefined payload
+ return LLVMBuildStructGEP(g->builder, prev_result_loc, err_union_err_index, "");
+}
+
static LLVMValueRef ir_render_assert_non_error(CodeGen *g, IrExecutable *executable,
IrInstructionAssertNonError *instruction)
{
@@ -5383,6 +5391,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_result_optional_payload(g, executable, (IrInstructionResultOptionalPayload *)instruction);
case IrInstructionIdResultErrorUnionPayload:
return ir_render_result_error_union_payload(g, executable, (IrInstructionResultErrorUnionPayload *)instruction);
+ case IrInstructionIdResultErrorUnionCode:
+ return ir_render_result_error_union_code(g, executable, (IrInstructionResultErrorUnionCode *)instruction);
case IrInstructionIdAssertNonError:
return ir_render_assert_non_error(g, executable, (IrInstructionAssertNonError *)instruction);
case IrInstructionIdResultSliceToBytes:
diff --git a/src/ir.cpp b/src/ir.cpp
index d401770629ab..2d3fca9a835e 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -863,6 +863,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResultErrorUnion
return IrInstructionIdResultErrorUnionPayload;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultErrorUnionCode *) {
+ return IrInstructionIdResultErrorUnionCode;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionResultOptionalPayload *) {
return IrInstructionIdResultOptionalPayload;
}
@@ -2816,6 +2820,17 @@ static IrInstruction *ir_build_result_error_union_payload(IrBuilder *irb, Scope
return &instruction->base;
}
+static IrInstruction *ir_build_result_error_union_code(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc)
+{
+ IrInstructionResultErrorUnionCode *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_result_return(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionResultReturn *instruction = ir_build_instruction(irb, scope, source_node);
return &instruction->base;
@@ -9848,6 +9863,23 @@ static IrInstruction *ir_analyze_result_error_union_payload(IrAnalyze *ira, IrIn
return result;
}
+static IrInstruction *ir_analyze_result_error_union_code(IrAnalyze *ira, IrInstruction *result_loc,
+ ZigType *needed_child_type)
+{
+ if (instr_is_comptime(result_loc)) {
+ zig_panic("TODO comptime ir_analyze_result_error_union_code");
+ }
+ ZigType *old_ptr_type = result_loc->value.type;
+ assert(old_ptr_type->id == ZigTypeIdPointer);
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
+ false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+
+ IrInstruction *result = ir_build_result_error_union_code(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc);
+ result->value.type = new_ptr_type;
+ return result;
+}
+
static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
ZigType *wanted_type)
{
@@ -11161,6 +11193,13 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
}
}
+ // cast from E to E!T
+ if (have_child_type->id == ZigTypeIdErrorUnion &&
+ needed_child_type->id == ZigTypeIdErrorSet)
+ {
+ return ir_analyze_result_error_union_code(ira, result_loc, needed_child_type);
+ }
+
ErrorMsg *parent_msg = ir_add_error_node(ira, source_node,
buf_sprintf("expected type '%s', found '%s'",
buf_ptr(&have_child_type->name),
@@ -13251,6 +13290,67 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
return var_ptr_instruction;
}
+static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *ptr, IrInstruction *value)
+{
+ Error err;
+ if ((err = resolve_possible_alloca_inference(ira, ptr, value->value.type)))
+ return ira->codegen->invalid_instruction;
+
+ if (ptr->value.type->id != ZigTypeIdPointer) {
+ ir_add_error(ira, ptr,
+ buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
+ return ir_const_void(ira, source_instr);
+ }
+
+ if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
+ ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
+ return ira->codegen->invalid_instruction;
+ }
+
+ ZigType *child_type = ptr->value.type->data.pointer.child_type;
+ IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type);
+ if (casted_value == ira->codegen->invalid_instruction)
+ return ira->codegen->invalid_instruction;
+
+ if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
+ if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
+ ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
+ return ira->codegen->invalid_instruction;
+ }
+ if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
+ if (instr_is_comptime(casted_value)) {
+ ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, source_instr->source_node);
+ if (dest_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (dest_val->special != ConstValSpecialRuntime) {
+ *dest_val = casted_value->value;
+ if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
+ ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
+ }
+ return ir_const_void(ira, source_instr);
+ }
+ }
+ ir_add_error(ira, source_instr,
+ buf_sprintf("cannot store runtime value in compile time variable"));
+ ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
+ dest_val->type = ira->codegen->builtin_types.entry_invalid;
+
+ return ira->codegen->invalid_instruction;
+ }
+ }
+
+ IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
+ ptr, casted_value);
+ result->value.type = ira->codegen->builtin_types.entry_void;
+ return result;
+}
+
+
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref,
IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline)
@@ -13795,7 +13895,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
IrInstruction *result_loc = nullptr;
- if (handle_is_ptr(return_type)) {
+ if (call_instruction->result_loc != nullptr) {
result_loc = ir_implicit_cast_result(ira, call_instruction->result_loc->child, return_type);
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
@@ -13806,6 +13906,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
casted_new_stack, result_loc);
new_call_instruction->value.type = return_type;
+
+ if (!handle_is_ptr(return_type) && result_loc != nullptr) {
+ ir_analyze_store_ptr(ira, &call_instruction->base, result_loc, new_call_instruction);
+ }
+
return ir_finish_anal(ira, new_call_instruction);
}
@@ -15217,66 +15322,6 @@ static IrInstruction *ir_analyze_instruction_load_result(IrAnalyze *ira, IrInstr
zig_panic("TODO");
}
-static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
- IrInstruction *ptr, IrInstruction *value)
-{
- Error err;
- if ((err = resolve_possible_alloca_inference(ira, ptr, value->value.type)))
- return ira->codegen->invalid_instruction;
-
- if (ptr->value.type->id != ZigTypeIdPointer) {
- ir_add_error(ira, ptr,
- buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
- return ir_const_void(ira, source_instr);
- }
-
- if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
- ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
- return ira->codegen->invalid_instruction;
- }
-
- ZigType *child_type = ptr->value.type->data.pointer.child_type;
- IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type);
- if (casted_value == ira->codegen->invalid_instruction)
- return ira->codegen->invalid_instruction;
-
- if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
- if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
- ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
- return ira->codegen->invalid_instruction;
- }
- if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
- if (instr_is_comptime(casted_value)) {
- ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, source_instr->source_node);
- if (dest_val == nullptr)
- return ira->codegen->invalid_instruction;
- if (dest_val->special != ConstValSpecialRuntime) {
- *dest_val = casted_value->value;
- if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
- ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
- }
- return ir_const_void(ira, source_instr);
- }
- }
- ir_add_error(ira, source_instr,
- buf_sprintf("cannot store runtime value in compile time variable"));
- ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
- dest_val->type = ira->codegen->builtin_types.entry_invalid;
-
- return ira->codegen->invalid_instruction;
- }
- }
-
- IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
- ptr, casted_value);
- result->value.type = ira->codegen->builtin_types.entry_void;
- return result;
-}
-
static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) {
IrInstruction *ptr = instruction->ptr->child;
if (type_is_invalid(ptr->value.type))
@@ -21140,12 +21185,6 @@ static IrInstruction *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira,
return ir_const_void(ira, &instruction->base);
}
-static IrInstruction *ir_analyze_instruction_result_error_union_payload(IrAnalyze *ira,
- IrInstructionResultErrorUnionPayload *instruction)
-{
- zig_panic("TODO");
-}
-
static IrInstruction *ir_analyze_instruction_result_return(IrAnalyze *ira, IrInstructionResultReturn *instruction) {
ZigFn *fn = exec_fn_entry(ira->new_irb.exec);
if (fn == nullptr) {
@@ -21214,6 +21253,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdDeclVarGen:
case IrInstructionIdAllocaGen:
case IrInstructionIdResultOptionalPayload:
+ case IrInstructionIdResultErrorUnionPayload:
+ case IrInstructionIdResultErrorUnionCode:
zig_unreachable();
case IrInstructionIdReturn:
@@ -21480,8 +21521,6 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);
case IrInstructionIdCheckRuntimeScope:
return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction);
- case IrInstructionIdResultErrorUnionPayload:
- return ir_analyze_instruction_result_error_union_payload(ira, (IrInstructionResultErrorUnionPayload *)instruction);
case IrInstructionIdResultReturn:
return ir_analyze_instruction_result_return(ira, (IrInstructionResultReturn *)instruction);
case IrInstructionIdResultParam:
@@ -21718,6 +21757,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdEnumToInt:
case IrInstructionIdResultOptionalPayload:
case IrInstructionIdResultErrorUnionPayload:
+ case IrInstructionIdResultErrorUnionCode:
case IrInstructionIdResultReturn:
case IrInstructionIdResultParam:
case IrInstructionIdResultPtrCast:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 647e77d2a04f..1966fff747d0 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1337,6 +1337,12 @@ static void ir_print_result_error_union_payload(IrPrint *irp, IrInstructionResul
fprintf(irp->f, ")");
}
+static void ir_print_result_error_union_code(IrPrint *irp, IrInstructionResultErrorUnionCode *instruction) {
+ fprintf(irp->f, "ResultErrorUnionCode(");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_result_return(IrPrint *irp, IrInstructionResultReturn *instruction) {
fprintf(irp->f, "ResultReturn");
}
@@ -1815,6 +1821,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdResultErrorUnionPayload:
ir_print_result_error_union_payload(irp, (IrInstructionResultErrorUnionPayload *)instruction);
break;
+ case IrInstructionIdResultErrorUnionCode:
+ ir_print_result_error_union_code(irp, (IrInstructionResultErrorUnionCode *)instruction);
+ break;
case IrInstructionIdResultReturn:
ir_print_result_return(irp, (IrInstructionResultReturn *)instruction);
break;
From e1dfb5f4ae5d6cec9dc8ece0ff20053f25a4e91a Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 01:47:35 -0400
Subject: [PATCH 015/190] copy elision: double implicit cast
```zig
export fn entry() void {
var x: error!?Foo = bar();
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca { i16, { %Foo, i1 } }, align 4
%0 = getelementptr inbounds { i16, { %Foo, i1 } }, { i16, { %Foo, i1 } }* %x, i32 0, i32 0, !dbg !61
store i16 0, i16* %0, align 2, !dbg !61
%1 = getelementptr inbounds { i16, { %Foo, i1 } }, { i16, { %Foo, i1 } }* %x, i32 0, i32 1, !dbg !61
%2 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %1, i32 0, i32 1, !dbg !61
store i1 true, i1* %2, align 1, !dbg !61
%3 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %1, i32 0, i32 0, !dbg !61
call fastcc void @bar(%Foo* sret %3), !dbg !62
ret void, !dbg !63
}
```
---
src/ir.cpp | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 2d3fca9a835e..8a027681e87a 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -4935,9 +4935,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
size_t arg_count = node->data.fn_call_expr.params.length;
IrInstruction **args = allocate(arg_count);
for (size_t i = 0; i < arg_count; i += 1) {
- IrInstruction *param_result_loc = ir_build_result_param(irb, scope, node, fn_ref, i);
AstNode *arg_node = node->data.fn_call_expr.params.at(i);
- args[i] = ir_gen_node(irb, arg_node, scope, LValNone, param_result_loc);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, nullptr);
if (args[i] == irb->codegen->invalid_instruction)
return args[i];
}
@@ -10885,7 +10884,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
}
- // cast from error set to error union type
+ // cast from E to E!T
if (wanted_type->id == ZigTypeIdErrorUnion &&
actual_type->id == ZigTypeIdErrorSet)
{
@@ -11200,6 +11199,27 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
return ir_analyze_result_error_union_code(ira, result_loc, needed_child_type);
}
+ // cast from T to E!?T
+ if (have_child_type->id == ZigTypeIdErrorUnion &&
+ have_child_type->data.error_union.payload_type->id == ZigTypeIdOptional &&
+ needed_child_type->id != ZigTypeIdOptional)
+ {
+ ZigType *wanted_child_type = have_child_type->data.error_union.payload_type->data.maybe.child_type;
+ if (types_match_const_cast_only(ira, wanted_child_type, needed_child_type, source_node,
+ false).id == ConstCastResultIdOk ||
+ needed_child_type->id == ZigTypeIdNull ||
+ needed_child_type->id == ZigTypeIdComptimeInt ||
+ needed_child_type->id == ZigTypeIdComptimeFloat)
+ {
+ IrInstruction *cast1 = ir_implicit_cast_result(ira, result_loc,
+ have_child_type->data.error_union.payload_type);
+ if (type_is_invalid(cast1->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return ir_implicit_cast_result(ira, cast1, needed_child_type);
+ }
+ }
+
ErrorMsg *parent_msg = ir_add_error_node(ira, source_node,
buf_sprintf("expected type '%s', found '%s'",
buf_ptr(&have_child_type->name),
From 5ee4e5ae3a9f4ecec3c339e49f1c2d3c59da7e66 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 02:22:19 -0400
Subject: [PATCH 016/190] copy elision: runtime struct init
```zig
export fn entry() void {
var x = Foo.{
.x = 1,
.y = bar(),
};
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca %Foo, align 4
%0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0, !dbg !56
store i32 1, i32* %0, align 4, !dbg !57
%1 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 1, !dbg !58
call fastcc void @bar(%Bar* sret %1), !dbg !59
ret void, !dbg !60
}
```
---
src/all_types.hpp | 3 +-
src/analyze.cpp | 2 +-
src/ast_render.cpp | 6 +--
src/ir.cpp | 126 +++++++++++++++++++++++++++------------------
src/parser.cpp | 6 +--
5 files changed, 84 insertions(+), 59 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 0cfd27899933..a1f5911580cf 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -436,7 +436,7 @@ enum NodeType {
NodeTypeArrayType,
NodeTypeErrorType,
NodeTypeIfErrorExpr,
- NodeTypeTestExpr,
+ NodeTypeIfOptional,
NodeTypeErrorSetDecl,
NodeTypeCancel,
NodeTypeResume,
@@ -2370,6 +2370,7 @@ struct IrInstructionFieldPtr {
IrInstruction *container_ptr;
Buf *field_name_buffer;
IrInstruction *field_name_expr;
+ IrInstruction *container_type;
bool is_const;
};
diff --git a/src/analyze.cpp b/src/analyze.cpp
index e71369eac934..ca5eba58d197 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -3517,7 +3517,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeArrayType:
case NodeTypeErrorType:
case NodeTypeIfErrorExpr:
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
case NodeTypeErrorSetDecl:
case NodeTypeCancel:
case NodeTypeResume:
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index f74c156de246..621edc9512f0 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -235,8 +235,8 @@ static const char *node_type_str(NodeType node_type) {
return "ErrorType";
case NodeTypeIfErrorExpr:
return "IfErrorExpr";
- case NodeTypeTestExpr:
- return "TestExpr";
+ case NodeTypeIfOptional:
+ return "IfOptional";
case NodeTypeErrorSetDecl:
return "ErrorSetDecl";
case NodeTypeCancel:
@@ -938,7 +938,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
}
break;
}
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
{
fprintf(ar->f, "if (");
render_node_grouped(ar, node->data.test_expr.target_node);
diff --git a/src/ir.cpp b/src/ir.cpp
index 8a027681e87a..997dc1e1996b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1170,14 +1170,16 @@ static IrInstruction *ir_build_field_ptr_instruction(IrBuilder *irb, Scope *scop
}
static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *container_ptr, Buf *field_name)
+ IrInstruction *container_ptr, IrInstruction *container_type, Buf *field_name)
{
IrInstructionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node);
instruction->container_ptr = container_ptr;
+ instruction->container_type = container_type;
instruction->field_name_buffer = field_name;
instruction->field_name_expr = nullptr;
ir_ref_instruction(container_ptr, irb->current_basic_block);
+ if (container_type != nullptr) ir_ref_instruction(container_type, irb->current_basic_block);
return &instruction->base;
}
@@ -3788,7 +3790,7 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode
if (container_ref_instruction == irb->codegen->invalid_instruction)
return container_ref_instruction;
- return ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name);
+ return ir_build_field_ptr(irb, scope, node, container_ref_instruction, nullptr, field_name);
}
static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *node, IrOverflowOp op) {
@@ -4956,12 +4958,14 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
return ir_lval_wrap(irb, scope, fn_call, lval);
}
-static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
+static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeIfBoolExpr);
IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope, LValNone, nullptr);
if (condition == irb->codegen->invalid_instruction)
- return condition;
+ return irb->codegen->invalid_instruction;
IrInstruction *is_comptime;
if (ir_should_inline(irb->exec, scope)) {
@@ -4984,7 +4988,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope, LValNone, result_loc);
if (then_expr_result == irb->codegen->invalid_instruction)
- return then_expr_result;
+ return irb->codegen->invalid_instruction;
if (!instr_is_unreachable(then_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
@@ -4993,7 +4997,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
if (else_node) {
else_expr_result = ir_gen_node(irb, else_node, subexpr_scope, LValNone, result_loc);
if (else_expr_result == irb->codegen->invalid_instruction)
- return else_expr_result;
+ return irb->codegen->invalid_instruction;
} else {
else_expr_result = ir_build_const_void(irb, scope, node);
}
@@ -5001,7 +5005,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, endif_block);
- return ir_build_load_ptr(irb, scope, node, result_loc, nullptr);
+ return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
}
static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id) {
@@ -5151,7 +5155,8 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
assert(entry_node->type == NodeTypeStructValueField);
Buf *name = entry_node->data.struct_val_field.name;
- IrInstruction *field_result_loc = ir_build_field_ptr(irb, scope, entry_node, result_loc, name);
+ IrInstruction *field_result_loc = ir_build_field_ptr(irb, scope, entry_node, result_loc,
+ container_type, name);
AstNode *expr_node = entry_node->data.struct_val_field.expr;
IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope, LValNone, field_result_loc);
@@ -5644,12 +5649,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
return ir_build_phi(irb, parent_scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
}
-static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
- IrInstruction *result_loc)
-{
+static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeBoolLiteral);
- IrInstruction *const_bool_val = ir_build_const_bool(irb, scope, node, node->data.bool_literal.value);
- return ir_gen_value(irb, scope, node, lval, result_loc, const_bool_val);
+ return ir_build_const_bool(irb, scope, node, node->data.bool_literal.value);
}
static IrInstruction *ir_gen_string_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -5789,7 +5791,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node,
IrInstruction *result_loc)
{
- assert(node->type == NodeTypeTestExpr);
+ assert(node->type == NodeTypeIfOptional);
Buf *var_symbol = node->data.test_expr.var_symbol;
AstNode *expr_node = node->data.test_expr.target_node;
@@ -6738,7 +6740,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
- IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
atomic_state_field_name);
// set the is_canceled bit
@@ -6816,7 +6818,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
- IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
atomic_state_field_name);
// clear the is_suspended bit
@@ -6884,12 +6886,14 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, target_inst);
Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
- IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
+ IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
+ result_ptr_field_name);
if (irb->codegen->have_err_ret_tracing) {
IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
- IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
+ IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, err_ret_trace_ptr_field_name);
ir_build_store_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
}
@@ -6911,7 +6915,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
- atomic_state_field_name);
+ nullptr, atomic_state_field_name);
IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false);
@@ -6963,12 +6967,14 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
if (irb->codegen->have_err_ret_tracing) {
Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
- IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
+ IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, err_ret_trace_field_name);
IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
}
Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
- IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
+ IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
+ result_field_name);
// If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to,
// because we're about to destroy the memory. So we store it into our result variable.
IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr, nullptr);
@@ -7173,17 +7179,17 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeBinOpExpr:
return ir_gen_bin_op(irb, scope, node, lval, result_loc);
case NodeTypeIntLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_int_lit(irb, scope, node));
case NodeTypeFloatLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_float_lit(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_float_lit(irb, scope, node));
case NodeTypeCharLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_char_lit(irb, scope, node));
case NodeTypeSymbol:
return ir_gen_symbol(irb, scope, node, lval, result_loc);
case NodeTypeFnCallExpr:
return ir_gen_fn_call(irb, scope, node, lval, result_loc);
case NodeTypeIfBoolExpr:
- return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node, result_loc), lval);
+ return ir_gen_if_bool_expr(irb, scope, node, lval, result_loc);
case NodeTypePrefixOpExpr:
return ir_gen_prefix_op_expr(irb, scope, node, lval);
case NodeTypeContainerInitExpr:
@@ -7230,31 +7236,31 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_build_load_ptr(irb, scope, node, unwrapped_ptr, nullptr);
}
case NodeTypeBoolLiteral:
- return ir_gen_bool_literal(irb, scope, node, lval, result_loc);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_bool_literal(irb, scope, node));
case NodeTypeArrayType:
- return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_array_type(irb, scope, node));
case NodeTypePointerType:
- return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_pointer_type(irb, scope, node));
case NodeTypePromiseType:
- return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_promise_type(irb, scope, node));
case NodeTypeStringLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_string_literal(irb, scope, node));
case NodeTypeUndefinedLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_undefined_literal(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_undefined_literal(irb, scope, node));
case NodeTypeAsmExpr:
- return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_asm_expr(irb, scope, node));
case NodeTypeNullLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_null_literal(irb, scope, node));
case NodeTypeIfErrorExpr:
return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node, result_loc), lval);
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node, result_loc), lval);
case NodeTypeSwitchExpr:
return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node, result_loc), lval);
case NodeTypeCompTime:
return ir_gen_comptime(irb, scope, node, lval, result_loc);
case NodeTypeErrorType:
- return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,ir_gen_error_type(irb, scope, node));
case NodeTypeBreak:
return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval);
case NodeTypeContinue:
@@ -7270,9 +7276,9 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeContainerDecl:
return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
case NodeTypeFnProto:
- return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_fn_proto(irb, scope, node));
case NodeTypeErrorSetDecl:
- return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_err_set_decl(irb, scope, node));
case NodeTypeCancel:
return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval);
case NodeTypeResume:
@@ -7375,7 +7381,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr,
coro_allocator_var_alloca);
Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
- IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
+ IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr,
+ nullptr, alloc_field_name);
IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr, nullptr);
IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size);
IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
@@ -7394,30 +7401,36 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
irb->exec->atomic_state_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
- atomic_state_field_name);
+ nullptr, atomic_state_field_name);
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
ir_build_store_ptr(irb, scope, node, irb->exec->atomic_state_field_ptr, zero);
Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
- irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
+ irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, result_field_name);
result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
- irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
+ irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, result_ptr_field_name);
ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
if (irb->codegen->have_err_ret_tracing) {
// initialize the error return trace
Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME);
- IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name);
+ IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, return_addresses_field_name);
Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
- err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
+ err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
+ err_ret_trace_field_name);
ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr);
// coordinate with builtin.zig
Buf *index_name = buf_create_from_str("index");
- IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name);
+ IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, nullptr,
+ index_name);
ir_build_store_ptr(irb, scope, node, index_ptr, zero);
Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
- IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name);
+ IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, nullptr,
+ instruction_addresses_name);
IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero,
nullptr, false, addrs_slice_ptr);
@@ -7478,7 +7491,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
}
if (irb->codegen->have_err_ret_tracing) {
Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
- IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
+ IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, err_ret_trace_ptr_field_name);
IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, nullptr);
ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
}
@@ -7513,7 +7527,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME);
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
ImplicitAllocatorIdLocalVar);
- IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, free_field_name);
+ IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, nullptr,
+ free_field_name);
IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr, nullptr);
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
@@ -13313,16 +13328,16 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *ptr, IrInstruction *value)
{
- Error err;
- if ((err = resolve_possible_alloca_inference(ira, ptr, value->value.type)))
- return ira->codegen->invalid_instruction;
-
if (ptr->value.type->id != ZigTypeIdPointer) {
ir_add_error(ira, ptr,
buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
return ira->codegen->invalid_instruction;
}
+ Error err;
+ if ((err = resolve_possible_alloca_inference(ira, ptr, value->value.type)))
+ return ira->codegen->invalid_instruction;
+
if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
return ir_const_void(ira, source_instr);
}
@@ -14953,6 +14968,15 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
buf_ptr(&container_ptr->value.type->name)));
return ira->codegen->invalid_instruction;
}
+
+ if (field_ptr_instruction->container_type != nullptr) {
+ ZigType *container_type = ir_resolve_type(ira, field_ptr_instruction->container_type->child);
+ if (type_is_invalid(container_type))
+ return ira->codegen->invalid_instruction;
+ if ((err = resolve_possible_alloca_inference(ira, container_ptr, container_type)))
+ return ira->codegen->invalid_instruction;
+ }
+
ZigType *container_type = container_ptr->value.type->data.pointer.child_type;
Buf *field_name = field_ptr_instruction->field_name_buffer;
diff --git a/src/parser.cpp b/src/parser.cpp
index 59e70713ab80..b8822c2d379b 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1604,7 +1604,7 @@ static AstNode *ast_parse_if_try_test_expr(ParseContext *pc, size_t *token_index
node->data.if_err_expr.else_node = else_node;
return node;
} else if (var_name_tok != nullptr) {
- AstNode *node = ast_create_node(pc, NodeTypeTestExpr, if_token);
+ AstNode *node = ast_create_node(pc, NodeTypeIfOptional, if_token);
node->data.test_expr.target_node = condition;
node->data.test_expr.var_is_ptr = var_is_ptr;
node->data.test_expr.var_symbol = token_buf(var_name_tok);
@@ -2407,7 +2407,7 @@ bool statement_terminates_without_semicolon(AstNode *node) {
if (node->data.if_err_expr.else_node)
return statement_terminates_without_semicolon(node->data.if_err_expr.else_node);
return node->data.if_err_expr.then_node->type == NodeTypeBlock;
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
if (node->data.test_expr.else_node)
return statement_terminates_without_semicolon(node->data.test_expr.else_node);
return node->data.test_expr.then_node->type == NodeTypeBlock;
@@ -3027,7 +3027,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
visit_field(&node->data.if_err_expr.then_node, visit, context);
visit_field(&node->data.if_err_expr.else_node, visit, context);
break;
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
visit_field(&node->data.test_expr.target_node, visit, context);
visit_field(&node->data.test_expr.then_node, visit, context);
visit_field(&node->data.test_expr.else_node, visit, context);
From 952da3c1ff9a71ce413b26b4b15f4ef33171e768 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 03:01:38 -0400
Subject: [PATCH 017/190] copy elision: catch unreachable with identifier expr
```zig
export fn entry() void {
var x: error!Bar = fail();
var z = x catch unreachable;
}
```
```llvm
define void @entry() #2 !dbg !42 {
Entry:
%error_return_trace_addresses = alloca [30 x i64], align 8
%error_return_trace = alloca %StackTrace, align 8
%x = alloca { i16, %Bar }, align 4
%z = alloca %Bar, align 4
%0 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 0
store i64 0, i64* %0, align 8
%1 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 1
%2 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 0
%3 = getelementptr inbounds [30 x i64], [30 x i64]* %error_return_trace_addresses, i64 0, i64 0
store i64* %3, i64** %2, align 8
%4 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 1
store i64 30, i64* %4, align 8
%5 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 0, !dbg !59
%6 = call fastcc i16 @fail(%StackTrace* %error_return_trace), !dbg !60
store i16 %6, i16* %5, align 2, !dbg !60
call void @llvm.dbg.declare(metadata { i16, %Bar }* %x, metadata !46, metadata !DIExpression()), !dbg !59
%7 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 1, !dbg !61
%8 = bitcast %Bar* %7 to i8*, !dbg !61
%9 = bitcast %Bar* %z to i8*, !dbg !61
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %8, i64 8, i1 false), !dbg !61
%10 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 0, !dbg !61
%11 = load i16, i16* %10, align 2, !dbg !61
%12 = icmp eq i16 %11, 0, !dbg !62
br i1 %12, label %UnwrapErrOk, label %UnwrapErrError, !dbg !62
UnwrapErrError: ; preds = %Entry
tail call fastcc void @__zig_fail_unwrap(%StackTrace* %error_return_trace, i16 %11), !dbg !62
unreachable, !dbg !62
UnwrapErrOk: ; preds = %Entry
call void @llvm.dbg.declare(metadata %Bar* %z, metadata !57, metadata !DIExpression()), !dbg !63
ret void, !dbg !64
}
```
---
src/ir.cpp | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 997dc1e1996b..7b3997677ff0 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3138,6 +3138,29 @@ static IrInstruction *ir_gen_value(IrBuilder *irb, Scope *scope, AstNode *node,
return ir_lval_wrap(irb, scope, value, lval);
}
+static IrInstruction *ir_gen_ptr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc, IrInstruction *ptr)
+{
+ switch (lval) {
+ case LValPtr:
+ assert(result_loc == nullptr);
+ return ptr;
+ case LValNone:
+ return ir_build_load_ptr(irb, scope, node, ptr, result_loc);
+ case LValErrorUnion: {
+ // ptr points to an error union;
+ // result_loc points to the result payload
+ // must return the error code
+ IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, node, ptr, false);
+ ir_build_load_ptr(irb, scope, node, payload_ptr, result_loc);
+ return ir_build_unwrap_err_code(irb, scope, node, ptr);
+ }
+ case LValOptional:
+ zig_panic("TODO");
+ }
+ zig_unreachable();
+}
+
static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc)
{
@@ -3735,10 +3758,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
ZigVar *var = find_variable(irb->codegen, scope, variable_name, &crossed_fndef_scope);
if (var) {
IrInstruction *var_ptr = ir_build_var_ptr_x(irb, scope, node, var, crossed_fndef_scope);
- if (lval == LValPtr)
- return var_ptr;
- IrInstruction *loaded = ir_build_load_ptr(irb, scope, node, var_ptr, result_loc);
- return ir_lval_wrap(irb, scope, loaded, lval);
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, var_ptr);
}
Tld *tld = find_decl(irb->codegen, scope, variable_name);
From d77b368ea6feb42327612941dd96e0a92cddcca1 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 04:17:54 -0400
Subject: [PATCH 018/190] copy elision: catch with identifier expression
This commit also makes `@sizeOf(?error) == @sizeOf(error)`.
Since 0 is not a valid error code, 0 can be used for the null
value, in the same way that 0 is used for the null value of
pointers.
```zig
export fn entry() void {
var x: error!Bar = fail();
var y = x catch bar2();
}
```
```llvm
define void @entry() #2 !dbg !42 {
Entry:
%error_return_trace_addresses = alloca [30 x i64], align 8
%error_return_trace = alloca %StackTrace, align 8
%x = alloca { i16, %Bar }, align 4
%y = alloca %Bar, align 4
%0 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 0
store i64 0, i64* %0, align 8
%1 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 1
%2 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 0
%3 = getelementptr inbounds [30 x i64], [30 x i64]* %error_return_trace_addresses, i64 0, i64 0
store i64* %3, i64** %2, align 8
%4 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 1
store i64 30, i64* %4, align 8
%5 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 0, !dbg !59
%6 = call fastcc i16 @fail(%StackTrace* %error_return_trace), !dbg !60
store i16 %6, i16* %5, align 2, !dbg !60
call void @llvm.dbg.declare(metadata { i16, %Bar }* %x, metadata !46, metadata !DIExpression()), !dbg !59
%7 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 1, !dbg !61
%8 = bitcast %Bar* %7 to i8*, !dbg !61
%9 = bitcast %Bar* %y to i8*, !dbg !61
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %8, i64 8, i1 false), !dbg !61
%10 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 0, !dbg !61
%11 = load i16, i16* %10, align 2, !dbg !62
%12 = icmp ne i16 %11, 0, !dbg !62
br i1 %12, label %CatchError, label %CatchEnd, !dbg !62
CatchError: ; preds = %Entry
call fastcc void @bar2(%Bar* sret %y), !dbg !63
br label %CatchEnd, !dbg !62
CatchEnd: ; preds = %CatchError, %Entry
call void @llvm.dbg.declare(metadata %Bar* %y, metadata !57, metadata !DIExpression()), !dbg !64
ret void, !dbg !65
}
```
---
src/all_types.hpp | 7 ++++
src/analyze.cpp | 5 +--
src/codegen.cpp | 32 ++++++++++++++---
src/ir.cpp | 92 ++++++++++++++++++++++++++++++++++++++---------
src/ir_print.cpp | 9 +++++
5 files changed, 121 insertions(+), 24 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index a1f5911580cf..da072e837332 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2186,6 +2186,7 @@ enum IrInstructionId {
IrInstructionIdAllocaSrc,
IrInstructionIdAllocaGen,
IrInstructionIdAssertNonError,
+ IrInstructionIdErrorUnionFieldErrorSet,
};
struct IrInstruction {
@@ -2882,6 +2883,12 @@ struct IrInstructionUnwrapErrCode {
IrInstruction *value;
};
+struct IrInstructionErrorUnionFieldErrorSet {
+ IrInstruction base;
+
+ IrInstruction *ptr;
+};
+
struct IrInstructionUnwrapErrPayload {
IrInstruction base;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index ca5eba58d197..ed8b286d6759 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -589,7 +589,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
if (child_type->zero_bits) {
entry->type_ref = LLVMInt1Type();
entry->di_type = g->builtin_types.entry_bool->di_type;
- } else if (type_is_codegen_pointer(child_type)) {
+ } else if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
assert(child_type->di_type);
// this is an optimization but also is necessary for calling C
// functions where all pointers are maybe pointers
@@ -4490,7 +4490,8 @@ bool handle_is_ptr(ZigType *type_entry) {
return type_has_bits(type_entry->data.error_union.payload_type);
case ZigTypeIdOptional:
return type_has_bits(type_entry->data.maybe.child_type) &&
- !type_is_codegen_pointer(type_entry->data.maybe.child_type);
+ !type_is_codegen_pointer(type_entry->data.maybe.child_type) &&
+ type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet;
case ZigTypeIdUnion:
assert(type_entry->data.unionation.zero_bits_known);
if (type_entry->data.unionation.gen_field_count == 0)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 0f0166be1670..b27409f2a630 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3734,8 +3734,8 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR
if (child_type->zero_bits) {
return maybe_handle;
} else {
- bool maybe_is_ptr = type_is_codegen_pointer(child_type);
- if (maybe_is_ptr) {
+ bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
+ if (is_scalar) {
return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
} else {
LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, "");
@@ -3774,8 +3774,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
if (child_type->zero_bits) {
return nullptr;
} else {
- bool maybe_is_ptr = type_is_codegen_pointer(child_type);
- if (maybe_is_ptr) {
+ bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
+ if (is_scalar) {
return maybe_ptr;
} else {
LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
@@ -4552,6 +4552,7 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
ZigType *ptr_type = instruction->value->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *err_union_type = ptr_type->data.pointer.child_type;
+ assert(err_union_type->id == ZigTypeIdErrorUnion);
ZigType *payload_type = err_union_type->data.error_union.payload_type;
LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
@@ -4564,6 +4565,23 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
}
}
+static LLVMValueRef ir_render_error_union_field_error_set(CodeGen *g, IrExecutable *executable,
+ IrInstructionErrorUnionFieldErrorSet *instruction)
+{
+ ZigType *ptr_type = instruction->ptr->value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+ ZigType *err_union_type = ptr_type->data.pointer.child_type;
+ assert(err_union_type->id == ZigTypeIdErrorUnion);
+ ZigType *payload_type = err_union_type->data.error_union.payload_type;
+ LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->ptr);
+
+ if (type_has_bits(payload_type)) {
+ return LLVMBuildStructGEP(g->builder, err_union_ptr, err_union_err_index, "");
+ } else {
+ return err_union_ptr;
+ }
+}
+
static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) {
ZigType *ptr_type = instruction->value->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
@@ -4615,7 +4633,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
}
LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
- if (type_is_codegen_pointer(child_type)) {
+ if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
return payload_val;
}
@@ -5301,6 +5319,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
case IrInstructionIdTestErr:
return ir_render_test_err(g, executable, (IrInstructionTestErr *)instruction);
+ case IrInstructionIdErrorUnionFieldErrorSet:
+ return ir_render_error_union_field_error_set(g, executable, (IrInstructionErrorUnionFieldErrorSet *)instruction);
case IrInstructionIdUnwrapErrCode:
return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction);
case IrInstructionIdUnwrapErrPayload:
@@ -5735,6 +5755,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);
} else if (type_is_codegen_pointer(child_type)) {
return gen_const_val_ptr(g, const_val, name);
+ } else if (child_type->id == ZigTypeIdErrorSet) {
+ zig_panic("TODO");
} else {
LLVMValueRef child_val;
LLVMValueRef maybe_val;
diff --git a/src/ir.cpp b/src/ir.cpp
index 7b3997677ff0..ab79223106f2 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -903,6 +903,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonError *
return IrInstructionIdAssertNonError;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnionFieldErrorSet *) {
+ return IrInstructionIdErrorUnionFieldErrorSet;
+}
+
template
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate(1);
@@ -2921,6 +2925,17 @@ static IrInstruction *ir_build_assert_non_error(IrBuilder *irb, Scope *scope, As
return &instruction->base;
}
+static IrInstruction *ir_build_error_union_field_error_set(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *ptr)
+{
+ IrInstructionErrorUnionFieldErrorSet *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->ptr = ptr;
+
+ ir_ref_instruction(ptr, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -3153,7 +3168,7 @@ static IrInstruction *ir_gen_ptr(IrBuilder *irb, Scope *scope, AstNode *node, LV
// must return the error code
IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, node, ptr, false);
ir_build_load_ptr(irb, scope, node, payload_ptr, result_loc);
- return ir_build_unwrap_err_code(irb, scope, node, ptr);
+ return ir_build_error_union_field_error_set(irb, scope, node, ptr);
}
case LValOptional:
zig_panic("TODO");
@@ -5109,11 +5124,12 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node,
AstNode *expr_node, LVal lval, IrInstruction *result_loc)
{
- IrInstruction *err_val = ir_gen_node(irb, expr_node, scope, LValErrorUnion, result_loc);
- if (err_val == irb->codegen->invalid_instruction)
+ IrInstruction *err_code_ptr = ir_gen_node(irb, expr_node, scope, LValErrorUnion, result_loc);
+ if (err_code_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- ir_build_assert_non_error(irb, scope, source_node, err_val);
+ IrInstruction *err_code = ir_build_load_ptr(irb, scope, source_node, err_code_ptr, nullptr);
+ ir_build_assert_non_error(irb, scope, source_node, err_code);
return ir_gen_lval_ptr(irb, scope, source_node, lval, result_loc);
}
@@ -6453,11 +6469,12 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, lval, result_loc);
}
- IrInstruction *err_val = ir_gen_node(irb, op1_node, parent_scope, LValErrorUnion, result_loc);
- if (err_val == irb->codegen->invalid_instruction)
+ IrInstruction *err_code_ptr = ir_gen_node(irb, op1_node, parent_scope, LValErrorUnion, result_loc);
+ if (err_code_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_val);
+ IrInstruction *opt_err_code = ir_build_load_ptr(irb, parent_scope, node, err_code_ptr, nullptr);
+ IrInstruction *is_err = ir_build_test_nonnull(irb, parent_scope, node, opt_err_code);
IrInstruction *is_comptime;
if (ir_should_inline(irb->exec, parent_scope)) {
@@ -6480,7 +6497,9 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
ZigVar *var = ir_create_var(irb, node, parent_scope, var_name,
is_const, is_const, is_shadowable, is_comptime);
err_scope = var->child_scope;
- ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
+ IrInstruction *unwrapped_err_code_ptr = ir_build_unwrap_maybe(irb, err_scope, var_node,
+ err_code_ptr, false);
+ ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, unwrapped_err_code_ptr);
} else {
err_scope = parent_scope;
}
@@ -19573,6 +19592,40 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
}
}
+static IrInstruction *ir_analyze_instruction_error_union_field_error_set(IrAnalyze *ira,
+ IrInstructionErrorUnionFieldErrorSet *instruction)
+{
+ IrInstruction *ptr = instruction->ptr->child;
+ if (type_is_invalid(ptr->value.type))
+ return ira->codegen->invalid_instruction;
+ ZigType *ptr_type = ptr->value.type;
+
+ assert(ptr_type->id == ZigTypeIdPointer);
+
+ ZigType *type_entry = ptr_type->data.pointer.child_type;
+ if (type_is_invalid(type_entry))
+ return ira->codegen->invalid_instruction;
+
+ if (type_entry->id != ZigTypeIdErrorUnion) {
+ ir_add_error(ira, ptr,
+ buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ ZigType *opt_err_set = get_optional_type(ira->codegen, type_entry->data.error_union.err_set_type);
+ ZigType *result_type = get_pointer_to_type_extra(ira->codegen, opt_err_set,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+
+ if (instr_is_comptime(ptr)) {
+ zig_panic("TODO need to change ConstExprValue x_err_union to have a ConstExprValue for error set value");
+ }
+
+ IrInstruction *result = ir_build_error_union_field_error_set(&ira->new_irb,
+ instruction->base.scope, instruction->base.source_node, ptr);
+ result->value.type = result_type;
+ return result;
+}
+
static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
IrInstructionUnwrapErrCode *instruction)
{
@@ -19681,19 +19734,21 @@ static IrInstruction *ir_analyze_instruction_assert_non_error(IrAnalyze *ira,
if (type_is_invalid(err_code->value.type))
return ira->codegen->invalid_instruction;
- assert(err_code->value.type->id == ZigTypeIdErrorSet);
+ assert(err_code->value.type->id == ZigTypeIdOptional);
+ assert(err_code->value.type->data.maybe.child_type->id == ZigTypeIdErrorSet);
if (instr_is_comptime(err_code)) {
- ConstExprValue *err_val = ir_resolve_const(ira, err_code, UndefBad);
- if (err_val == nullptr)
+ ConstExprValue *opt_val = ir_resolve_const(ira, err_code, UndefBad);
+ if (opt_val == nullptr)
return ira->codegen->invalid_instruction;
+ ConstExprValue *err_val = opt_val->data.x_optional;
+ if (err_val == nullptr)
+ return ir_const_void(ira, &instruction->base);
ErrorTableEntry *err = err_val->data.x_err_set;
- if (err != nullptr) {
- ir_add_error(ira, &instruction->base,
- buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
- return ira->codegen->invalid_instruction;
- }
- return ir_const_void(ira, &instruction->base);
+ assert(err != nullptr);
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
+ return ira->codegen->invalid_instruction;
}
ir_build_assert_non_error(&ira->new_irb, instruction->base.scope,
@@ -21593,6 +21648,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_result_ptr_cast(ira, (IrInstructionResultPtrCast *)instruction);
case IrInstructionIdAllocaSrc:
return ir_analyze_instruction_alloca(ira, (IrInstructionAllocaSrc *)instruction);
+ case IrInstructionIdErrorUnionFieldErrorSet:
+ return ir_analyze_instruction_error_union_field_error_set(ira, (IrInstructionErrorUnionFieldErrorSet *)instruction);
case IrInstructionIdResultBytesToSlice:
zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
@@ -21829,6 +21886,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdResultBytesToSlice:
case IrInstructionIdAllocaSrc:
case IrInstructionIdAllocaGen:
+ case IrInstructionIdErrorUnionFieldErrorSet:
return false;
case IrInstructionIdLoadPtr:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 1966fff747d0..aea1e9702f15 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1393,6 +1393,12 @@ static void ir_print_assert_non_error(IrPrint *irp, IrInstructionAssertNonError
fprintf(irp->f, ")");
}
+static void ir_print_error_union_field_error_set(IrPrint *irp, IrInstructionErrorUnionFieldErrorSet *instruction) {
+ fprintf(irp->f, "ErrorUnionFieldErrorSet(");
+ ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1854,6 +1860,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdAssertNonError:
ir_print_assert_non_error(irp, (IrInstructionAssertNonError *)instruction);
break;
+ case IrInstructionIdErrorUnionFieldErrorSet:
+ ir_print_error_union_field_error_set(irp, (IrInstructionErrorUnionFieldErrorSet *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
From 94abb0d803a7c0a5c5a3cbc267c8f47b0eec8fd0 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 13:40:26 -0400
Subject: [PATCH 019/190] copy elision: if-bool with scalar types
```zig
export fn entry() void {
var c = true;
var y: i32 = if (c) 1234 else 5678;
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%c = alloca i1, align 1
%y = alloca i32, align 4
store i1 true, i1* %c, align 1, !dbg !51
call void @llvm.dbg.declare(metadata i1* %c, metadata !45, metadata !DIExpression()), !dbg !52
%0 = load i1, i1* %c, align 1, !dbg !53
br i1 %0, label %Then, label %Else, !dbg !53
Then: ; preds = %Entry
store i32 1234, i32* %y, align 4, !dbg !54
br label %EndIf, !dbg !55
Else: ; preds = %Entry
store i32 5678, i32* %y, align 4, !dbg !56
br label %EndIf, !dbg !55
EndIf: ; preds = %Else, %Then
call void @llvm.dbg.declare(metadata i32* %y, metadata !48, metadata !DIExpression()), !dbg !57
ret void, !dbg !58
}
```
---
src/all_types.hpp | 8 ++++
src/codegen.cpp | 1 +
src/ir.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++---
src/ir_print.cpp | 11 ++++++
4 files changed, 108 insertions(+), 5 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index da072e837332..506615e59c29 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2187,6 +2187,7 @@ enum IrInstructionId {
IrInstructionIdAllocaGen,
IrInstructionIdAssertNonError,
IrInstructionIdErrorUnionFieldErrorSet,
+ IrInstructionIdFirstArgResultLoc,
};
struct IrInstruction {
@@ -3371,6 +3372,13 @@ struct IrInstructionAssertNonError {
IrInstruction *err_code;
};
+struct IrInstructionFirstArgResultLoc {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ IrInstruction *fn_ref;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index b27409f2a630..88f72dd5ca8e 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5241,6 +5241,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdDeclVarSrc:
case IrInstructionIdAllocaSrc:
case IrInstructionIdAllocaGen:
+ case IrInstructionIdFirstArgResultLoc:
zig_unreachable();
case IrInstructionIdDeclVarGen:
diff --git a/src/ir.cpp b/src/ir.cpp
index ab79223106f2..9b2be0f5e27e 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -907,6 +907,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnionFieldE
return IrInstructionIdErrorUnionFieldErrorSet;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionFirstArgResultLoc *) {
+ return IrInstructionIdFirstArgResultLoc;
+}
+
template
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate(1);
@@ -2936,6 +2940,19 @@ static IrInstruction *ir_build_error_union_field_error_set(IrBuilder *irb, Scope
return &instruction->base;
}
+static IrInstruction *ir_build_first_arg_result_loc(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, IrInstruction *fn_ref)
+{
+ IrInstructionFirstArgResultLoc *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->fn_ref = fn_ref;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ ir_ref_instruction(fn_ref, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -4969,8 +4986,24 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
if (fn_ref == irb->codegen->invalid_instruction)
return fn_ref;
+ // In pass 1, we can't tell the difference between a function call with a single argument
+ // and an implicit cast. So if there is only one argument, we emit a special instruction.
size_t arg_count = node->data.fn_call_expr.params.length;
IrInstruction **args = allocate(arg_count);
+ bool is_async = node->data.fn_call_expr.is_async;
+ if (arg_count == 1 && !is_async) {
+ AstNode *arg_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg_result_loc = ir_build_first_arg_result_loc(irb, scope, arg_node, result_loc, fn_ref);
+ args[0] = ir_gen_node(irb, arg_node, scope, LValNone, arg_result_loc);
+ if (args[0] == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+ // In the analysis, this call instruction will be a simple LoadPtr instruction if
+ // it turns out to be an implicit cast.
+ IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
+ FnInlineAuto, false, nullptr, nullptr, result_loc);
+ return ir_lval_wrap(irb, scope, fn_call, lval);
+ }
+
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, scope, LValNone, nullptr);
@@ -4978,7 +5011,6 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
return args[i];
}
- bool is_async = node->data.fn_call_expr.is_async;
IrInstruction *async_allocator = nullptr;
if (is_async) {
if (node->data.fn_call_expr.async_allocator) {
@@ -13989,6 +14021,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
}
static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) {
+ Error err;
IrInstruction *fn_ref = call_instruction->fn_ref->child;
if (type_is_invalid(fn_ref->value.type))
return ira->codegen->invalid_instruction;
@@ -14010,12 +14043,18 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC
return ira->codegen->invalid_instruction;
}
- IrInstruction *arg = call_instruction->args[0]->child;
+ // This is handled with the result location mechanism. So all we need to do here is
+ // a LoadPtr on the result location.
+ IrInstruction *result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if ((err = resolve_possible_alloca_inference(ira, result_loc, dest_type)))
+ return ira->codegen->invalid_instruction;
- IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, dest_type, arg);
- if (type_is_invalid(cast_instruction->value.type))
+ IrInstruction *deref = ir_get_deref(ira, &call_instruction->base, result_loc);
+ if (type_is_invalid(deref->value.type))
return ira->codegen->invalid_instruction;
- return ir_finish_anal(ira, cast_instruction);
+ return ir_finish_anal(ira, deref);
} else if (fn_ref->value.type->id == ZigTypeIdFn) {
ZigFn *fn_table_entry = ir_resolve_fn(ira, fn_ref);
if (fn_table_entry == nullptr)
@@ -21357,6 +21396,47 @@ static IrInstruction *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructio
return &result->base;
}
+static IrInstruction *ir_analyze_instruction_first_arg_result_loc(IrAnalyze *ira,
+ IrInstructionFirstArgResultLoc *instruction)
+{
+ Error err;
+
+ IrInstruction *fn_ref = instruction->fn_ref->child;
+ if (type_is_invalid(fn_ref->value.type))
+ return ira->codegen->invalid_instruction;
+
+ if (fn_ref->value.type->id == ZigTypeIdMetaType) {
+ // Result of this instruction should be the implicitly casted result location.
+
+ ZigType *dest_type = ir_resolve_type(ira, fn_ref);
+ if (type_is_invalid(dest_type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = ir_implicit_cast_result(ira, instruction->prev_result_loc->child,
+ dest_type);
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ return new_result_loc;
+ }
+
+ // Result of this instruction should be the result location for the first argument of the function call.
+ // This means it should be a stack allocation.
+ IrInstructionAllocaGen *result = ir_create_alloca_gen(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, 0, "");
+
+ assert(fn_ref->value.type->id == ZigTypeIdFn);
+ ZigType *param_type = fn_ref->value.type->data.fn.fn_type_id.param_info[0].type;
+ if (type_is_invalid(param_type))
+ return ira->codegen->invalid_instruction;
+ if ((err = resolve_alloca_inference(ira, result, param_type)))
+ return ira->codegen->invalid_instruction;
+ ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
+ if (fn_entry != nullptr) {
+ fn_entry->alloca_list.append(result);
+ }
+ return &result->base;
+}
+
static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -21650,6 +21730,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_alloca(ira, (IrInstructionAllocaSrc *)instruction);
case IrInstructionIdErrorUnionFieldErrorSet:
return ir_analyze_instruction_error_union_field_error_set(ira, (IrInstructionErrorUnionFieldErrorSet *)instruction);
+ case IrInstructionIdFirstArgResultLoc:
+ return ir_analyze_instruction_first_arg_result_loc(ira, (IrInstructionFirstArgResultLoc *)instruction);
case IrInstructionIdResultBytesToSlice:
zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
@@ -21887,6 +21969,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdAllocaSrc:
case IrInstructionIdAllocaGen:
case IrInstructionIdErrorUnionFieldErrorSet:
+ case IrInstructionIdFirstArgResultLoc:
return false;
case IrInstructionIdLoadPtr:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index aea1e9702f15..43ca9850262f 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1399,6 +1399,14 @@ static void ir_print_error_union_field_error_set(IrPrint *irp, IrInstructionErro
fprintf(irp->f, ")");
}
+static void ir_print_first_arg_result_loc(IrPrint *irp, IrInstructionFirstArgResultLoc *instruction) {
+ fprintf(irp->f, "FirstArgResultLoc(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",fn=");
+ ir_print_other_instruction(irp, instruction->fn_ref);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1863,6 +1871,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdErrorUnionFieldErrorSet:
ir_print_error_union_field_error_set(irp, (IrInstructionErrorUnionFieldErrorSet *)instruction);
break;
+ case IrInstructionIdFirstArgResultLoc:
+ ir_print_first_arg_result_loc(irp, (IrInstructionFirstArgResultLoc *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
From 1bda9705aad83877e66d7eab6d9f5ce426d61ddb Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 14:36:36 -0400
Subject: [PATCH 020/190] copy elision: if-optional with aggregate
```zig
export fn entry() void {
var x: ?Foo = foo();
var y = if (x) |a| a.y else bar();
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca { %Foo, i1 }, align 4
%y = alloca %Bar, align 4
%0 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !64
store i1 true, i1* %0, align 1, !dbg !64
%1 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !64
call fastcc void @foo(%Foo* sret %1), !dbg !65
call void @llvm.dbg.declare(metadata { %Foo, i1 }* %x, metadata !45, metadata !DIExpression()), !dbg !64
%2 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !66
%3 = load i1, i1* %2, align 1, !dbg !66
br i1 %3, label %OptionalThen, label %OptionalElse, !dbg !66
OptionalThen: ; preds = %Entry
%4 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !66
call void @llvm.dbg.declare(metadata %Foo* %4, metadata !61, metadata !DIExpression()), !dbg !66
%5 = getelementptr inbounds %Foo, %Foo* %4, i32 0, i32 1, !dbg !67
%6 = bitcast %Bar* %5 to i8*, !dbg !67
%7 = bitcast %Bar* %y to i8*, !dbg !67
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %7, i8* align 4 %6, i64 8, i1 false), !dbg !67
br label %OptionalEndIf, !dbg !66
OptionalElse: ; preds = %Entry
call fastcc void @bar(%Bar* sret %y), !dbg !69
br label %OptionalEndIf, !dbg !66
OptionalEndIf: ; preds = %OptionalElse, %OptionalThen
call void @llvm.dbg.declare(metadata %Bar* %y, metadata !63, metadata !DIExpression()), !dbg !70
ret void, !dbg !71
}
```
---
src/ir.cpp | 42 +++++++++++++-----------------------------
src/ir_print.cpp | 3 ++-
2 files changed, 15 insertions(+), 30 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 9b2be0f5e27e..ef0184d7983b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3832,7 +3832,9 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode
return ir_build_load_result(irb, scope, node, ptr_instruction, result_loc);
}
-static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeFieldAccessExpr);
AstNode *container_ref_node = node->data.field_access_expr.struct_expr;
@@ -3842,7 +3844,8 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode
if (container_ref_instruction == irb->codegen->invalid_instruction)
return container_ref_instruction;
- return ir_build_field_ptr(irb, scope, node, container_ref_instruction, nullptr, field_name);
+ IrInstruction *field_ptr = ir_build_field_ptr(irb, scope, node, container_ref_instruction, nullptr, field_name);
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, field_ptr);
}
static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *node, IrOverflowOp op) {
@@ -5856,7 +5859,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile);
}
-static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node,
+static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc)
{
assert(node->type == NodeTypeIfOptional);
@@ -5897,12 +5900,10 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, is_const, is_const, is_shadowable, is_comptime);
- IrInstruction *payload_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "optional_payload");
- IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
- IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_result(irb, subexpr_scope, node,
- var_ptr_value, payload_alloca);
- ir_build_store_result(irb, subexpr_scope, node, payload_alloca, var_value);
- ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, payload_alloca);
+ IrInstruction *payload_ptr = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
+ IrInstruction *var_ptr = var_is_ptr ?
+ ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr;
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_ptr);
var_scope = var->child_scope;
} else {
var_scope = subexpr_scope;
@@ -5910,7 +5911,6 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope, LValNone, result_loc);
if (then_expr_result == irb->codegen->invalid_instruction)
return then_expr_result;
- IrBasicBlock *after_then_block = irb->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
@@ -5923,19 +5923,11 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
} else {
else_expr_result = ir_build_const_void(irb, scope, node);
}
- IrBasicBlock *after_else_block = irb->current_basic_block;
if (!instr_is_unreachable(else_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, endif_block);
- IrInstruction **incoming_values = allocate(2);
- incoming_values[0] = then_expr_result;
- incoming_values[1] = else_expr_result;
- IrBasicBlock **incoming_blocks = allocate(2);
- incoming_blocks[0] = after_then_block;
- incoming_blocks[1] = after_else_block;
-
- return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
+ return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
}
static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
@@ -7276,15 +7268,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeReturnExpr:
return ir_gen_return(irb, scope, node, lval, result_loc);
case NodeTypeFieldAccessExpr:
- {
- IrInstruction *ptr_instruction = ir_gen_field_access(irb, scope, node);
- if (ptr_instruction == irb->codegen->invalid_instruction)
- return ptr_instruction;
- if (lval == LValPtr)
- return ptr_instruction;
-
- return ir_build_load_ptr(irb, scope, node, ptr_instruction, nullptr);
- }
+ return ir_gen_field_access(irb, scope, node, lval, result_loc);
case NodeTypePtrDeref: {
AstNode *expr_node = node->data.ptr_deref_expr.target;
IrInstruction *value = ir_gen_node(irb, expr_node, scope, lval, nullptr);
@@ -7325,7 +7309,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeIfErrorExpr:
return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node, result_loc), lval);
case NodeTypeIfOptional:
- return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node, result_loc), lval);
+ return ir_gen_if_optional_expr(irb, scope, node, lval, result_loc);
case NodeTypeSwitchExpr:
return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node, result_loc), lval);
case NodeTypeCompTime:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 43ca9850262f..f999b98b8d32 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -491,8 +491,9 @@ static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instructi
}
static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) {
- fprintf(irp->f, "&??*");
+ fprintf(irp->f, "UnwrapOptional(");
ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ")");
if (!instruction->safety_check_on) {
fprintf(irp->f, " // no safety");
}
From 88427ae04b1c817331ab9104778f1d356ecb9e15 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 16:19:43 -0400
Subject: [PATCH 021/190] copy elision: if-err with aggregate
```zig
export fn entry() void {
var x: error!Foo = foo();
var y = if (x) |a| a.y else |e| bar();
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca { i16, %Foo }, align 4
%y = alloca %Bar, align 4
%0 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 0, !dbg !64
store i16 0, i16* %0, align 2, !dbg !64
%1 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 1, !dbg !64
call fastcc void @foo(%Foo* sret %1), !dbg !65
call void @llvm.dbg.declare(metadata { i16, %Foo }* %x, metadata !45, metadata !DIExpression()), !dbg !64
%2 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 0, !dbg !66
%3 = load i16, i16* %2, align 2, !dbg !66
%4 = icmp ne i16 %3, 0, !dbg !66
br i1 %4, label %IfErrElse, label %IfErrThen, !dbg !66
IfErrThen: ; preds = %Entry
%5 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 1, !dbg !66
call void @llvm.dbg.declare(metadata %Foo* %5, metadata !60, metadata !DIExpression()), !dbg !66
%6 = getelementptr inbounds %Foo, %Foo* %5, i32 0, i32 1, !dbg !67
%7 = bitcast %Bar* %6 to i8*, !dbg !67
%8 = bitcast %Bar* %y to i8*, !dbg !67
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %8, i8* align 4 %7, i64 8, i1 false), !dbg !67
br label %IfErrEnd, !dbg !66
IfErrElse: ; preds = %Entry
%9 = load i16, i16* %2, align 2, !dbg !66
call void @llvm.dbg.declare(metadata i16* %2, metadata !62, metadata !DIExpression()), !dbg !66
call fastcc void @bar(%Bar* sret %y), !dbg !69
br label %IfErrEnd, !dbg !66
IfErrEnd: ; preds = %IfErrElse, %IfErrThen
call void @llvm.dbg.declare(metadata %Bar* %y, metadata !63, metadata !DIExpression()), !dbg !71
ret void, !dbg !72
}
```
---
src/ir.cpp | 66 +++++++++++++++++++++++++-----------------------------
1 file changed, 31 insertions(+), 35 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index ef0184d7983b..89a57e1c7a6b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5930,7 +5930,9 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
}
-static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
+static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeIfErrorExpr);
AstNode *target_node = node->data.if_err_expr.target_node;
@@ -5941,19 +5943,21 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
Buf *var_symbol = node->data.if_err_expr.var_symbol;
Buf *err_symbol = node->data.if_err_expr.err_symbol;
- IrInstruction *err_val_ptr = ir_gen_node(irb, target_node, scope, LValPtr, nullptr);
- if (err_val_ptr == irb->codegen->invalid_instruction)
- return err_val_ptr;
+ IrInstruction *err_union_ptr = ir_gen_node(irb, target_node, scope, LValPtr, nullptr);
+ if (err_union_ptr == irb->codegen->invalid_instruction)
+ return err_union_ptr;
- IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr, nullptr);
- IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val);
+ IrInstruction *ptr_opt_err_code = ir_build_error_union_field_error_set(irb, scope, node, err_union_ptr);
+ IrInstruction *opt_err_code = ir_build_load_ptr(irb, scope, node, ptr_opt_err_code, nullptr);
+ IrInstruction *is_err = ir_build_test_nonnull(irb, scope, node, opt_err_code);
- IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");
- IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");
- IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "TryEnd");
+ IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "IfErrThen");
+ IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "IfErrElse");
+ IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "IfErrEnd");
bool force_comptime = ir_should_inline(irb->exec, scope);
- IrInstruction *is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err);
+ IrInstruction *is_comptime = force_comptime ?
+ ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err);
ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, ok_block);
@@ -5961,18 +5965,19 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
Scope *var_scope;
if (var_symbol) {
+ IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_union_ptr, false);
+
IrInstruction *var_type = nullptr;
bool is_shadowable = false;
- IrInstruction *var_is_comptime = force_comptime ? ir_build_const_bool(irb, subexpr_scope, node, true) : ir_build_test_comptime(irb, subexpr_scope, node, err_val);
+ IrInstruction *var_is_comptime = force_comptime ?
+ ir_build_const_bool(irb, subexpr_scope, node, true) :
+ ir_build_test_comptime(irb, subexpr_scope, node, payload_ptr);
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);
- IrInstruction *payload_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "errunion_payload");
- IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false);
- IrInstruction *var_value = var_is_ptr ?
- var_ptr_value : ir_build_load_result(irb, subexpr_scope, node, var_ptr_value, payload_alloca);
- ir_build_store_result(irb, subexpr_scope, node, payload_alloca, var_value);
- ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, payload_alloca);
+ IrInstruction *var_ptr = var_is_ptr ?
+ ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr;
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_ptr);
var_scope = var->child_scope;
} else {
var_scope = subexpr_scope;
@@ -5980,7 +5985,6 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope, LValNone, result_loc);
if (then_expr_result == irb->codegen->invalid_instruction)
return then_expr_result;
- IrBasicBlock *after_then_block = irb->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
@@ -5990,14 +5994,14 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
if (else_node) {
Scope *err_var_scope;
if (err_symbol) {
- IrInstruction *var_type = nullptr;
bool is_shadowable = false;
bool is_const = true;
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
err_symbol, is_const, is_const, is_shadowable, is_comptime);
- IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr);
- ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+ IrInstruction *unwrapped_err_code_ptr = ir_build_unwrap_maybe(irb, subexpr_scope, node,
+ ptr_opt_err_code, false);
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, nullptr, unwrapped_err_code_ptr);
err_var_scope = var->child_scope;
} else {
err_var_scope = subexpr_scope;
@@ -6008,19 +6012,11 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
} else {
else_expr_result = ir_build_const_void(irb, scope, node);
}
- IrBasicBlock *after_else_block = irb->current_basic_block;
if (!instr_is_unreachable(else_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, endif_block);
- IrInstruction **incoming_values = allocate(2);
- incoming_values[0] = then_expr_result;
- incoming_values[1] = else_expr_result;
- IrBasicBlock **incoming_blocks = allocate(2);
- incoming_blocks[0] = after_then_block;
- incoming_blocks[1] = after_else_block;
-
- return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
+ return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
}
static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node,
@@ -6493,11 +6489,11 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, lval, result_loc);
}
- IrInstruction *err_code_ptr = ir_gen_node(irb, op1_node, parent_scope, LValErrorUnion, result_loc);
- if (err_code_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *ptr_opt_err_code = ir_gen_node(irb, op1_node, parent_scope, LValErrorUnion, result_loc);
+ if (ptr_opt_err_code == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *opt_err_code = ir_build_load_ptr(irb, parent_scope, node, err_code_ptr, nullptr);
+ IrInstruction *opt_err_code = ir_build_load_ptr(irb, parent_scope, node, ptr_opt_err_code, nullptr);
IrInstruction *is_err = ir_build_test_nonnull(irb, parent_scope, node, opt_err_code);
IrInstruction *is_comptime;
@@ -6522,7 +6518,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
is_const, is_const, is_shadowable, is_comptime);
err_scope = var->child_scope;
IrInstruction *unwrapped_err_code_ptr = ir_build_unwrap_maybe(irb, err_scope, var_node,
- err_code_ptr, false);
+ ptr_opt_err_code, false);
ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, unwrapped_err_code_ptr);
} else {
err_scope = parent_scope;
@@ -7307,7 +7303,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeNullLiteral:
return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_null_literal(irb, scope, node));
case NodeTypeIfErrorExpr:
- return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node, result_loc), lval);
+ return ir_gen_if_err_expr(irb, scope, node, lval, result_loc);
case NodeTypeIfOptional:
return ir_gen_if_optional_expr(irb, scope, node, lval, result_loc);
case NodeTypeSwitchExpr:
From 7d6c9671e3224b1a63b8746eb5538c468441fbcf Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 16:46:59 -0400
Subject: [PATCH 022/190] copy elision: implicit cast error set to error union
runtime
```zig
export fn entry() void {
var x = error.Failure;
var y: error!Foo = x;
}
```
```llvm
define void @entry() #2 !dbg !42 {
Entry:
%x = alloca i16, align 2
%y = alloca { i16, %Foo }, align 4
store i16 1, i16* %x, align 2, !dbg !63
call void @llvm.dbg.declare(metadata i16* %x, metadata !46, metadata !DIExpression()), !dbg !64
%0 = load i16, i16* %x, align 2, !dbg !65
%1 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %y, i32 0, i32 0, !dbg !66
store i16 %0, i16* %1, align 2, !dbg !65
call void @llvm.dbg.declare(metadata { i16, %Foo }* %y, metadata !48, metadata !DIExpression()), !dbg !66
ret void, !dbg !67
}
```
---
src/ir.cpp | 27 +++++++++++----------------
1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 89a57e1c7a6b..ef7b4a6a0ce0 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -13377,30 +13377,25 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
}
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
- IrInstruction *ptr, IrInstruction *value)
+ IrInstruction *uncasted_ptr, IrInstruction *value)
{
- if (ptr->value.type->id != ZigTypeIdPointer) {
- ir_add_error(ira, ptr,
- buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
+ if (uncasted_ptr->value.type->id != ZigTypeIdPointer) {
+ ir_add_error(ira, uncasted_ptr,
+ buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&uncasted_ptr->value.type->name)));
return ira->codegen->invalid_instruction;
}
- Error err;
- if ((err = resolve_possible_alloca_inference(ira, ptr, value->value.type)))
- return ira->codegen->invalid_instruction;
-
- if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
+ if (uncasted_ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
return ir_const_void(ira, source_instr);
}
- if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
+ if (uncasted_ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
return ira->codegen->invalid_instruction;
}
- ZigType *child_type = ptr->value.type->data.pointer.child_type;
- IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type);
- if (casted_value == ira->codegen->invalid_instruction)
+ IrInstruction *ptr = ir_implicit_cast_result(ira, uncasted_ptr, value->value.type);
+ if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
@@ -13409,12 +13404,12 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
return ira->codegen->invalid_instruction;
}
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
- if (instr_is_comptime(casted_value)) {
+ if (instr_is_comptime(value)) {
ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, source_instr->source_node);
if (dest_val == nullptr)
return ira->codegen->invalid_instruction;
if (dest_val->special != ConstValSpecialRuntime) {
- *dest_val = casted_value->value;
+ *dest_val = value->value;
if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
}
@@ -13431,7 +13426,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
}
IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
- ptr, casted_value);
+ ptr, value);
result->value.type = ira->codegen->builtin_types.entry_void;
return result;
}
From 58a3d997f0bf3f62d91ae9dc33949c66888189eb Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 18:06:01 -0400
Subject: [PATCH 023/190] copy elision: if-err with scalar types
```zig
export fn entry() void {
var x: error!i32 = 1234;
var y = if (x) |a| a else |e| 5678;
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca { i16, i32 }, align 4
%y = alloca i32, align 4
%0 = bitcast { i16, i32 }* %x to i8*, !dbg !56
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast ({ i16, i32 }* @0 to i8*), i64 8, i1 false), !dbg !56
call void @llvm.dbg.declare(metadata { i16, i32 }* %x, metadata !45, metadata !DIExpression()), !dbg !57
%1 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %x, i32 0, i32 0, !dbg !58
%2 = load i16, i16* %1, align 2, !dbg !58
%3 = icmp ne i16 %2, 0, !dbg !58
br i1 %3, label %IfErrElse, label %IfErrThen, !dbg !58
IfErrThen: ; preds = %Entry
%4 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %x, i32 0, i32 1, !dbg !58
call void @llvm.dbg.declare(metadata i32* %4, metadata !52, metadata !DIExpression()), !dbg !58
%5 = load i32, i32* %4, align 4, !dbg !59
store i32 %5, i32* %y, align 4, !dbg !59
br label %IfErrEnd, !dbg !58
IfErrElse: ; preds = %Entry
%6 = load i16, i16* %1, align 2, !dbg !58
call void @llvm.dbg.declare(metadata i16* %1, metadata !54, metadata !DIExpression()), !dbg !58
store i32 5678, i32* %y, align 4, !dbg !61
br label %IfErrEnd, !dbg !58
IfErrEnd: ; preds = %IfErrElse, %IfErrThen
call void @llvm.dbg.declare(metadata i32* %y, metadata !55, metadata !DIExpression()), !dbg !63
ret void, !dbg !64
}
```
---
src/ir.cpp | 53 ++++++++++++++++++-----------------------------------
1 file changed, 18 insertions(+), 35 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index ef7b4a6a0ce0..c0c0170c28ba 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -10984,19 +10984,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (actual_type->id == ZigTypeIdComptimeFloat ||
actual_type->id == ZigTypeIdComptimeInt)
{
- if ((err = ensure_complete_type(ira->codegen, wanted_type)))
- return ira->codegen->invalid_instruction;
- if (wanted_type->id == ZigTypeIdEnum) {
- IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value);
- if (type_is_invalid(cast1->value.type))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
- if (type_is_invalid(cast2->value.type))
- return ira->codegen->invalid_instruction;
-
- return cast2;
- } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
+ if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
CastOp op;
if ((actual_type->id == ZigTypeIdComptimeFloat &&
wanted_type->id == ZigTypeIdFloat) ||
@@ -11211,7 +11199,7 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
}
static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *result_loc,
- ZigType *needed_child_type)
+ ZigType *needed_child_type, bool allow_failure)
{
Error err;
if (type_is_invalid(result_loc->value.type) || type_is_invalid(needed_child_type))
@@ -11278,14 +11266,18 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
needed_child_type->id == ZigTypeIdComptimeFloat)
{
IrInstruction *cast1 = ir_implicit_cast_result(ira, result_loc,
- have_child_type->data.error_union.payload_type);
+ have_child_type->data.error_union.payload_type, allow_failure);
if (type_is_invalid(cast1->value.type))
return ira->codegen->invalid_instruction;
- return ir_implicit_cast_result(ira, cast1, needed_child_type);
+ return ir_implicit_cast_result(ira, cast1, needed_child_type, allow_failure);
}
}
+ if (allow_failure) {
+ return result_loc;
+ }
+
ErrorMsg *parent_msg = ir_add_error_node(ira, source_node,
buf_sprintf("expected type '%s', found '%s'",
buf_ptr(&have_child_type->name),
@@ -13377,7 +13369,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
}
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
- IrInstruction *uncasted_ptr, IrInstruction *value)
+ IrInstruction *uncasted_ptr, IrInstruction *uncasted_value)
{
if (uncasted_ptr->value.type->id != ZigTypeIdPointer) {
ir_add_error(ira, uncasted_ptr,
@@ -13394,10 +13386,15 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
return ira->codegen->invalid_instruction;
}
- IrInstruction *ptr = ir_implicit_cast_result(ira, uncasted_ptr, value->value.type);
+ IrInstruction *ptr = ir_implicit_cast_result(ira, uncasted_ptr, uncasted_value->value.type, true);
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
+ ZigType *child_type = ptr->value.type->data.pointer.child_type;
+ IrInstruction *value = ir_implicit_cast(ira, uncasted_value, child_type);
+ if (type_is_invalid(value->value.type))
+ return ira->codegen->invalid_instruction;
+
if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
@@ -13977,7 +13974,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
IrInstruction *result_loc = nullptr;
if (call_instruction->result_loc != nullptr) {
- result_loc = ir_implicit_cast_result(ira, call_instruction->result_loc->child, return_type);
+ result_loc = ir_implicit_cast_result(ira, call_instruction->result_loc->child, return_type, false);
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
}
@@ -15434,21 +15431,7 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
static IrInstruction *ir_analyze_store_result(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
IrInstruction *uncasted_result_loc)
{
- if (instr_is_comptime(value)) {
- // No need for the ir_implicit_cast_result for comptime values.
- return ir_analyze_store_ptr(ira, source_instr, uncasted_result_loc, value);
- }
-
- if (value->id == IrInstructionIdCall && handle_is_ptr(value->value.type)) {
- // Elide this copy because it was the sret pointer in the function call.
- return ir_const_void(ira, source_instr);
- }
-
- IrInstruction *result_loc = ir_implicit_cast_result(ira, uncasted_result_loc, value->value.type);
- if (type_is_invalid(result_loc->value.type))
- return ira->codegen->invalid_instruction;
-
- return ir_analyze_store_ptr(ira, source_instr, result_loc, value);
+ zig_panic("TODO delete this instruction");
}
static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInstructionStoreResult *instruction) {
@@ -21388,7 +21371,7 @@ static IrInstruction *ir_analyze_instruction_first_arg_result_loc(IrAnalyze *ira
return ira->codegen->invalid_instruction;
IrInstruction *new_result_loc = ir_implicit_cast_result(ira, instruction->prev_result_loc->child,
- dest_type);
+ dest_type, false);
if (type_is_invalid(new_result_loc->value.type))
return ira->codegen->invalid_instruction;
return new_result_loc;
From a69436304b3a83fc96e99712b1f39b6d1fd32c5d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 18:15:13 -0400
Subject: [PATCH 024/190] copy elision: returning scalar from function
```zig
fn fail() error {
return error.Failure;
}
```
```llvm
define internal fastcc i16 @fail(%StackTrace* nonnull) unnamed_addr #2 !dbg !56 {
Entry:
call fastcc void @__zig_return_error(%StackTrace* %0), !dbg !60
ret i16 1, !dbg !60
}
```
---
src/ir.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index c0c0170c28ba..32919857d0ce 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -7381,7 +7381,9 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ZigFn *fn_entry = exec_fn_entry(irb->exec);
- irb->exec->return_result_loc = ir_build_result_return(irb, scope, node);
+ if (fn_entry != nullptr && handle_is_ptr(fn_entry->type_entry->data.fn.fn_type_id.return_type)) {
+ irb->exec->return_result_loc = ir_build_result_return(irb, scope, node);
+ }
bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
IrInstruction *coro_id;
From 00a5b728567ba410359535750ee8710b911232fd Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 30 Oct 2018 19:16:37 -0400
Subject: [PATCH 025/190] copy elision: while-optional with aggregate
```zig
export fn entry() void {
var c = false;
var x: ?Foo = foo();
var z = while (x) |a| {
_ = if (c) break a.y;
} else bar();
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%c = alloca i1, align 1
%x = alloca { %Foo, i1 }, align 4
%z = alloca %Bar, align 4
store i1 false, i1* %c, align 1, !dbg !66
call void @llvm.dbg.declare(metadata i1* %c, metadata !45, metadata !DIExpression()), !dbg !67
%0 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !68
store i1 true, i1* %0, align 1, !dbg !68
%1 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !68
call fastcc void @foo(%Foo* sret %1), !dbg !69
call void @llvm.dbg.declare(metadata { %Foo, i1 }* %x, metadata !48, metadata !DIExpression()), !dbg !68
br label %WhileCond, !dbg !70
WhileCond: ; preds = %Else, %Entry
%2 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !71
%3 = load i1, i1* %2, align 1, !dbg !71
br i1 %3, label %WhileBody, label %WhileElse, !dbg !71
WhileBody: ; preds = %WhileCond
%4 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !72
call void @llvm.dbg.declare(metadata %Foo* %4, metadata !63, metadata !DIExpression()), !dbg !70
%5 = load i1, i1* %c, align 1, !dbg !74
br i1 %5, label %Then, label %Else, !dbg !74
Then: ; preds = %WhileBody
%6 = getelementptr inbounds %Foo, %Foo* %4, i32 0, i32 1, !dbg !76
%7 = bitcast %Bar* %6 to i8*, !dbg !76
%8 = bitcast %Bar* %z to i8*, !dbg !76
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %8, i8* align 4 %7, i64 8, i1 false), !dbg !76
br label %WhileEnd, !dbg !77
Else: ; preds = %WhileBody
br label %WhileCond, !dbg !72
WhileElse: ; preds = %WhileCond
call fastcc void @bar(%Bar* sret %z), !dbg !78
br label %WhileEnd, !dbg !70
WhileEnd: ; preds = %WhileElse, %Then
call void @llvm.dbg.declare(metadata %Bar* %z, metadata !65, metadata !DIExpression()), !dbg !79
ret void, !dbg !80
}
```
---
src/codegen.cpp | 6 ++-
src/ir.cpp | 99 +++++++++++++++++++++----------------------------
2 files changed, 46 insertions(+), 59 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 88f72dd5ca8e..ec710304d145 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -6322,8 +6322,10 @@ static void do_code_gen(CodeGen *g) {
ZigType *ptr_type = instruction->base.value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *child_type = ptr_type->data.pointer.child_type;
- instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
- get_ptr_align(g, ptr_type));
+ if (type_has_bits(child_type)) {
+ instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
+ get_ptr_align(g, ptr_type));
+ }
}
ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
diff --git a/src/ir.cpp b/src/ir.cpp
index 32919857d0ce..aadc4a2e1c25 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5323,7 +5323,9 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, alloca);
}
-static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
+static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeWhileExpr);
AstNode *continue_expr_node = node->data.while_expr.continue_expr;
@@ -5358,14 +5360,17 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
} else {
payload_scope = subexpr_scope;
}
- IrInstruction *err_val_ptr = ir_gen_node(irb, node->data.while_expr.condition, subexpr_scope,
+ IrInstruction *err_union_ptr = ir_gen_node(irb, node->data.while_expr.condition, subexpr_scope,
LValPtr, nullptr);
- if (err_val_ptr == irb->codegen->invalid_instruction)
- return err_val_ptr;
- IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr, nullptr);
- IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val);
- IrBasicBlock *after_cond_block = irb->current_basic_block;
- IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
+ if (type_is_invalid(err_union_ptr->value.type))
+ return err_union_ptr;
+
+ IrInstruction *ptr_opt_err_code = ir_build_error_union_field_error_set(irb, scope,
+ node->data.while_expr.condition, err_union_ptr);
+ IrInstruction *opt_err_code = ir_build_load_ptr(irb, scope, node->data.while_expr.condition,
+ ptr_opt_err_code, nullptr);
+ IrInstruction *is_err = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, opt_err_code);
+
if (!instr_is_unreachable(is_err)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err,
else_block, body_block, is_comptime));
@@ -5373,11 +5378,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, body_block);
if (var_symbol) {
- IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node,
- err_val_ptr, false);
- IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
- ir_build_ref(irb, payload_scope, symbol_node, var_ptr_value, true, false) : var_ptr_value;
- ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
+ IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node,
+ err_union_ptr, false);
+ IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ?
+ ir_build_ref(irb, payload_scope, symbol_node, payload_ptr, true, false) : payload_ptr;
+ ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_ptr);
}
ZigList incoming_values = {0};
@@ -5419,8 +5424,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ZigVar *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol,
true, false, false, is_comptime);
Scope *err_scope = err_var->child_scope;
- IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);
- ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value);
+ IrInstruction *unwrapped_err_code_ptr = ir_build_unwrap_maybe(irb, err_scope, err_symbol_node,
+ ptr_opt_err_code, false);
+ ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, unwrapped_err_code_ptr);
else_result = ir_gen_node(irb, else_node, err_scope, LValNone, result_loc);
if (else_result == irb->codegen->invalid_instruction)
@@ -5428,17 +5434,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
}
- IrBasicBlock *after_else_block = irb->current_basic_block;
- ir_set_cursor_at_end_and_append_block(irb, end_block);
- if (else_result) {
- incoming_blocks.append(after_else_block);
- incoming_values.append(else_result);
- } else {
- incoming_blocks.append(after_cond_block);
- incoming_values.append(void_else_result);
- }
- return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
+ ir_set_cursor_at_end_and_append_block(irb, end_block);
+ return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
} else if (var_symbol != nullptr) {
ir_set_cursor_at_end_and_append_block(irb, cond_block);
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
@@ -5454,18 +5452,16 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
return maybe_val_ptr;
IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr, nullptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val);
- IrBasicBlock *after_cond_block = irb->current_basic_block;
- IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
if (!instr_is_unreachable(is_non_null)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null,
body_block, else_block, is_comptime));
}
ir_set_cursor_at_end_and_append_block(irb, body_block);
- IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
- IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
- ir_build_ref(irb, child_scope, symbol_node, var_ptr_value, true, false) : var_ptr_value;
- ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
+ IrInstruction *payload_ptr = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
+ IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ?
+ ir_build_ref(irb, child_scope, symbol_node, payload_ptr, true, false) : payload_ptr;
+ ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_ptr);
ZigList incoming_values = {0};
ZigList incoming_blocks = {0};
@@ -5480,7 +5476,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base,
LValNone, result_loc);
- if (body_result == irb->codegen->invalid_instruction)
+ if (type_is_invalid(body_result->value.type))
return body_result;
if (!instr_is_unreachable(body_result)) {
@@ -5507,24 +5503,13 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
}
- IrBasicBlock *after_else_block = irb->current_basic_block;
ir_set_cursor_at_end_and_append_block(irb, end_block);
- if (else_result) {
- incoming_blocks.append(after_else_block);
- incoming_values.append(else_result);
- } else {
- incoming_blocks.append(after_cond_block);
- incoming_values.append(void_else_result);
- }
-
- return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
+ return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
} else {
ir_set_cursor_at_end_and_append_block(irb, cond_block);
IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope, LValNone, nullptr);
if (cond_val == irb->codegen->invalid_instruction)
return cond_val;
- IrBasicBlock *after_cond_block = irb->current_basic_block;
- IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
if (!instr_is_unreachable(cond_val)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,
body_block, else_block, is_comptime));
@@ -5574,17 +5559,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
}
- IrBasicBlock *after_else_block = irb->current_basic_block;
- ir_set_cursor_at_end_and_append_block(irb, end_block);
- if (else_result) {
- incoming_blocks.append(after_else_block);
- incoming_values.append(else_result);
- } else {
- incoming_blocks.append(after_cond_block);
- incoming_values.append(void_else_result);
- }
- return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
+ ir_set_cursor_at_end_and_append_block(irb, end_block);
+ return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
}
}
@@ -5944,7 +5921,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
Buf *err_symbol = node->data.if_err_expr.err_symbol;
IrInstruction *err_union_ptr = ir_gen_node(irb, target_node, scope, LValPtr, nullptr);
- if (err_union_ptr == irb->codegen->invalid_instruction)
+ if (type_is_invalid(err_union_ptr->value.type))
return err_union_ptr;
IrInstruction *ptr_opt_err_code = ir_build_error_union_field_error_set(irb, scope, node, err_union_ptr);
@@ -7216,6 +7193,12 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
}
+static IrInstruction *ensure_result_loc(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
+ if (result_loc)
+ return result_loc;
+ return ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
+}
+
static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
IrInstruction *result_loc)
{
@@ -7248,7 +7231,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeFnCallExpr:
return ir_gen_fn_call(irb, scope, node, lval, result_loc);
case NodeTypeIfBoolExpr:
- return ir_gen_if_bool_expr(irb, scope, node, lval, result_loc);
+ return ir_gen_if_bool_expr(irb, scope, node, lval,
+ ensure_result_loc(irb, scope, node, result_loc));
case NodeTypePrefixOpExpr:
return ir_gen_prefix_op_expr(irb, scope, node, lval);
case NodeTypeContainerInitExpr:
@@ -7256,7 +7240,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeVariableDeclaration:
return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval);
case NodeTypeWhileExpr:
- return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node, result_loc), lval);
+ return ir_gen_while_expr(irb, scope, node, lval,
+ ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeForExpr:
return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node, result_loc), lval);
case NodeTypeArrayAccessExpr:
From 167c37ee553e709129df2796d96d5a9124ae0829 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 31 Oct 2018 10:20:45 -0400
Subject: [PATCH 026/190] copy elision: while-bool with aggregate
```zig
export fn entry() void {
var c = false;
var z = while (c) {
if (c) break bar2();
} else bar();
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%c = alloca i1, align 1
%z = alloca %Bar, align 4
store i1 false, i1* %c, align 1, !dbg !55
call void @llvm.dbg.declare(metadata i1* %c, metadata !45, metadata !DIExpression()), !dbg !56
br label %WhileCond, !dbg !57
WhileCond: ; preds = %Else, %Entry
%0 = load i1, i1* %c, align 1, !dbg !58
br i1 %0, label %WhileBody, label %WhileElse, !dbg !58
WhileBody: ; preds = %WhileCond
%1 = load i1, i1* %c, align 1, !dbg !59
br i1 %1, label %Then, label %Else, !dbg !59
Then: ; preds = %WhileBody
call fastcc void @bar2(%Bar* sret %z), !dbg !61
br label %WhileEnd, !dbg !62
Else: ; preds = %WhileBody
br label %WhileCond, !dbg !57
WhileElse: ; preds = %WhileCond
call fastcc void @bar(%Bar* sret %z), !dbg !63
br label %WhileEnd, !dbg !57
WhileEnd: ; preds = %WhileElse, %Then
call void @llvm.dbg.declare(metadata %Bar* %z, metadata !48, metadata !DIExpression()), !dbg !64
ret void, !dbg !65
}
```
---
src/ir.cpp | 64 +++++++++++++++++++++++++++++-------------------------
1 file changed, 35 insertions(+), 29 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index aadc4a2e1c25..1a5a276d3304 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5070,6 +5070,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
return irb->codegen->invalid_instruction;
} else {
else_expr_result = ir_build_const_void(irb, scope, node);
+ ir_build_store_ptr(irb, scope, node, result_loc, else_expr_result);
}
if (!instr_is_unreachable(else_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
@@ -5336,8 +5337,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrBasicBlock *continue_block = continue_expr_node ?
ir_create_basic_block(irb, scope, "WhileContinue") : cond_block;
IrBasicBlock *end_block = ir_create_basic_block(irb, scope, "WhileEnd");
- IrBasicBlock *else_block = else_node ?
- ir_create_basic_block(irb, scope, "WhileElse") : end_block;
+ IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "WhileElse");
IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node,
ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline);
@@ -5415,25 +5415,22 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_mark_gen(ir_build_br(irb, payload_scope, node, cond_block, is_comptime));
}
- IrInstruction *else_result = nullptr;
- if (else_node) {
- ir_set_cursor_at_end_and_append_block(irb, else_block);
+ ir_set_cursor_at_end_and_append_block(irb, else_block);
- // TODO make it an error to write to error variable
- AstNode *err_symbol_node = else_node; // TODO make more accurate
- ZigVar *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol,
- true, false, false, is_comptime);
- Scope *err_scope = err_var->child_scope;
- IrInstruction *unwrapped_err_code_ptr = ir_build_unwrap_maybe(irb, err_scope, err_symbol_node,
- ptr_opt_err_code, false);
- ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, unwrapped_err_code_ptr);
+ // TODO make it an error to write to error variable
+ AstNode *err_symbol_node = else_node; // TODO make more accurate
+ ZigVar *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol,
+ true, false, false, is_comptime);
+ Scope *err_scope = err_var->child_scope;
+ IrInstruction *unwrapped_err_code_ptr = ir_build_unwrap_maybe(irb, err_scope, err_symbol_node,
+ ptr_opt_err_code, false);
+ ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, unwrapped_err_code_ptr);
- else_result = ir_gen_node(irb, else_node, err_scope, LValNone, result_loc);
- if (else_result == irb->codegen->invalid_instruction)
- return else_result;
- if (!instr_is_unreachable(else_result))
- ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
- }
+ IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope, LValNone, result_loc);
+ if (else_result == irb->codegen->invalid_instruction)
+ return else_result;
+ if (!instr_is_unreachable(else_result))
+ ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, end_block);
return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
@@ -5493,16 +5490,19 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_mark_gen(ir_build_br(irb, child_scope, node, cond_block, is_comptime));
}
+ ir_set_cursor_at_end_and_append_block(irb, else_block);
IrInstruction *else_result = nullptr;
if (else_node) {
- ir_set_cursor_at_end_and_append_block(irb, else_block);
-
else_result = ir_gen_node(irb, else_node, scope, LValNone, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
- if (!instr_is_unreachable(else_result))
- ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
+ } else {
+ else_result = ir_build_const_void(irb, scope, node);
+ ir_build_store_ptr(irb, scope, node, result_loc, else_result);
}
+ if (!instr_is_unreachable(else_result))
+ ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
+
ir_set_cursor_at_end_and_append_block(irb, end_block);
return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
} else {
@@ -5549,16 +5549,18 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_mark_gen(ir_build_br(irb, scope, node, cond_block, is_comptime));
}
+ ir_set_cursor_at_end_and_append_block(irb, else_block);
IrInstruction *else_result = nullptr;
if (else_node) {
- ir_set_cursor_at_end_and_append_block(irb, else_block);
-
else_result = ir_gen_node(irb, else_node, subexpr_scope, LValNone, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
- if (!instr_is_unreachable(else_result))
- ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
+ } else {
+ else_result = ir_build_const_void(irb, subexpr_scope, node);
+ ir_build_store_ptr(irb, subexpr_scope, node, result_loc, else_result);
}
+ if (!instr_is_unreachable(else_result))
+ ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, end_block);
return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
@@ -5899,6 +5901,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
return else_expr_result;
} else {
else_expr_result = ir_build_const_void(irb, scope, node);
+ ir_build_store_ptr(irb, scope, node, result_loc, else_expr_result);
}
if (!instr_is_unreachable(else_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
@@ -5988,6 +5991,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
return else_expr_result;
} else {
else_expr_result = ir_build_const_void(irb, scope, node);
+ ir_build_store_ptr(irb, scope, node, result_loc, else_expr_result);
}
if (!instr_is_unreachable(else_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
@@ -7288,9 +7292,11 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeNullLiteral:
return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_null_literal(irb, scope, node));
case NodeTypeIfErrorExpr:
- return ir_gen_if_err_expr(irb, scope, node, lval, result_loc);
+ return ir_gen_if_err_expr(irb, scope, node, lval,
+ ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeIfOptional:
- return ir_gen_if_optional_expr(irb, scope, node, lval, result_loc);
+ return ir_gen_if_optional_expr(irb, scope, node, lval,
+ ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeSwitchExpr:
return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node, result_loc), lval);
case NodeTypeCompTime:
From 6af39bc370a03213ff5ca7e8f66c24b3b4ca4caf Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 31 Oct 2018 11:03:21 -0400
Subject: [PATCH 027/190] copy elision: while-err with aggregates
```zig
export fn entry() void {
var x = true;
var y: error!Foo = foo();
var z = while (y) |a| {
if (x) break a.y;
} else |e| bar();
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca i1, align 1
%y = alloca { i16, %Foo }, align 4
%z = alloca %Bar, align 4
store i1 true, i1* %x, align 1, !dbg !67
call void @llvm.dbg.declare(metadata i1* %x, metadata !45, metadata !DIExpression()), !dbg !68
%0 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %y, i32 0, i32 0, !dbg !69
store i16 0, i16* %0, align 2, !dbg !69
%1 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %y, i32 0, i32 1, !dbg !69
call fastcc void @foo(%Foo* sret %1), !dbg !70
call void @llvm.dbg.declare(metadata { i16, %Foo }* %y, metadata !48, metadata !DIExpression()), !dbg !69
br label %WhileCond, !dbg !71
WhileCond: ; preds = %Else, %Entry
%2 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %y, i32 0, i32 0, !dbg !72
%3 = load i16, i16* %2, align 2, !dbg !72
%4 = icmp ne i16 %3, 0, !dbg !72
br i1 %4, label %WhileElse, label %WhileBody, !dbg !72
WhileBody: ; preds = %WhileCond
%5 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %y, i32 0, i32 1, !dbg !73
call void @llvm.dbg.declare(metadata %Foo* %5, metadata !63, metadata !DIExpression()), !dbg !71
%6 = load i1, i1* %x, align 1, !dbg !75
br i1 %6, label %Then, label %Else, !dbg !75
Then: ; preds = %WhileBody
%7 = getelementptr inbounds %Foo, %Foo* %5, i32 0, i32 1, !dbg !77
%8 = bitcast %Bar* %7 to i8*, !dbg !77
%9 = bitcast %Bar* %z to i8*, !dbg !77
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %8, i64 8, i1 false), !dbg !77
br label %WhileEnd, !dbg !78
Else: ; preds = %WhileBody
br label %WhileCond, !dbg !73
WhileElse: ; preds = %WhileCond
%10 = load i16, i16* %2, align 2, !dbg !79
call void @llvm.dbg.declare(metadata i16* %2, metadata !65, metadata !DIExpression()), !dbg !81
call fastcc void @bar(%Bar* sret %z), !dbg !79
br label %WhileEnd, !dbg !71
WhileEnd: ; preds = %WhileElse, %Then
call void @llvm.dbg.declare(metadata %Bar* %z, metadata !66, metadata !DIExpression()), !dbg !82
ret void, !dbg !83
}
```
---
src/ir.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 1a5a276d3304..64e623ec44ba 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5362,7 +5362,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
}
IrInstruction *err_union_ptr = ir_gen_node(irb, node->data.while_expr.condition, subexpr_scope,
LValPtr, nullptr);
- if (type_is_invalid(err_union_ptr->value.type))
+ if (err_union_ptr == irb->codegen->invalid_instruction)
return err_union_ptr;
IrInstruction *ptr_opt_err_code = ir_build_error_union_field_error_set(irb, scope,
@@ -5473,7 +5473,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base,
LValNone, result_loc);
- if (type_is_invalid(body_result->value.type))
+ if (body_result == irb->codegen->invalid_instruction)
return body_result;
if (!instr_is_unreachable(body_result)) {
@@ -5924,7 +5924,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
Buf *err_symbol = node->data.if_err_expr.err_symbol;
IrInstruction *err_union_ptr = ir_gen_node(irb, target_node, scope, LValPtr, nullptr);
- if (type_is_invalid(err_union_ptr->value.type))
+ if (err_union_ptr == irb->codegen->invalid_instruction)
return err_union_ptr;
IrInstruction *ptr_opt_err_code = ir_build_error_union_field_error_set(irb, scope, node, err_union_ptr);
From 25306e3c606f6260feccd18a3a234657e01acc05 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Nov 2018 15:19:26 -0400
Subject: [PATCH 028/190] result location mechanism gains ability to infer
comptime
* introduce ConstPtrMutInfer
* `?error` is represented in comptime values the same as `error`
* this test case works now:
```zig
export fn entry() void {
if ((Bar.{
.x = 3,
.y = 4,
}).x != 3) {
@compileError("this compile error should not trigger");
}
}
```
This commit comments out code and makes StructFieldInit instruction
obselete. Come back and clean this up.
---
src/all_types.hpp | 7 +-
src/analyze.cpp | 9 +-
src/codegen.cpp | 21 ++-
src/ir.cpp | 446 ++++++++++++++++++++++++++--------------------
src/ir_print.cpp | 5 +-
5 files changed, 276 insertions(+), 212 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 506615e59c29..310a3292f581 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -180,6 +180,9 @@ enum ConstPtrMut {
// The pointer points to memory that is known only at runtime.
// For example it may point to the initializer value of a variable.
ConstPtrMutRuntimeVar,
+ // The pointer points to memory for which it must be inferred whether the
+ // value is comptime known or not.
+ ConstPtrMutInfer,
};
struct ConstPtrValue {
@@ -211,7 +214,7 @@ struct ConstPtrValue {
};
struct ConstErrValue {
- ErrorTableEntry *err;
+ ConstExprValue *error_set;
ConstExprValue *payload;
};
@@ -2458,7 +2461,6 @@ struct IrInstructionContainerInitList {
struct IrInstructionContainerInitFieldsField {
Buf *name;
- IrInstruction *value;
IrInstruction *result_loc;
AstNode *source_node;
TypeStructField *type_struct_field;
@@ -2470,6 +2472,7 @@ struct IrInstructionContainerInitFields {
IrInstruction *container_type;
size_t field_count;
IrInstructionContainerInitFieldsField *fields;
+ IrInstruction *result_loc;
};
struct IrInstructionStructInitField {
diff --git a/src/analyze.cpp b/src/analyze.cpp
index ed8b286d6759..b4a8e10f7809 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -4739,6 +4739,8 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
case ConstPtrMutComptimeVar:
hash_val += (uint32_t)1103195694;
break;
+ case ConstPtrMutInfer:
+ zig_unreachable();
}
switch (const_val->data.x_ptr.special) {
case ConstPtrSpecialInvalid:
@@ -4982,7 +4984,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
return can_mutate_comptime_var_state(value->data.x_optional);
case ZigTypeIdErrorUnion:
- if (value->data.x_err_union.err != nullptr)
+ if (value->data.x_err_union.error_set->data.x_err_set != nullptr)
return false;
assert(value->data.x_err_union.payload != nullptr);
return can_mutate_comptime_var_state(value->data.x_err_union.payload);
@@ -5943,11 +5945,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
case ZigTypeIdErrorUnion:
{
buf_appendf(buf, "%s(", buf_ptr(&type_entry->name));
- if (const_val->data.x_err_union.err == nullptr) {
+ ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+ if (err_set == nullptr) {
render_const_value(g, buf, const_val->data.x_err_union.payload);
} else {
buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name),
- buf_ptr(&const_val->data.x_err_union.err->name));
+ buf_ptr(&err_set->name));
}
buf_appendf(buf, ")");
return;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index ec710304d145..f27a46922f9b 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5703,6 +5703,11 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
zig_unreachable();
}
+static LLVMValueRef gen_const_val_err_set(CodeGen *g, ConstExprValue *const_val, const char *name) {
+ uint64_t value = (const_val->data.x_err_set == nullptr) ? 0 : const_val->data.x_err_set->value;
+ return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, value, false);
+}
+
static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
ZigType *type_entry = const_val->type;
assert(!type_entry->zero_bits);
@@ -5720,9 +5725,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
case ZigTypeIdInt:
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
case ZigTypeIdErrorSet:
- assert(const_val->data.x_err_set != nullptr);
- return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref,
- const_val->data.x_err_set->value, false);
+ return gen_const_val_err_set(g, const_val, name);
case ZigTypeIdFloat:
switch (type_entry->data.floating.bit_count) {
case 16:
@@ -5757,7 +5760,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
} else if (type_is_codegen_pointer(child_type)) {
return gen_const_val_ptr(g, const_val, name);
} else if (child_type->id == ZigTypeIdErrorSet) {
- zig_panic("TODO");
+ return gen_const_val_err_set(g, const_val, name);
} else {
LLVMValueRef child_val;
LLVMValueRef maybe_val;
@@ -5986,7 +5989,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
ZigType *err_set_type = type_entry->data.error_union.err_set_type;
if (!type_has_bits(payload_type)) {
assert(type_has_bits(err_set_type));
- uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
+ ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+ uint64_t value = (err_set == nullptr) ? 0 : err_set->value;
return LLVMConstInt(g->err_tag_type->type_ref, value, false);
} else if (!type_has_bits(err_set_type)) {
assert(type_has_bits(payload_type));
@@ -5995,8 +5999,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
LLVMValueRef err_tag_value;
LLVMValueRef err_payload_value;
bool make_unnamed_struct;
- if (const_val->data.x_err_union.err) {
- err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false);
+ ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+ if (err_set != nullptr) {
+ err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, err_set->value, false);
err_payload_value = LLVMConstNull(payload_type->type_ref);
make_unnamed_struct = false;
} else {
@@ -6322,7 +6327,7 @@ static void do_code_gen(CodeGen *g) {
ZigType *ptr_type = instruction->base.value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *child_type = ptr_type->data.pointer.child_type;
- if (type_has_bits(child_type)) {
+ if (type_has_bits(child_type) && instruction->base.value.special == ConstValSpecialRuntime) {
instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
get_ptr_align(g, ptr_type));
}
diff --git a/src/ir.cpp b/src/ir.cpp
index 64e623ec44ba..9d3e7d0b4158 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -188,6 +188,11 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
return result;
}
+static bool is_opt_err_set(ZigType *ty) {
+ return ty->id == ZigTypeIdErrorSet ||
+ (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet);
+}
+
static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
if (a == b)
return true;
@@ -198,6 +203,9 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr)
return true;
+ if (is_opt_err_set(a) && is_opt_err_set(b))
+ return true;
+
return false;
}
@@ -1332,48 +1340,51 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope,
}
static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields)
+ IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields,
+ IrInstruction *result_loc)
{
IrInstructionContainerInitFields *container_init_fields_instruction =
ir_build_instruction(irb, scope, source_node);
container_init_fields_instruction->container_type = container_type;
container_init_fields_instruction->field_count = field_count;
container_init_fields_instruction->fields = fields;
+ container_init_fields_instruction->result_loc = result_loc;
ir_ref_instruction(container_type, irb->current_basic_block);
for (size_t i = 0; i < field_count; i += 1) {
- ir_ref_instruction(fields[i].value, irb->current_basic_block);
+ ir_ref_instruction(fields[i].result_loc, irb->current_basic_block);
}
+ ir_ref_instruction(result_loc, irb->current_basic_block);
return &container_init_fields_instruction->base;
}
-static IrInstruction *ir_build_struct_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
- ZigType *struct_type, size_t field_count, IrInstructionStructInitField *fields)
-{
- IrInstructionStructInit *struct_init_instruction = ir_build_instruction(irb, scope, source_node);
- struct_init_instruction->struct_type = struct_type;
- struct_init_instruction->field_count = field_count;
- struct_init_instruction->fields = fields;
-
- for (size_t i = 0; i < field_count; i += 1)
- ir_ref_instruction(fields[i].value, irb->current_basic_block);
-
- return &struct_init_instruction->base;
-}
-
-static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
- ZigType *union_type, TypeUnionField *field, IrInstruction *init_value)
-{
- IrInstructionUnionInit *union_init_instruction = ir_build_instruction(irb, scope, source_node);
- union_init_instruction->union_type = union_type;
- union_init_instruction->field = field;
- union_init_instruction->init_value = init_value;
-
- ir_ref_instruction(init_value, irb->current_basic_block);
-
- return &union_init_instruction->base;
-}
+//static IrInstruction *ir_build_struct_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
+// ZigType *struct_type, size_t field_count, IrInstructionStructInitField *fields)
+//{
+// IrInstructionStructInit *struct_init_instruction = ir_build_instruction(irb, scope, source_node);
+// struct_init_instruction->struct_type = struct_type;
+// struct_init_instruction->field_count = field_count;
+// struct_init_instruction->fields = fields;
+//
+// for (size_t i = 0; i < field_count; i += 1)
+// ir_ref_instruction(fields[i].value, irb->current_basic_block);
+//
+// return &struct_init_instruction->base;
+//}
+
+//static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
+// ZigType *union_type, TypeUnionField *field, IrInstruction *init_value)
+//{
+// IrInstructionUnionInit *union_init_instruction = ir_build_instruction(irb, scope, source_node);
+// union_init_instruction->union_type = union_type;
+// union_init_instruction->field = field;
+// union_init_instruction->init_value = init_value;
+//
+// ir_ref_instruction(init_value, irb->current_basic_block);
+//
+// return &union_init_instruction->base;
+//}
static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionUnreachable *unreachable_instruction =
@@ -3142,7 +3153,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime);
}
-static IrInstruction *ir_gen_lval_ptr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+static IrInstruction *ir_gen_result(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc)
{
switch (lval) {
@@ -3164,7 +3175,7 @@ static IrInstruction *ir_gen_value(IrBuilder *irb, Scope *scope, AstNode *node,
ir_build_store_ptr(irb, scope, node, result_loc, value);
if (lval != LValNone) {
assert(lval != LValPtr);
- return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
}
}
return ir_lval_wrap(irb, scope, value, lval);
@@ -3306,7 +3317,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
}
ir_set_cursor_at_end_and_append_block(irb, continue_block);
- return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
}
}
zig_unreachable();
@@ -3620,7 +3631,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode
ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, end_block);
- return ir_gen_lval_ptr(irb, parent_scope, node, lval, result_loc);
+ return ir_gen_result(irb, parent_scope, node, lval, result_loc);
}
static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@@ -5076,7 +5087,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, endif_block);
- return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
}
static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id) {
@@ -5167,7 +5178,7 @@ static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, Ast
IrInstruction *err_code = ir_build_load_ptr(irb, scope, source_node, err_code_ptr, nullptr);
ir_build_assert_non_error(irb, scope, source_node, err_code);
- return ir_gen_lval_ptr(irb, scope, source_node, lval, result_loc);
+ return ir_gen_result(irb, scope, source_node, lval, result_loc);
}
static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -5207,7 +5218,7 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
zig_unreachable();
}
-static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node,
+static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc)
{
assert(node->type == NodeTypeContainerInitExpr);
@@ -5236,10 +5247,11 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
return expr_value;
fields[i].name = name;
- fields[i].value = expr_value;
+ fields[i].result_loc = field_result_loc;
fields[i].source_node = entry_node;
}
- return ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields);
+ ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
} else if (kind == ContainerInitKindArray) {
size_t item_count = container_init_expr->entries.length;
IrInstruction **values = allocate(item_count);
@@ -5254,7 +5266,8 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
values[i] = expr_value;
}
- return ir_build_container_init_list(irb, scope, node, container_type, item_count, values);
+ ir_build_container_init_list(irb, scope, node, container_type, item_count, values);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
} else {
zig_unreachable();
}
@@ -5433,7 +5446,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, end_block);
- return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
} else if (var_symbol != nullptr) {
ir_set_cursor_at_end_and_append_block(irb, cond_block);
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
@@ -5504,7 +5517,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, end_block);
- return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
} else {
ir_set_cursor_at_end_and_append_block(irb, cond_block);
IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope, LValNone, nullptr);
@@ -5563,7 +5576,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, end_block);
- return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
}
}
@@ -5907,7 +5920,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, endif_block);
- return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
}
static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
@@ -5997,7 +6010,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, endif_block);
- return ir_gen_lval_ptr(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
}
static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node,
@@ -6511,7 +6524,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
ir_mark_gen(ir_build_br(irb, err_scope, node, end_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, end_block);
- return ir_gen_lval_ptr(irb, parent_scope, node, lval, result_loc);
+ return ir_gen_result(irb, parent_scope, node, lval, result_loc);
}
static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *outer_scope, Scope *inner_scope) {
@@ -7240,7 +7253,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypePrefixOpExpr:
return ir_gen_prefix_op_expr(irb, scope, node, lval);
case NodeTypeContainerInitExpr:
- return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node, result_loc), lval);
+ return ir_gen_container_init_expr(irb, scope, node, lval,
+ ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeVariableDeclaration:
return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval);
case NodeTypeWhileExpr:
@@ -9821,7 +9835,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
fprintf(stderr, "\nSource: ");
ast_render(codegen, stderr, node, 4);
fprintf(stderr, "\n{ // (IR)\n");
- ir_print(codegen, stderr, ir_executable, 4);
+ ir_print(codegen, stderr, ir_executable, 2);
fprintf(stderr, "}\n");
}
IrExecutable *analyzed_executable = allocate(1);
@@ -9841,7 +9855,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
if (codegen->verbose_ir) {
fprintf(stderr, "{ // (analyzed)\n");
- ir_print(codegen, stderr, analyzed_executable, 4);
+ ir_print(codegen, stderr, analyzed_executable, 2);
fprintf(stderr, "}\n");
}
@@ -9924,14 +9938,36 @@ static IrInstruction *ir_analyze_result_error_union_payload(IrAnalyze *ira, IrIn
static IrInstruction *ir_analyze_result_error_union_code(IrAnalyze *ira, IrInstruction *result_loc,
ZigType *needed_child_type)
{
- if (instr_is_comptime(result_loc)) {
- zig_panic("TODO comptime ir_analyze_result_error_union_code");
- }
ZigType *old_ptr_type = result_loc->value.type;
assert(old_ptr_type->id == ZigTypeIdPointer);
ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+ if (instr_is_comptime(result_loc) && result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) {
+ ConstExprValue *const_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (const_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ ConstExprValue *error_union_val = const_ptr_pointee(ira->codegen, const_val);
+ assert(error_union_val->type->id == ZigTypeIdErrorUnion);
+
+ if (error_union_val->special == ConstValSpecialUndef) {
+ ConstExprValue *err_set_val = create_const_vals(1);
+ err_set_val->type = error_union_val->type->data.error_union.err_set_type;
+ err_set_val->special = ConstValSpecialUndef;
+
+ error_union_val->data.x_err_union.error_set = err_set_val;
+ error_union_val->special = ConstValSpecialStatic;
+ }
+ assert(error_union_val->data.x_err_union.error_set != nullptr);
+
+ IrInstruction *result = ir_const(ira, result_loc, new_ptr_type);
+ ConstExprValue *result_val = &result->value;
+ result_val->data.x_ptr.special = ConstPtrSpecialRef;
+ result_val->data.x_ptr.mut = result_loc->value.data.x_ptr.mut;
+ result_val->data.x_ptr.data.ref.pointee = error_union_val->data.x_err_union.error_set;
+ return result;
+ }
+
IrInstruction *result = ir_build_result_error_union_code(&ira->new_irb, result_loc->scope,
result_loc->source_node, result_loc);
result->value.type = new_ptr_type;
@@ -9986,11 +10022,16 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
if (!val)
return ira->codegen->invalid_instruction;
+ ConstExprValue *err_set_val = create_const_vals(1);
+ err_set_val->type = wanted_type->data.error_union.err_set_type;
+ err_set_val->special = ConstValSpecialStatic;
+ err_set_val->data.x_err_set = nullptr;
+
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
const_instruction->base.value.type = wanted_type;
const_instruction->base.value.special = ConstValSpecialStatic;
- const_instruction->base.value.data.x_err_union.err = nullptr;
+ const_instruction->base.value.data.x_err_union.error_set = err_set_val;
const_instruction->base.value.data.x_err_union.payload = val;
return &const_instruction->base;
}
@@ -10054,11 +10095,16 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
if (!val)
return ira->codegen->invalid_instruction;
+ ConstExprValue *err_set_val = create_const_vals(1);
+ err_set_val->special = ConstValSpecialStatic;
+ err_set_val->type = wanted_type->data.error_union.err_set_type;
+ err_set_val->data.x_err_set = val->data.x_err_set;
+
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
const_instruction->base.value.type = wanted_type;
const_instruction->base.value.special = ConstValSpecialStatic;
- const_instruction->base.value.data.x_err_union.err = val->data.x_err_set;
+ const_instruction->base.value.data.x_err_union.error_set = err_set_val;
const_instruction->base.value.data.x_err_union.payload = nullptr;
return &const_instruction->base;
}
@@ -10509,7 +10555,7 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
ErrorTableEntry *err;
if (err_type->id == ZigTypeIdErrorUnion) {
- err = val->data.x_err_union.err;
+ err = val->data.x_err_union.error_set->data.x_err_set;
} else if (err_type->id == ZigTypeIdErrorSet) {
err = val->data.x_err_set;
} else {
@@ -11138,6 +11184,7 @@ static Error resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *al
Error err;
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
return err;
+ alloca->base.value.data.x_ptr.data.ref.pointee->type = child_type;
alloca->base.value.type = get_pointer_to_type_extra(ira->codegen, child_type, false, false,
PtrLenSingle, alloca->align, 0, 0);
return ErrorNone;
@@ -13294,9 +13341,7 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) {
return fn_entry->variable_list.at(next_var_i);
}
-static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
- ZigVar *var)
-{
+static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) {
while (var->next_var != nullptr) {
var = var->next_var;
}
@@ -13393,7 +13438,9 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
return ira->codegen->invalid_instruction;
}
- if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
+ if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar ||
+ ptr->value.data.x_ptr.mut == ConstPtrMutInfer)
+ {
if (instr_is_comptime(value)) {
ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, source_instr->source_node);
if (dest_val == nullptr)
@@ -13403,15 +13450,22 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
}
+ if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ }
return ir_const_void(ira, source_instr);
}
}
- ir_add_error(ira, source_instr,
- buf_sprintf("cannot store runtime value in compile time variable"));
- ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
- dest_val->type = ira->codegen->builtin_types.entry_invalid;
+ if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
+ } else {
+ ir_add_error(ira, source_instr,
+ buf_sprintf("cannot store runtime value in compile time variable"));
+ ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
+ dest_val->type = ira->codegen->builtin_types.entry_invalid;
- return ira->codegen->invalid_instruction;
+ return ira->codegen->invalid_instruction;
+ }
}
}
@@ -13583,10 +13637,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
if (inferred_err_set_type != nullptr) {
inferred_err_set_type->data.error_set.infer_fn = nullptr;
if (result->value.type->id == ZigTypeIdErrorUnion) {
- if (result->value.data.x_err_union.err != nullptr) {
+ ErrorTableEntry *err = result->value.data.x_err_union.error_set->data.x_err_set;
+ if (err != nullptr) {
inferred_err_set_type->data.error_set.err_count = 1;
inferred_err_set_type->data.error_set.errors = allocate(1);
- inferred_err_set_type->data.error_set.errors[0] = result->value.data.x_err_union.err;
+ inferred_err_set_type->data.error_set.errors[0] = err;
}
ZigType *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type;
inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count;
@@ -14828,6 +14883,18 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
return ira->codegen->invalid_instruction;
if (type_is_invalid(struct_val->type))
return ira->codegen->invalid_instruction;
+
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer &&
+ struct_val->special == ConstValSpecialUndef)
+ {
+ struct_val->data.x_struct.fields = create_const_vals(bare_type->data.structure.src_field_count);
+ struct_val->special = ConstValSpecialStatic;
+ for (size_t i = 0; i < bare_type->data.structure.src_field_count; i += 1) {
+ ConstExprValue *field_val = &struct_val->data.x_struct.fields[i];
+ field_val->special = ConstValSpecialUndef;
+ field_val->type = bare_type->data.structure.fields[i].type_entry;
+ }
+ }
ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index];
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_val->type,
is_const, is_volatile, PtrLenSingle, align_bytes,
@@ -14836,7 +14903,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
IrInstruction *result = ir_const(ira, source_instr, ptr_type);
ConstExprValue *const_val = &result->value;
const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
- const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut;
+ const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
const_val->data.x_ptr.data.base_struct.struct_val = struct_val;
const_val->data.x_ptr.data.base_struct.field_index = field->src_index;
return result;
@@ -16536,74 +16603,75 @@ static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRe
static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction,
ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)
{
- Error err;
- assert(container_type->id == ZigTypeIdUnion);
-
- if ((err = ensure_complete_type(ira->codegen, container_type)))
- return ira->codegen->invalid_instruction;
-
- if (instr_field_count != 1) {
- ir_add_error(ira, instruction,
- buf_sprintf("union initialization expects exactly one field"));
- return ira->codegen->invalid_instruction;
- }
-
- IrInstructionContainerInitFieldsField *field = &fields[0];
- IrInstruction *field_value = field->value->child;
- if (type_is_invalid(field_value->value.type))
- return ira->codegen->invalid_instruction;
-
- TypeUnionField *type_field = find_union_type_field(container_type, field->name);
- if (!type_field) {
- ir_add_error_node(ira, field->source_node,
- buf_sprintf("no member named '%s' in union '%s'",
- buf_ptr(field->name), buf_ptr(&container_type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- if (type_is_invalid(type_field->type_entry))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry);
- if (casted_field_value == ira->codegen->invalid_instruction)
- return ira->codegen->invalid_instruction;
-
- if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown)))
- return ira->codegen->invalid_instruction;
-
- bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
- if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime ||
- !type_has_bits(casted_field_value->value.type))
- {
- ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
- if (!field_val)
- return ira->codegen->invalid_instruction;
-
- IrInstruction *result = ir_const(ira, instruction, container_type);
- ConstExprValue *out_val = &result->value;
- out_val->data.x_union.payload = field_val;
- out_val->data.x_union.tag = type_field->enum_field->value;
-
- ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
- if (parent != nullptr) {
- parent->id = ConstParentIdUnion;
- parent->data.p_union.union_val = out_val;
- }
-
- return result;
- }
-
- IrInstruction *new_instruction = ir_build_union_init(&ira->new_irb,
- instruction->scope, instruction->source_node,
- container_type, type_field, casted_field_value);
- new_instruction->value.type = container_type;
- return new_instruction;
+ zig_panic("TODO");
+ //Error err;
+ //assert(container_type->id == ZigTypeIdUnion);
+
+ //if ((err = ensure_complete_type(ira->codegen, container_type)))
+ // return ira->codegen->invalid_instruction;
+
+ //if (instr_field_count != 1) {
+ // ir_add_error(ira, instruction,
+ // buf_sprintf("union initialization expects exactly one field"));
+ // return ira->codegen->invalid_instruction;
+ //}
+
+ //IrInstructionContainerInitFieldsField *field = &fields[0];
+ //IrInstruction *field_value = field->value->child;
+ //if (type_is_invalid(field_value->value.type))
+ // return ira->codegen->invalid_instruction;
+
+ //TypeUnionField *type_field = find_union_type_field(container_type, field->name);
+ //if (!type_field) {
+ // ir_add_error_node(ira, field->source_node,
+ // buf_sprintf("no member named '%s' in union '%s'",
+ // buf_ptr(field->name), buf_ptr(&container_type->name)));
+ // return ira->codegen->invalid_instruction;
+ //}
+
+ //if (type_is_invalid(type_field->type_entry))
+ // return ira->codegen->invalid_instruction;
+
+ //IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry);
+ //if (casted_field_value == ira->codegen->invalid_instruction)
+ // return ira->codegen->invalid_instruction;
+
+ //if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown)))
+ // return ira->codegen->invalid_instruction;
+
+ //bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
+ //if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime ||
+ // !type_has_bits(casted_field_value->value.type))
+ //{
+ // ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
+ // if (!field_val)
+ // return ira->codegen->invalid_instruction;
+
+ // IrInstruction *result = ir_const(ira, instruction, container_type);
+ // ConstExprValue *out_val = &result->value;
+ // out_val->data.x_union.payload = field_val;
+ // out_val->data.x_union.tag = type_field->enum_field->value;
+
+ // ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
+ // if (parent != nullptr) {
+ // parent->id = ConstParentIdUnion;
+ // parent->data.p_union.union_val = out_val;
+ // }
+
+ // return result;
+ //}
+
+ //IrInstruction *new_instruction = ir_build_union_init(&ira->new_irb,
+ // instruction->scope, instruction->source_node,
+ // container_type, type_field, casted_field_value);
+ //new_instruction->value.type = container_type;
+ //return new_instruction;
}
static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction,
- ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)
+ ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields,
+ IrInstruction *result_loc)
{
- Error err;
if (container_type->id == ZigTypeIdUnion) {
return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields);
}
@@ -16614,28 +16682,26 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
return ira->codegen->invalid_instruction;
}
- if ((err = ensure_complete_type(ira->codegen, container_type)))
- return ira->codegen->invalid_instruction;
-
size_t actual_field_count = container_type->data.structure.src_field_count;
-
- IrInstruction *first_non_const_instruction = nullptr;
-
AstNode **field_assign_nodes = allocate(actual_field_count);
+ ZigList const_ptrs = {};
+
+ // Here we iterate over the fields that have been initialized, and emit
+ // compile errors for missing fields and duplicate fields.
+ // It is only now that we find out whether the struct initialization can be a comptime
+ // value, but we have already emitted runtime instructions for the fields that
+ // were initialized with runtime values, and have omitted instructions that would have
+ // initialized fields with comptime values.
+ // So now we must clean up this situation. If it turns out the struct initialization can
+ // be a comptime value, overwrite ConstPtrMutInfer with ConstPtrMutComptimeConst.
+ // Otherwise, we must emit instructions to runtime-initialize the fields that have
+ // comptime-known values.
- IrInstructionStructInitField *new_fields = allocate(actual_field_count);
-
- bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
-
- ConstExprValue const_val = {};
- const_val.special = ConstValSpecialStatic;
- const_val.type = container_type;
- const_val.data.x_struct.fields = create_const_vals(actual_field_count);
for (size_t i = 0; i < instr_field_count; i += 1) {
IrInstructionContainerInitFieldsField *field = &fields[i];
- IrInstruction *field_value = field->value->child;
- if (type_is_invalid(field_value->value.type))
+ IrInstruction *field_result_loc = field->result_loc->child;
+ if (type_is_invalid(field_result_loc->value.type))
return ira->codegen->invalid_instruction;
TypeStructField *type_field = find_struct_type_field(container_type, field->name);
@@ -16649,10 +16715,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
if (type_is_invalid(type_field->type_entry))
return ira->codegen->invalid_instruction;
- IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry);
- if (casted_field_value == ira->codegen->invalid_instruction)
- return ira->codegen->invalid_instruction;
-
size_t field_index = type_field->src_index;
AstNode *existing_assign_node = field_assign_nodes[field_index];
if (existing_assign_node) {
@@ -16662,19 +16724,10 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
}
field_assign_nodes[field_index] = field->source_node;
- new_fields[field_index].value = casted_field_value;
- new_fields[field_index].type_struct_field = type_field;
-
- if (const_val.special == ConstValSpecialStatic) {
- if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) {
- ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
- if (!field_val)
- return ira->codegen->invalid_instruction;
-
- copy_const_val(&const_val.data.x_struct.fields[field_index], field_val, true);
- } else {
- first_non_const_instruction = casted_field_value;
- const_val.special = ConstValSpecialRuntime;
+ if (instr_is_comptime(field_result_loc)) {
+ ConstExprValue *field_value = field_result_loc->value.data.x_ptr.data.ref.pointee;
+ if (field_value->special != ConstValSpecialRuntime) {
+ const_ptrs.append(field_result_loc);
}
}
}
@@ -16690,37 +16743,21 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
if (any_missing)
return ira->codegen->invalid_instruction;
- if (const_val.special == ConstValSpecialStatic) {
- IrInstruction *result = ir_const(ira, instruction, nullptr);
- ConstExprValue *out_val = &result->value;
- // TODO copy_const_val?
- *out_val = const_val;
- result->value.type = container_type;
-
- for (size_t i = 0; i < instr_field_count; i += 1) {
- ConstExprValue *field_val = &out_val->data.x_struct.fields[i];
- ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
- if (parent != nullptr) {
- parent->id = ConstParentIdStruct;
- parent->data.p_struct.field_index = i;
- parent->data.p_struct.struct_val = out_val;
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (const_ptrs.length == actual_field_count) {
+ result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ result_loc->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
+ for (size_t i = 0; i < const_ptrs.length; i += 1) {
+ IrInstruction *field_result_loc = const_ptrs.at(i);
+ IrInstruction *deref = ir_get_deref(ira, field_result_loc, field_result_loc);
+ field_result_loc->value.special = ConstValSpecialRuntime;
+ ir_analyze_store_ptr(ira, field_result_loc, field_result_loc, deref);
}
}
-
- return result;
- }
-
- if (is_comptime) {
- ir_add_error_node(ira, first_non_const_instruction->source_node,
- buf_sprintf("unable to evaluate constant expression"));
- return ira->codegen->invalid_instruction;
}
- IrInstruction *new_instruction = ir_build_struct_init(&ira->new_irb,
- instruction->scope, instruction->source_node,
- container_type, actual_field_count, new_fields);
- new_instruction->value.type = container_type;
- return new_instruction;
+ return ir_const_void(ira, instruction);
}
static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
@@ -16738,7 +16775,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) {
return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
- 0, nullptr);
+ 0, nullptr, nullptr);
} else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) {
// array is same as slice init but we make a compile error if the length is wrong
ZigType *child_type;
@@ -16845,14 +16882,20 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
}
}
-static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) {
+static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira,
+ IrInstructionContainerInitFields *instruction)
+{
IrInstruction *container_type_value = instruction->container_type->child;
ZigType *container_type = ir_resolve_type(ira, container_type_value);
if (type_is_invalid(container_type))
return ira->codegen->invalid_instruction;
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
- instruction->field_count, instruction->fields);
+ instruction->field_count, instruction->fields, result_loc);
}
static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira,
@@ -19556,7 +19599,8 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
return ira->codegen->invalid_instruction;
if (err_union_val->special != ConstValSpecialRuntime) {
- return ir_const_bool(ira, &instruction->base, (err_union_val->data.x_err_union.err != nullptr));
+ ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
+ return ir_const_bool(ira, &instruction->base, (err != nullptr));
}
}
@@ -19639,7 +19683,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
if (err_union_val == nullptr)
return ira->codegen->invalid_instruction;
if (err_union_val->special != ConstValSpecialRuntime) {
- ErrorTableEntry *err = err_union_val->data.x_err_union.err;
+ ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
assert(err);
IrInstruction *result = ir_const(ira, &instruction->base,
@@ -19691,7 +19735,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
if (err_union_val == nullptr)
return ira->codegen->invalid_instruction;
if (err_union_val->special != ConstValSpecialRuntime) {
- ErrorTableEntry *err = err_union_val->data.x_err_union.err;
+ ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
if (err != nullptr) {
ir_add_error(ira, &instruction->base,
buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
@@ -21324,13 +21368,21 @@ static IrInstruction *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructio
}
}
+ ConstExprValue *pointee = create_const_vals(1);
+ pointee->special = ConstValSpecialUndef;
+
IrInstructionAllocaGen *result = ir_create_alloca_gen(&ira->new_irb, instruction->base.scope,
instruction->base.source_node, align, instruction->name_hint);
+ result->base.value.special = ConstValSpecialStatic;
+ result->base.value.data.x_ptr.special = ConstPtrSpecialRef;
+ result->base.value.data.x_ptr.mut = ConstPtrMutInfer;
+ result->base.value.data.x_ptr.data.ref.pointee = pointee;
if (instruction->child_type == nullptr) {
// We use a pointer to a special opaque type to signal that we want type inference.
result->base.value.type = get_pointer_to_type_extra(ira->codegen,
ira->codegen->builtin_types.entry_infer, false, false, PtrLenSingle, align, 0, 0);
+ result->base.value.data.x_ptr.data.ref.pointee->type = ira->codegen->builtin_types.entry_infer;
} else {
ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child);
if (type_is_invalid(child_type))
@@ -21818,6 +21870,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdLoadResult:
case IrInstructionIdStoreResult:
case IrInstructionIdAssertNonError:
+ case IrInstructionIdContainerInitFields:
+ case IrInstructionIdContainerInitList:
return true;
case IrInstructionIdPhi:
@@ -21825,8 +21879,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdBinOp:
case IrInstructionIdConst:
case IrInstructionIdCast:
- case IrInstructionIdContainerInitList:
- case IrInstructionIdContainerInitFields:
case IrInstructionIdStructInit:
case IrInstructionIdUnionInit:
case IrInstructionIdFieldPtr:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index f999b98b8d32..360af612c374 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -288,9 +288,10 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI
IrInstructionContainerInitFieldsField *field = &instruction->fields[i];
const char *comma = (i == 0) ? "" : ", ";
fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field->name));
- ir_print_other_instruction(irp, field->value);
+ ir_print_other_instruction(irp, field->result_loc);
}
- fprintf(irp->f, "} // container init");
+ fprintf(irp->f, "} // result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
}
static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruction) {
From e36d7372294f93540f3a000de8475779a8c6904d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Nov 2018 21:01:01 -0400
Subject: [PATCH 029/190] copy elision: fix var decls and return result
instructions
---
src/all_types.hpp | 2 -
src/ir.cpp | 106 +++++++++++++++++++++++++++++++++++++++-------
2 files changed, 90 insertions(+), 18 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 310a3292f581..420c5d5fba64 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -68,8 +68,6 @@ struct IrExecutable {
Scope *begin_scope;
ZigList tld_list;
- IrInstruction *return_result_loc;
-
IrInstruction *coro_handle;
IrInstruction *atomic_state_field_ptr; // this one is shared and in the promise
IrInstruction *coro_result_ptr_field_ptr;
diff --git a/src/ir.cpp b/src/ir.cpp
index 9d3e7d0b4158..95eecf02d728 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -157,6 +157,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
ConstExprValue *out_val, ConstExprValue *ptr_val);
static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr,
ZigType *dest_type, IrInstruction *dest_type_src);
+static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *uncasted_ptr, IrInstruction *uncasted_value);
static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
assert(get_src_ptr_type(const_val->type) != nullptr);
@@ -3232,10 +3234,14 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
{
IrInstruction *return_value;
if (expr_node) {
+ IrInstruction *return_result_loc = nullptr;
+ if (handle_is_ptr(fn_entry->type_entry->data.fn.fn_type_id.return_type)) {
+ return_result_loc = ir_build_result_return(irb, scope, node);
+ }
// Temporarily set this so that if we return a type it gets the name of the function
ZigFn *prev_name_fn = irb->exec->name_fn;
irb->exec->name_fn = exec_fn_entry(irb->exec);
- return_value = ir_gen_node(irb, expr_node, scope, LValNone, irb->exec->return_result_loc);
+ return_value = ir_gen_node(irb, expr_node, scope, LValNone, return_result_loc);
irb->exec->name_fn = prev_name_fn;
if (return_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -7386,10 +7392,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ZigFn *fn_entry = exec_fn_entry(irb->exec);
- if (fn_entry != nullptr && handle_is_ptr(fn_entry->type_entry->data.fn.fn_type_id.return_type)) {
- irb->exec->return_result_loc = ir_build_result_return(irb, scope, node);
- }
-
bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
IrInstruction *coro_id;
IrInstruction *u8_ptr_type;
@@ -12817,6 +12819,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
}
assert(var_ptr->value.type->id == ZigTypeIdPointer);
+
ZigType *result_type = var_ptr->value.type->data.pointer.child_type;
if (type_is_invalid(result_type)) {
result_type = ira->codegen->builtin_types.entry_invalid;
@@ -12826,7 +12829,21 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
}
}
+ ConstExprValue *init_val = nullptr;
+ if (instr_is_comptime(var_ptr) && var_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) {
+ init_val = const_ptr_pointee(ira->codegen, &var_ptr->value);
+ }
+
if (!type_is_invalid(result_type)) {
+ // Resolve ConstPtrMutInfer
+ if (instr_is_comptime(var_ptr)) {
+ if (var_ptr->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (!is_comptime_var && !var->gen_is_const) {
+ var_ptr->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
+ }
+ }
+ }
+
if (result_type->id == ZigTypeIdUnreachable ||
result_type->id == ZigTypeIdOpaque)
{
@@ -12841,6 +12858,20 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
buf_ptr(&result_type->name)));
result_type = ira->codegen->builtin_types.entry_invalid;
}
+ } else if (init_val != nullptr) {
+ if (init_val->special == ConstValSpecialStatic &&
+ init_val->type->id == ZigTypeIdFn &&
+ init_val->data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
+ {
+ var_class_requires_const = true;
+ if (!var->src_is_const && !is_comptime_var) {
+ ErrorMsg *msg = ir_add_error_node(ira, source_node,
+ buf_sprintf("functions marked inline must be stored in const or comptime var"));
+ AstNode *proto_node = init_val->data.x_ptr.data.fn.fn_entry->proto_node;
+ add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
+ result_type = ira->codegen->builtin_types.entry_invalid;
+ }
+ }
}
}
@@ -12885,9 +12916,14 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
}
}
- if (var->mem_slot_index != SIZE_MAX) {
- if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
- return ir_const_void(ira, &decl_var_instruction->base);
+ if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) {
+ if (var->mem_slot_index != SIZE_MAX) {
+ assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length);
+ ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index);
+ copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const);
+ if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
+ return ir_const_void(ira, &decl_var_instruction->base);
+ }
}
} else if (is_comptime_var) {
ir_add_error(ira, &decl_var_instruction->base,
@@ -12896,6 +12932,21 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
return ira->codegen->invalid_instruction;
}
+ if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) {
+ if (var->gen_is_const) {
+ var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else if (is_comptime_var) {
+ var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeVar;
+ } else {
+ // we need a runtime ptr but we have a comptime val.
+ // since it's a comptime val there are no instructions for it.
+ // we memcpy the init value here
+ IrInstruction *deref = ir_get_deref(ira, var_ptr, var_ptr);
+ var_ptr->value.special = ConstValSpecialRuntime;
+ ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref);
+ }
+ }
+
ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
if (fn_entry)
fn_entry->variable_list.append(var);
@@ -14900,7 +14951,15 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
is_const, is_volatile, PtrLenSingle, align_bytes,
(uint32_t)(ptr_bit_offset + field->bit_offset_in_host),
(uint32_t)host_int_bytes_for_result_type);
- IrInstruction *result = ir_const(ira, source_instr, ptr_type);
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_struct_field_ptr(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, container_ptr, field);
+ result->value.type = ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, source_instr, ptr_type);
+ }
ConstExprValue *const_val = &result->value;
const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
@@ -16724,11 +16783,10 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
}
field_assign_nodes[field_index] = field->source_node;
- if (instr_is_comptime(field_result_loc)) {
- ConstExprValue *field_value = field_result_loc->value.data.x_ptr.data.ref.pointee;
- if (field_value->special != ConstValSpecialRuntime) {
- const_ptrs.append(field_result_loc);
- }
+ if (instr_is_comptime(field_result_loc) &&
+ field_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ const_ptrs.append(field_result_loc);
}
}
@@ -16748,6 +16806,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
} else {
result_loc->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
+ result_loc->value.special = ConstValSpecialRuntime;
for (size_t i = 0; i < const_ptrs.length; i += 1) {
IrInstruction *field_result_loc = const_ptrs.at(i);
IrInstruction *deref = ir_get_deref(ira, field_result_loc, field_result_loc);
@@ -21344,9 +21403,24 @@ static IrInstruction *ir_analyze_instruction_result_return(IrAnalyze *ira, IrIns
ir_add_error(ira, &instruction->base, buf_sprintf("return outside function"));
return ira->codegen->invalid_instruction;
}
- ZigType *result_type = get_pointer_to_type(ira->codegen, fn->type_entry->data.fn.fn_type_id.return_type, false);
- IrInstruction *result = ir_build_result_return(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
+
+ // Here we create a pass2 instruction for getting the return value pointer.
+ // However we create a const value for it and mark it with ConstPtrMutInfer
+ // so that if the return expression is comptime-known, we can emit a memcpy
+ // rather than runtime instructions instructions.
+
+ ConstExprValue *pointee = create_const_vals(1);
+ pointee->special = ConstValSpecialUndef;
+ pointee->type = fn->type_entry->data.fn.fn_type_id.return_type;
+
+ ZigType *result_type = get_pointer_to_type(ira->codegen, pointee->type, false);
+ IrInstruction *result = ir_build_result_return(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node);
result->value.type = result_type;
+ result->value.special = ConstValSpecialStatic;
+ result->value.data.x_ptr.special = ConstPtrSpecialRef;
+ result->value.data.x_ptr.data.ref.pointee = pointee;
+ result->value.data.x_ptr.mut = ConstPtrMutInfer;
return result;
}
From 7d4d8b1f8b848870c71c17d133e9c12fdd072707 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 5 Nov 2018 10:50:34 -0500
Subject: [PATCH 030/190] copy elision: implicit cast error set to error union
---
src/all_types.hpp | 10 ++++
src/analyze.cpp | 14 ++++++
src/codegen.cpp | 34 ++++++++++++++
src/ir.cpp | 117 ++++++++++++++++++++++++++++++++++++++--------
4 files changed, 156 insertions(+), 19 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 420c5d5fba64..35deaf694203 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -90,6 +90,7 @@ enum OutType {
enum ConstParentId {
ConstParentIdNone,
ConstParentIdStruct,
+ ConstParentIdErrUnionCode,
ConstParentIdArray,
ConstParentIdUnion,
ConstParentIdScalar,
@@ -107,6 +108,9 @@ struct ConstParent {
ConstExprValue *struct_val;
size_t field_index;
} p_struct;
+ struct {
+ ConstExprValue *err_union_val;
+ } p_err_union_code;
struct {
ConstExprValue *union_val;
} p_union;
@@ -153,6 +157,8 @@ enum ConstPtrSpecial {
ConstPtrSpecialBaseArray,
// The pointer points to a field in an underlying struct.
ConstPtrSpecialBaseStruct,
+ // The pointer points to the error set field of an error union
+ ConstPtrSpecialBaseErrorUnionCode,
// This means that we did a compile-time pointer reinterpret and we cannot
// understand the value of pointee at compile time. However, we will still
// emit a binary with a compile time known address.
@@ -202,6 +208,9 @@ struct ConstPtrValue {
ConstExprValue *struct_val;
size_t field_index;
} base_struct;
+ struct {
+ ConstExprValue *err_union_val;
+ } base_err_union_code;
struct {
uint64_t addr;
} hard_coded_addr;
@@ -214,6 +223,7 @@ struct ConstPtrValue {
struct ConstErrValue {
ConstExprValue *error_set;
ConstExprValue *payload;
+ ConstParent parent;
};
struct ConstBoundFnValue {
diff --git a/src/analyze.cpp b/src/analyze.cpp
index b4a8e10f7809..aad631f6f2c4 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -4760,6 +4760,10 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index);
return hash_val;
+ case ConstPtrSpecialBaseErrorUnionCode:
+ hash_val += (uint32_t)2994743799;
+ hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_code.err_union_val);
+ return hash_val;
case ConstPtrSpecialHardCodedAddr:
hash_val += (uint32_t)4048518294;
hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr);
@@ -5570,6 +5574,15 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
return false;
return true;
+ case ConstPtrSpecialBaseErrorUnionCode:
+ if (a->data.x_ptr.data.base_err_union_code.err_union_val !=
+ b->data.x_ptr.data.base_err_union_code.err_union_val &&
+ a->data.x_ptr.data.base_err_union_code.err_union_val->global_refs !=
+ b->data.x_ptr.data.base_err_union_code.err_union_val->global_refs)
+ {
+ return false;
+ }
+ return true;
case ConstPtrSpecialHardCodedAddr:
if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
return false;
@@ -5752,6 +5765,7 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy
zig_unreachable();
case ConstPtrSpecialRef:
case ConstPtrSpecialBaseStruct:
+ case ConstPtrSpecialBaseErrorUnionCode:
buf_appendf(buf, "*");
render_const_value(g, buf, const_ptr_pointee(g, const_val));
return;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index f27a46922f9b..eb28e92b6bb5 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5455,6 +5455,7 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val);
+static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val);
static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
switch (parent->id) {
@@ -5465,6 +5466,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
case ConstParentIdStruct:
return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val,
parent->data.p_struct.field_index);
+ case ConstParentIdErrUnionCode:
+ return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val);
case ConstParentIdArray:
return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val,
parent->data.p_array.elem_index);
@@ -5516,6 +5519,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s
return LLVMConstInBoundsGEP(base_ptr, indices, 2);
}
+static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val) {
+ ConstParent *parent = &err_union_const_val->data.x_err_union.parent;
+ LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent);
+
+ ZigType *u32 = g->builtin_types.entry_u32;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(u32->type_ref),
+ LLVMConstInt(u32->type_ref, err_union_err_index, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) {
ConstParent *parent = &union_const_val->data.x_union.parent;
LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent);
@@ -5687,6 +5702,25 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
render_const_val_global(g, const_val, "");
return ptr_val;
}
+ case ConstPtrSpecialBaseErrorUnionCode:
+ {
+ render_const_val_global(g, const_val, name);
+ ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_code.err_union_val;
+ assert(err_union_const_val->type->id == ZigTypeIdErrorUnion);
+ if (err_union_const_val->type->zero_bits) {
+ // make this a null pointer
+ ZigType *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val);
+ LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+ const_val->global_refs->llvm_value = ptr_val;
+ render_const_val_global(g, const_val, "");
+ return ptr_val;
+ }
case ConstPtrSpecialHardCodedAddr:
{
render_const_val_global(g, const_val, name);
diff --git a/src/ir.cpp b/src/ir.cpp
index 95eecf02d728..1e3f121a8418 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -179,6 +179,9 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[
const_val->data.x_ptr.data.base_struct.field_index];
break;
+ case ConstPtrSpecialBaseErrorUnionCode:
+ result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set;
+ break;
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialDiscard:
@@ -14763,6 +14766,8 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO elem ptr on a const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO elem ptr on a const inner error union");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
@@ -14816,6 +14821,8 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO elem ptr on a slice backed by const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO elem ptr on a slice backed by const inner error union");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
@@ -18868,6 +18875,8 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memset on const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO memset on const inner error union");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
@@ -18983,6 +18992,8 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memcpy on const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO memcpy on const inner error union");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
@@ -19019,6 +19030,8 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memcpy on const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO memcpy on const inner error union");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
@@ -19186,6 +19199,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialBaseStruct:
zig_panic("TODO slice const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO slice const inner error union");
case ConstPtrSpecialHardCodedAddr:
array_val = nullptr;
abs_offset = 0;
@@ -19223,6 +19238,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialBaseStruct:
zig_panic("TODO slice const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO slice const inner error union");
case ConstPtrSpecialHardCodedAddr:
array_val = nullptr;
abs_offset = 0;
@@ -19295,6 +19312,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
zig_unreachable();
case ConstPtrSpecialBaseStruct:
zig_panic("TODO");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO");
case ConstPtrSpecialHardCodedAddr:
init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
parent_ptr->type->data.pointer.child_type,
@@ -19710,7 +19729,44 @@ static IrInstruction *ir_analyze_instruction_error_union_field_error_set(IrAnaly
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
if (instr_is_comptime(ptr)) {
- zig_panic("TODO need to change ConstExprValue x_err_union to have a ConstExprValue for error set value");
+ ConstExprValue *ptr_val = ir_resolve_const(ira, ptr, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
+ ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val);
+ if (err_union_val->data.x_ptr.mut == ConstPtrMutInfer &&
+ err_union_val->special == ConstValSpecialUndef)
+ {
+ ConstExprValue *vals = create_const_vals(2);
+ ConstExprValue *err_set_val = &vals[0];
+ ConstExprValue *payload_val = &vals[1];
+
+ err_set_val->special = ConstValSpecialUndef;
+ err_set_val->type = opt_err_set;
+
+ payload_val->special = ConstValSpecialUndef;
+ payload_val->type = type_entry->data.error_union.payload_type;
+
+ err_union_val->special = ConstValSpecialStatic;
+ err_union_val->data.x_err_union.error_set = err_set_val;
+ err_union_val->data.x_err_union.payload = payload_val;
+ }
+
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_error_union_field_error_set(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, ptr);
+ result->value.type = result_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, &instruction->base, result_type);
+ }
+ ConstExprValue *const_val = &result->value;
+ const_val->data.x_ptr.special = ConstPtrSpecialBaseErrorUnionCode;
+ const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ const_val->data.x_ptr.data.base_err_union_code.err_union_val = err_union_val;
+ return result;
+ }
}
IrInstruction *result = ir_build_error_union_field_error_set(&ira->new_irb,
@@ -19790,21 +19846,42 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
if (!ptr_val)
return ira->codegen->invalid_instruction;
- ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node);
- if (err_union_val == nullptr)
- return ira->codegen->invalid_instruction;
- if (err_union_val->special != ConstValSpecialRuntime) {
- ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
- if (err != nullptr) {
- ir_add_error(ira, &instruction->base,
- buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
+ ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node);
+ if (err_union_val == nullptr)
return ira->codegen->invalid_instruction;
+ if (err_union_val->data.x_ptr.mut == ConstPtrMutInfer &&
+ err_union_val->special == ConstValSpecialUndef)
+ {
+ ConstExprValue *vals = create_const_vals(2);
+ ConstExprValue *err_set_val = &vals[0];
+ ConstExprValue *payload_val = &vals[1];
+
+ ZigType *opt_err_set = get_optional_type(ira->codegen, type_entry->data.error_union.err_set_type);
+ err_set_val->special = ConstValSpecialStatic;
+ err_set_val->type = opt_err_set;
+ err_set_val->data.x_err_set = nullptr;
+
+ payload_val->special = ConstValSpecialUndef;
+ payload_val->type = payload_type;
+
+ err_union_val->special = ConstValSpecialStatic;
+ err_union_val->data.x_err_union.error_set = err_set_val;
+ err_union_val->data.x_err_union.payload = payload_val;
}
+ if (err_union_val->special != ConstValSpecialRuntime) {
+ ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
+ if (err != nullptr) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
+ return ira->codegen->invalid_instruction;
+ }
- IrInstruction *result = ir_const(ira, &instruction->base, result_type);
- result->value.data.x_ptr.special = ConstPtrSpecialRef;
- result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload;
- return result;
+ IrInstruction *result = ir_const(ira, &instruction->base, result_type);
+ result->value.data.x_ptr.special = ConstPtrSpecialRef;
+ result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload;
+ return result;
+ }
}
}
@@ -19831,14 +19908,16 @@ static IrInstruction *ir_analyze_instruction_assert_non_error(IrAnalyze *ira,
assert(err_code->value.type->data.maybe.child_type->id == ZigTypeIdErrorSet);
if (instr_is_comptime(err_code)) {
- ConstExprValue *opt_val = ir_resolve_const(ira, err_code, UndefBad);
- if (opt_val == nullptr)
- return ira->codegen->invalid_instruction;
- ConstExprValue *err_val = opt_val->data.x_optional;
+ ConstExprValue *err_val = ir_resolve_const(ira, err_code, UndefBad);
if (err_val == nullptr)
- return ir_const_void(ira, &instruction->base);
+ return ira->codegen->invalid_instruction;
+ // just like optional pointers are represented with the same comptime
+ // value representation as normal pointers,
+ // optional error sets are represented with the same comptime value
+ // representation as normal error sets.
ErrorTableEntry *err = err_val->data.x_err_set;
- assert(err != nullptr);
+ if (err == nullptr)
+ return ir_const_void(ira, &instruction->base);
ir_add_error(ira, &instruction->base,
buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
return ira->codegen->invalid_instruction;
From 9e9ec3b416d87fdf16c1e319626279e11480f6a1 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 5 Nov 2018 17:14:32 -0500
Subject: [PATCH 031/190] copy elision: implicit optional wrap
```zig
export fn entry() void {
var a: ?Bar = Bar.{.x = 1, .y = 2};
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%a = alloca { %Bar, i1 }, align 4
%0 = bitcast { %Bar, i1 }* %a to i8*, !dbg !57
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast ({ %Bar, i1 }* @0 to i8*), i64 12, i1 false), !dbg !57
call void @llvm.dbg.declare(metadata { %Bar, i1 }* %a, metadata !45, metadata !DIExpression()), !dbg !57
ret void, !dbg !58
}
```
---
src/all_types.hpp | 8 +++++
src/codegen.cpp | 1 +
src/ir.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++---
src/ir_print.cpp | 11 +++++++
4 files changed, 93 insertions(+), 5 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 35deaf694203..64887eed0a12 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2192,6 +2192,7 @@ enum IrInstructionId {
IrInstructionIdResultSliceToBytes,
IrInstructionIdResultParam,
IrInstructionIdResultPtrCast,
+ IrInstructionIdResultCast,
IrInstructionIdLoadResult,
IrInstructionIdStoreResult,
IrInstructionIdAllocaSrc,
@@ -3362,6 +3363,13 @@ struct IrInstructionResultPtrCast {
IrInstruction *prev_result_loc;
};
+struct IrInstructionResultCast {
+ IrInstruction base;
+
+ IrInstruction *elem_type;
+ IrInstruction *prev_result_loc;
+};
+
struct IrInstructionAllocaSrc {
IrInstruction base;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index eb28e92b6bb5..904bc6bf5938 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5242,6 +5242,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdAllocaSrc:
case IrInstructionIdAllocaGen:
case IrInstructionIdFirstArgResultLoc:
+ case IrInstructionIdResultCast:
zig_unreachable();
case IrInstructionIdDeclVarGen:
diff --git a/src/ir.cpp b/src/ir.cpp
index 1e3f121a8418..d0699aeb95e8 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -896,6 +896,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtrCast *)
return IrInstructionIdResultPtrCast;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultCast *) {
+ return IrInstructionIdResultCast;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionResultSliceToBytes *) {
return IrInstructionIdResultSliceToBytes;
}
@@ -2886,6 +2890,19 @@ static IrInstruction *ir_build_result_ptr_cast(IrBuilder *irb, Scope *scope, Ast
return &instruction->base;
}
+static IrInstruction *ir_build_result_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *elem_type, IrInstruction *prev_result_loc)
+{
+ IrInstructionResultCast *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->elem_type = elem_type;
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(elem_type, irb->current_basic_block);
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_result_slice_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *elem_type, IrInstruction *prev_result_loc)
{
@@ -5240,6 +5257,8 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
return container_type;
if (kind == ContainerInitKindStruct) {
+ IrInstruction *new_result_loc = ir_build_result_cast(irb, scope, node, container_type, result_loc);
+
size_t field_count = container_init_expr->entries.length;
IrInstructionContainerInitFieldsField *fields = allocate(field_count);
for (size_t i = 0; i < field_count; i += 1) {
@@ -5247,7 +5266,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
assert(entry_node->type == NodeTypeStructValueField);
Buf *name = entry_node->data.struct_val_field.name;
- IrInstruction *field_result_loc = ir_build_field_ptr(irb, scope, entry_node, result_loc,
+ IrInstruction *field_result_loc = ir_build_field_ptr(irb, scope, entry_node, new_result_loc,
container_type, name);
AstNode *expr_node = entry_node->data.struct_val_field.expr;
@@ -5259,7 +5278,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
fields[i].result_loc = field_result_loc;
fields[i].source_node = entry_node;
}
- ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields, result_loc);
+ ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields, new_result_loc);
return ir_gen_result(irb, scope, node, lval, result_loc);
} else if (kind == ContainerInitKindArray) {
size_t item_count = container_init_expr->entries.length;
@@ -9909,14 +9928,44 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
static IrInstruction *ir_analyze_result_optional_payload(IrAnalyze *ira, IrInstruction *result_loc,
ZigType *needed_child_type)
{
- if (instr_is_comptime(result_loc)) {
- zig_panic("TODO comptime ir_analyze_result_optional_payload");
- }
ZigType *old_ptr_type = result_loc->value.type;
assert(old_ptr_type->id == ZigTypeIdPointer);
ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (ptr_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
+ ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *optional_val = const_ptr_pointee(ira->codegen, ptr_val);
+ assert(optional_val->type->id == ZigTypeIdOptional);
+ if (optional_val->special == ConstValSpecialUndef) {
+ ConstExprValue *payload_val = create_const_vals(1);
+ payload_val->type = needed_child_type;
+ payload_val->special = ConstValSpecialUndef;
+
+ optional_val->data.x_optional = payload_val;
+ optional_val->special = ConstValSpecialStatic;
+ }
+ assert(optional_val->data.x_optional != nullptr);
+
+ IrInstruction *result = ir_const(ira, result_loc, new_ptr_type);
+ ConstExprValue *result_val = &result->value;
+ result_val->data.x_ptr.special = ConstPtrSpecialRef;
+ result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ result_val->data.x_ptr.data.ref.pointee = optional_val->data.x_optional;
+
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
+ }
+
+ return result;
+ }
+ }
+
IrInstruction *result = ir_build_result_optional_payload(&ira->new_irb, result_loc->scope,
result_loc->source_node, result_loc);
result->value.type = new_ptr_type;
@@ -21511,6 +21560,22 @@ static IrInstruction *ir_analyze_instruction_result_ptr_cast(IrAnalyze *ira, IrI
zig_panic("TODO");
}
+static IrInstruction *ir_analyze_instruction_result_cast(IrAnalyze *ira, IrInstructionResultCast *instruction) {
+ ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child);
+ if (type_is_invalid(elem_type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = ir_implicit_cast_result(ira, prev_result_loc, elem_type, false);
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return new_result_loc;
+}
+
static IrInstruction *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAllocaSrc *instruction) {
Error err;
@@ -21882,6 +21947,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_result_param(ira, (IrInstructionResultParam *)instruction);
case IrInstructionIdResultPtrCast:
return ir_analyze_instruction_result_ptr_cast(ira, (IrInstructionResultPtrCast *)instruction);
+ case IrInstructionIdResultCast:
+ return ir_analyze_instruction_result_cast(ira, (IrInstructionResultCast *)instruction);
case IrInstructionIdAllocaSrc:
return ir_analyze_instruction_alloca(ira, (IrInstructionAllocaSrc *)instruction);
case IrInstructionIdErrorUnionFieldErrorSet:
@@ -22120,6 +22187,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdResultReturn:
case IrInstructionIdResultParam:
case IrInstructionIdResultPtrCast:
+ case IrInstructionIdResultCast:
case IrInstructionIdResultSliceToBytes:
case IrInstructionIdResultBytesToSlice:
case IrInstructionIdAllocaSrc:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 360af612c374..fd6c2d3c26bb 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1365,6 +1365,14 @@ static void ir_print_result_ptr_cast(IrPrint *irp, IrInstructionResultPtrCast *i
fprintf(irp->f, "ResultPtrCast");
}
+static void ir_print_result_cast(IrPrint *irp, IrInstructionResultCast *instruction) {
+ fprintf(irp->f, "ResultCast(child_ty=");
+ ir_print_other_instruction(irp, instruction->elem_type);
+ fprintf(irp->f, ",prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_load_result(IrPrint *irp, IrInstructionLoadResult *instruction) {
fprintf(irp->f, "LoadResult");
}
@@ -1855,6 +1863,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdResultPtrCast:
ir_print_result_ptr_cast(irp, (IrInstructionResultPtrCast *)instruction);
break;
+ case IrInstructionIdResultCast:
+ ir_print_result_cast(irp, (IrInstructionResultCast *)instruction);
+ break;
case IrInstructionIdLoadResult:
ir_print_load_result(irp, (IrInstructionLoadResult *)instruction);
break;
From 7b86ff5798947e0fe2f1f19cf5209886baa7bd94 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 5 Nov 2018 20:43:05 -0500
Subject: [PATCH 032/190] const expr supports parent pointers for error union
payloads
---
src/all_types.hpp | 9 +++++
src/analyze.cpp | 16 ++++++++
src/codegen.cpp | 34 +++++++++++++++++
src/ir.cpp | 93 +++++++++++++++++++++++++++++++++++++++++------
4 files changed, 141 insertions(+), 11 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 64887eed0a12..a958111ba3f4 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -91,6 +91,7 @@ enum ConstParentId {
ConstParentIdNone,
ConstParentIdStruct,
ConstParentIdErrUnionCode,
+ ConstParentIdErrUnionPayload,
ConstParentIdArray,
ConstParentIdUnion,
ConstParentIdScalar,
@@ -111,6 +112,9 @@ struct ConstParent {
struct {
ConstExprValue *err_union_val;
} p_err_union_code;
+ struct {
+ ConstExprValue *err_union_val;
+ } p_err_union_payload;
struct {
ConstExprValue *union_val;
} p_union;
@@ -159,6 +163,8 @@ enum ConstPtrSpecial {
ConstPtrSpecialBaseStruct,
// The pointer points to the error set field of an error union
ConstPtrSpecialBaseErrorUnionCode,
+ // The pointer points to the payload field of an error union
+ ConstPtrSpecialBaseErrorUnionPayload,
// This means that we did a compile-time pointer reinterpret and we cannot
// understand the value of pointee at compile time. However, we will still
// emit a binary with a compile time known address.
@@ -211,6 +217,9 @@ struct ConstPtrValue {
struct {
ConstExprValue *err_union_val;
} base_err_union_code;
+ struct {
+ ConstExprValue *err_union_val;
+ } base_err_union_payload;
struct {
uint64_t addr;
} hard_coded_addr;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index aad631f6f2c4..2ad058904d1c 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -4764,6 +4764,10 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
hash_val += (uint32_t)2994743799;
hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_code.err_union_val);
return hash_val;
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ hash_val += (uint32_t)3456080131;
+ hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_payload.err_union_val);
+ return hash_val;
case ConstPtrSpecialHardCodedAddr:
hash_val += (uint32_t)4048518294;
hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr);
@@ -5583,6 +5587,15 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
return false;
}
return true;
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ if (a->data.x_ptr.data.base_err_union_payload.err_union_val !=
+ b->data.x_ptr.data.base_err_union_payload.err_union_val &&
+ a->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs !=
+ b->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs)
+ {
+ return false;
+ }
+ return true;
case ConstPtrSpecialHardCodedAddr:
if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
return false;
@@ -5766,6 +5779,7 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy
case ConstPtrSpecialRef:
case ConstPtrSpecialBaseStruct:
case ConstPtrSpecialBaseErrorUnionCode:
+ case ConstPtrSpecialBaseErrorUnionPayload:
buf_appendf(buf, "*");
render_const_value(g, buf, const_ptr_pointee(g, const_val));
return;
@@ -6218,6 +6232,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) {
return &value->data.x_struct.parent;
} else if (type_entry->id == ZigTypeIdUnion) {
return &value->data.x_union.parent;
+ } else if (type_entry->id == ZigTypeIdErrorUnion) {
+ return &value->data.x_err_union.parent;
}
return nullptr;
}
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 904bc6bf5938..266b65890f89 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5457,6 +5457,7 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s
static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val);
static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val);
+static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val);
static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
switch (parent->id) {
@@ -5469,6 +5470,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
parent->data.p_struct.field_index);
case ConstParentIdErrUnionCode:
return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val);
+ case ConstParentIdErrUnionPayload:
+ return gen_const_ptr_err_union_payload_recursive(g, parent->data.p_err_union_payload.err_union_val);
case ConstParentIdArray:
return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val,
parent->data.p_array.elem_index);
@@ -5532,6 +5535,18 @@ static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExpr
return LLVMConstInBoundsGEP(base_ptr, indices, 2);
}
+static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val) {
+ ConstParent *parent = &err_union_const_val->data.x_err_union.parent;
+ LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent);
+
+ ZigType *u32 = g->builtin_types.entry_u32;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(u32->type_ref),
+ LLVMConstInt(u32->type_ref, err_union_payload_index, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) {
ConstParent *parent = &union_const_val->data.x_union.parent;
LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent);
@@ -5722,6 +5737,25 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
render_const_val_global(g, const_val, "");
return ptr_val;
}
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ {
+ render_const_val_global(g, const_val, name);
+ ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val;
+ assert(err_union_const_val->type->id == ZigTypeIdErrorUnion);
+ if (err_union_const_val->type->zero_bits) {
+ // make this a null pointer
+ ZigType *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val);
+ LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+ const_val->global_refs->llvm_value = ptr_val;
+ render_const_val_global(g, const_val, "");
+ return ptr_val;
+ }
case ConstPtrSpecialHardCodedAddr:
{
render_const_val_global(g, const_val, name);
diff --git a/src/ir.cpp b/src/ir.cpp
index d0699aeb95e8..2a94acd5d79f 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -182,6 +182,9 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
case ConstPtrSpecialBaseErrorUnionCode:
result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set;
break;
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ result = const_val->data.x_ptr.data.base_err_union_payload.err_union_val->data.x_err_union.payload;
+ break;
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialDiscard:
@@ -9975,14 +9978,65 @@ static IrInstruction *ir_analyze_result_optional_payload(IrAnalyze *ira, IrInstr
static IrInstruction *ir_analyze_result_error_union_payload(IrAnalyze *ira, IrInstruction *result_loc,
ZigType *needed_child_type)
{
- if (instr_is_comptime(result_loc)) {
- zig_panic("TODO comptime ir_analyze_result_error_union_payload");
- }
ZigType *old_ptr_type = result_loc->value.type;
assert(old_ptr_type->id == ZigTypeIdPointer);
ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (ptr_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
+ ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *error_union_val = const_ptr_pointee(ira->codegen, ptr_val);
+ assert(error_union_val->type->id == ZigTypeIdErrorUnion);
+
+ if (error_union_val->special == ConstValSpecialUndef) {
+ ConstExprValue *vals = create_const_vals(2);
+ ConstExprValue *err_set_val = &vals[0];
+ ConstExprValue *payload_val = &vals[1];
+
+ err_set_val->type = get_optional_type(ira->codegen,
+ error_union_val->type->data.error_union.err_set_type);
+ err_set_val->special = ConstValSpecialStatic;
+ err_set_val->data.x_err_set = nullptr;
+
+ payload_val->type = error_union_val->type->data.error_union.payload_type;
+ payload_val->special = ConstValSpecialUndef;
+ ConstParent *payload_parent = get_const_val_parent(ira->codegen, payload_val);
+ if (payload_parent != nullptr) {
+ payload_parent->id = ConstParentIdErrUnionPayload;
+ payload_parent->data.p_err_union_payload.err_union_val = error_union_val;
+ }
+
+ error_union_val->data.x_err_union.error_set = err_set_val;
+ error_union_val->data.x_err_union.payload = payload_val;
+ error_union_val->special = ConstValSpecialStatic;
+ ConstParent *err_set_parent = get_const_val_parent(ira->codegen, err_set_val);
+ if (err_set_parent != nullptr) {
+ err_set_parent->id = ConstParentIdErrUnionCode;
+ err_set_parent->data.p_err_union_code.err_union_val = error_union_val;
+ }
+ }
+
+ assert(error_union_val->data.x_err_union.payload != nullptr);
+
+ IrInstruction *result = ir_const(ira, result_loc, new_ptr_type);
+ ConstExprValue *result_val = &result->value;
+ result_val->data.x_ptr.special = ConstPtrSpecialRef;
+ result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ result_val->data.x_ptr.data.ref.pointee = error_union_val->data.x_err_union.payload;
+
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
+ }
+
+ return result;
+ }
+ }
+
IrInstruction *result = ir_build_result_error_union_payload(&ira->new_irb, result_loc->scope,
result_loc->source_node, result_loc);
result->value.type = new_ptr_type;
@@ -10006,7 +10060,8 @@ static IrInstruction *ir_analyze_result_error_union_code(IrAnalyze *ira, IrInstr
if (error_union_val->special == ConstValSpecialUndef) {
ConstExprValue *err_set_val = create_const_vals(1);
- err_set_val->type = error_union_val->type->data.error_union.err_set_type;
+ err_set_val->type = get_optional_type(ira->codegen,
+ error_union_val->type->data.error_union.err_set_type);
err_set_val->special = ConstValSpecialUndef;
error_union_val->data.x_err_union.error_set = err_set_val;
@@ -14816,7 +14871,9 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
case ConstPtrSpecialBaseStruct:
zig_panic("TODO elem ptr on a const inner struct");
case ConstPtrSpecialBaseErrorUnionCode:
- zig_panic("TODO elem ptr on a const inner error union");
+ zig_panic("TODO elem ptr on a const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO elem ptr on a const inner error union payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
@@ -14871,7 +14928,9 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
case ConstPtrSpecialBaseStruct:
zig_panic("TODO elem ptr on a slice backed by const inner struct");
case ConstPtrSpecialBaseErrorUnionCode:
- zig_panic("TODO elem ptr on a slice backed by const inner error union");
+ zig_panic("TODO elem ptr on a slice backed by const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO elem ptr on a slice backed by const inner error union payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
@@ -18925,7 +18984,9 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memset on const inner struct");
case ConstPtrSpecialBaseErrorUnionCode:
- zig_panic("TODO memset on const inner error union");
+ zig_panic("TODO memset on const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO memset on const inner error union payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
@@ -19042,7 +19103,9 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memcpy on const inner struct");
case ConstPtrSpecialBaseErrorUnionCode:
- zig_panic("TODO memcpy on const inner error union");
+ zig_panic("TODO memcpy on const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO memcpy on const inner error union payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
@@ -19080,7 +19143,9 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memcpy on const inner struct");
case ConstPtrSpecialBaseErrorUnionCode:
- zig_panic("TODO memcpy on const inner error union");
+ zig_panic("TODO memcpy on const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO memcpy on const inner error union payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
@@ -19249,7 +19314,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
case ConstPtrSpecialBaseStruct:
zig_panic("TODO slice const inner struct");
case ConstPtrSpecialBaseErrorUnionCode:
- zig_panic("TODO slice const inner error union");
+ zig_panic("TODO slice const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO slice const inner error union payload");
case ConstPtrSpecialHardCodedAddr:
array_val = nullptr;
abs_offset = 0;
@@ -19288,7 +19355,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
case ConstPtrSpecialBaseStruct:
zig_panic("TODO slice const inner struct");
case ConstPtrSpecialBaseErrorUnionCode:
- zig_panic("TODO slice const inner error union");
+ zig_panic("TODO slice const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO slice const inner error union payload");
case ConstPtrSpecialHardCodedAddr:
array_val = nullptr;
abs_offset = 0;
@@ -19363,6 +19432,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
zig_panic("TODO");
case ConstPtrSpecialBaseErrorUnionCode:
zig_panic("TODO");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO");
case ConstPtrSpecialHardCodedAddr:
init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
parent_ptr->type->data.pointer.child_type,
From c136bfff05d4582c8c3efdab9844ae096276aecd Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 5 Nov 2018 21:52:44 -0500
Subject: [PATCH 033/190] copy elision: handle store ptr with runtime value
better
```zig
export fn entry() void {
var a: error!Bar = Bar.{.x = 1, .y = 2};
var b = a catch unreachable;
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%a = alloca { i16, %Bar }, align 4
%b = alloca %Bar, align 4
%0 = bitcast { i16, %Bar }* %a to i8*, !dbg !58
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast ({ i16, %Bar }* @0 to i8*), i64 12, i1 false), !dbg !58
call void @llvm.dbg.declare(metadata { i16, %Bar }* %a, metadata !45, metadata !DIExpression()), !dbg !58
%1 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %a, i32 0, i32 1, !dbg !59
%2 = bitcast %Bar* %1 to i8*, !dbg !59
%3 = bitcast %Bar* %b to i8*, !dbg !59
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %3, i8* align 4 %2, i64 8, i1 false), !dbg !59
%4 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %a, i32 0, i32 0, !dbg !59
%5 = load i16, i16* %4, align 2, !dbg !60
call void @llvm.dbg.declare(metadata %Bar* %b, metadata !56, metadata !DIExpression()), !dbg !61
ret void, !dbg !62
}
```
---
src/ir.cpp | 44 +++++++++++++++++++++++++-------------------
src/ir_print.cpp | 4 ++--
2 files changed, 27 insertions(+), 21 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 2a94acd5d79f..53fe58ef0e25 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -13023,22 +13023,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
}
}
- if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) {
- if (var->mem_slot_index != SIZE_MAX) {
- assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length);
- ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index);
- copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const);
- if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
- return ir_const_void(ira, &decl_var_instruction->base);
- }
- }
- } else if (is_comptime_var) {
- ir_add_error(ira, &decl_var_instruction->base,
- buf_sprintf("cannot store runtime value in compile time variable"));
- var->value->type = ira->codegen->builtin_types.entry_invalid;
- return ira->codegen->invalid_instruction;
- }
-
if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) {
if (var->gen_is_const) {
var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
@@ -13052,6 +13036,19 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
var_ptr->value.special = ConstValSpecialRuntime;
ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref);
}
+ if (var_ptr->value.special == ConstValSpecialStatic && var->mem_slot_index != SIZE_MAX) {
+ assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length);
+ ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index);
+ copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const);
+ if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
+ return ir_const_void(ira, &decl_var_instruction->base);
+ }
+ }
+ } else if (is_comptime_var) {
+ ir_add_error(ira, &decl_var_instruction->base,
+ buf_sprintf("cannot store runtime value in compile time variable"));
+ var->value->type = ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
}
ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
@@ -13615,7 +13612,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
}
}
if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) {
- ptr->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
+ ptr->value.special = ConstValSpecialRuntime;
} else {
ir_add_error(ira, source_instr,
buf_sprintf("cannot store runtime value in compile time variable"));
@@ -19970,7 +19967,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node);
if (err_union_val == nullptr)
return ira->codegen->invalid_instruction;
- if (err_union_val->data.x_ptr.mut == ConstPtrMutInfer &&
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer &&
err_union_val->special == ConstValSpecialUndef)
{
ConstExprValue *vals = create_const_vals(2);
@@ -19997,9 +19994,18 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_const(ira, &instruction->base, result_type);
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_unwrap_err_payload(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, value, instruction->safety_check_on);
+ result->value.type = result_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, &instruction->base, result_type);
+ }
result->value.data.x_ptr.special = ConstPtrSpecialRef;
result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload;
+ result->value.data.x_ptr.mut = ptr_val->data.x_ptr.mut;
return result;
}
}
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index fd6c2d3c26bb..aeacce36301b 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -818,13 +818,13 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) {
}
static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) {
- fprintf(irp->f, "@unwrapErrorCode(");
+ fprintf(irp->f, "UnwrapErrorCode(");
ir_print_other_instruction(irp, instruction->value);
fprintf(irp->f, ")");
}
static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) {
- fprintf(irp->f, "@unwrapErrorPayload(");
+ fprintf(irp->f, "ErrorUnionFieldPayload(");
ir_print_other_instruction(irp, instruction->value);
fprintf(irp->f, ")");
if (!instruction->safety_check_on) {
From c17c46ca4373001469972fb6fa29403df64c79d9 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 6 Nov 2018 16:08:01 -0500
Subject: [PATCH 034/190] copy elision: implicit cast fn call to error union
```zig
export fn entry() void {
var x: error!i32 = fail();
}
```
```llvm
define void @entry() #2 !dbg !42 {
Entry:
%x = alloca { i16, i32 }, align 4
%0 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %x, i32 0, i32 0, !dbg !53
%1 = call fastcc i16 @fail(), !dbg !54
store i16 %1, i16* %0, align 2, !dbg !54
ret void, !dbg !55
}
```
---
src/codegen.cpp | 6 +-
src/ir.cpp | 142 +++++++++++++++++++++++++++++-------------------
2 files changed, 91 insertions(+), 57 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 266b65890f89..bc1375028364 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5445,8 +5445,10 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block);
for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) {
IrInstruction *instruction = current_block->instruction_list.at(instr_i);
- if (instruction->ref_count == 0 && !ir_has_side_effects(instruction))
- continue;
+ if (!ir_has_side_effects(instruction)) {
+ if (instruction->ref_count == 0 || instruction->value.special != ConstValSpecialRuntime)
+ continue;
+ }
instruction->llvm_value = ir_render_instruction(g, executable, instruction);
}
current_block->llvm_exit_block = LLVMGetInsertBlock(g->builder);
diff --git a/src/ir.cpp b/src/ir.cpp
index 53fe58ef0e25..c82059f97152 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -9975,6 +9975,36 @@ static IrInstruction *ir_analyze_result_optional_payload(IrAnalyze *ira, IrInstr
return result;
}
+static void init_if_undef_err_union(IrAnalyze *ira, ConstExprValue *error_union_val) {
+ if (error_union_val->special != ConstValSpecialUndef)
+ return;
+
+ ConstExprValue *vals = create_const_vals(2);
+ ConstExprValue *err_set_val = &vals[0];
+ ConstExprValue *payload_val = &vals[1];
+
+ err_set_val->type = get_optional_type(ira->codegen,
+ error_union_val->type->data.error_union.err_set_type);
+ err_set_val->special = ConstValSpecialUndef;
+ ConstParent *err_set_parent = get_const_val_parent(ira->codegen, err_set_val);
+ if (err_set_parent != nullptr) {
+ err_set_parent->id = ConstParentIdErrUnionCode;
+ err_set_parent->data.p_err_union_code.err_union_val = error_union_val;
+ }
+
+ payload_val->type = error_union_val->type->data.error_union.payload_type;
+ payload_val->special = ConstValSpecialUndef;
+ ConstParent *payload_parent = get_const_val_parent(ira->codegen, payload_val);
+ if (payload_parent != nullptr) {
+ payload_parent->id = ConstParentIdErrUnionPayload;
+ payload_parent->data.p_err_union_payload.err_union_val = error_union_val;
+ }
+
+ error_union_val->data.x_err_union.error_set = err_set_val;
+ error_union_val->data.x_err_union.payload = payload_val;
+ error_union_val->special = ConstValSpecialStatic;
+}
+
static IrInstruction *ir_analyze_result_error_union_payload(IrAnalyze *ira, IrInstruction *result_loc,
ZigType *needed_child_type)
{
@@ -9993,37 +10023,18 @@ static IrInstruction *ir_analyze_result_error_union_payload(IrAnalyze *ira, IrIn
ConstExprValue *error_union_val = const_ptr_pointee(ira->codegen, ptr_val);
assert(error_union_val->type->id == ZigTypeIdErrorUnion);
- if (error_union_val->special == ConstValSpecialUndef) {
- ConstExprValue *vals = create_const_vals(2);
- ConstExprValue *err_set_val = &vals[0];
- ConstExprValue *payload_val = &vals[1];
-
- err_set_val->type = get_optional_type(ira->codegen,
- error_union_val->type->data.error_union.err_set_type);
- err_set_val->special = ConstValSpecialStatic;
- err_set_val->data.x_err_set = nullptr;
-
- payload_val->type = error_union_val->type->data.error_union.payload_type;
- payload_val->special = ConstValSpecialUndef;
- ConstParent *payload_parent = get_const_val_parent(ira->codegen, payload_val);
- if (payload_parent != nullptr) {
- payload_parent->id = ConstParentIdErrUnionPayload;
- payload_parent->data.p_err_union_payload.err_union_val = error_union_val;
- }
-
- error_union_val->data.x_err_union.error_set = err_set_val;
- error_union_val->data.x_err_union.payload = payload_val;
- error_union_val->special = ConstValSpecialStatic;
- ConstParent *err_set_parent = get_const_val_parent(ira->codegen, err_set_val);
- if (err_set_parent != nullptr) {
- err_set_parent->id = ConstParentIdErrUnionCode;
- err_set_parent->data.p_err_union_code.err_union_val = error_union_val;
- }
- }
-
+ init_if_undef_err_union(ira, error_union_val);
assert(error_union_val->data.x_err_union.payload != nullptr);
- IrInstruction *result = ir_const(ira, result_loc, new_ptr_type);
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_result_error_union_payload(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc);
+ result->value.type = new_ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, result_loc, new_ptr_type);
+ }
ConstExprValue *result_val = &result->value;
result_val->data.x_ptr.special = ConstPtrSpecialRef;
result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
@@ -10051,30 +10062,39 @@ static IrInstruction *ir_analyze_result_error_union_code(IrAnalyze *ira, IrInstr
ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
- if (instr_is_comptime(result_loc) && result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) {
- ConstExprValue *const_val = ir_resolve_const(ira, result_loc, UndefBad);
- if (const_val == nullptr)
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (ptr_val == nullptr)
return ira->codegen->invalid_instruction;
- ConstExprValue *error_union_val = const_ptr_pointee(ira->codegen, const_val);
- assert(error_union_val->type->id == ZigTypeIdErrorUnion);
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
+ ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *error_union_val = const_ptr_pointee(ira->codegen, ptr_val);
+ assert(error_union_val->type->id == ZigTypeIdErrorUnion);
- if (error_union_val->special == ConstValSpecialUndef) {
- ConstExprValue *err_set_val = create_const_vals(1);
- err_set_val->type = get_optional_type(ira->codegen,
- error_union_val->type->data.error_union.err_set_type);
- err_set_val->special = ConstValSpecialUndef;
+ init_if_undef_err_union(ira, error_union_val);
+ assert(error_union_val->data.x_err_union.error_set != nullptr);
- error_union_val->data.x_err_union.error_set = err_set_val;
- error_union_val->special = ConstValSpecialStatic;
- }
- assert(error_union_val->data.x_err_union.error_set != nullptr);
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_result_error_union_code(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc);
+ result->value.type = new_ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, result_loc, new_ptr_type);
+ }
+ ConstExprValue *result_val = &result->value;
+ result_val->data.x_ptr.special = ConstPtrSpecialRef;
+ result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ result_val->data.x_ptr.data.ref.pointee = error_union_val->data.x_err_union.error_set;
- IrInstruction *result = ir_const(ira, result_loc, new_ptr_type);
- ConstExprValue *result_val = &result->value;
- result_val->data.x_ptr.special = ConstPtrSpecialRef;
- result_val->data.x_ptr.mut = result_loc->value.data.x_ptr.mut;
- result_val->data.x_ptr.data.ref.pointee = error_union_val->data.x_err_union.error_set;
- return result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
+ }
+
+ return result;
+ }
}
IrInstruction *result = ir_build_result_error_union_code(&ira->new_irb, result_loc->scope,
@@ -14174,22 +14194,34 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
return ira->codegen->invalid_instruction;
}
- IrInstruction *result_loc = nullptr;
+ IrInstruction *casted_result_loc = nullptr;
if (call_instruction->result_loc != nullptr) {
- result_loc = ir_implicit_cast_result(ira, call_instruction->result_loc->child, return_type, false);
- if (type_is_invalid(result_loc->value.type))
+ IrInstruction *prev_result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if (instr_is_comptime(prev_result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, prev_result_loc, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr_val->special = ConstValSpecialRuntime;
+ }
+ }
+
+ casted_result_loc = ir_implicit_cast_result(ira, prev_result_loc, return_type, false);
+ if (type_is_invalid(casted_result_loc->value.type))
return ira->codegen->invalid_instruction;
}
IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
call_instruction->base.scope, call_instruction->base.source_node,
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
- casted_new_stack, result_loc);
+ casted_new_stack, casted_result_loc);
new_call_instruction->value.type = return_type;
- if (!handle_is_ptr(return_type) && result_loc != nullptr) {
- ir_analyze_store_ptr(ira, &call_instruction->base, result_loc, new_call_instruction);
+ if (!handle_is_ptr(return_type) && casted_result_loc != nullptr) {
+ ir_analyze_store_ptr(ira, &call_instruction->base, casted_result_loc, new_call_instruction);
}
return ir_finish_anal(ira, new_call_instruction);
From b2222228541523c7d8e740d83070aa1c88c5c25c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 7 Nov 2018 10:39:13 -0500
Subject: [PATCH 035/190] copy elision: fix unwrap maybe and while
```zig
export fn entry() void {
const c = false;
const x: error!i32 = error.Failure;
var z = while (x) |a| {
if (c) break a;
} else |_| i32(3);
}
```
---
src/ir.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index c82059f97152..4cf799298ce5 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5464,7 +5464,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
// TODO make it an error to write to error variable
AstNode *err_symbol_node = else_node; // TODO make more accurate
ZigVar *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol,
- true, false, false, is_comptime);
+ true, true, false, is_comptime);
Scope *err_scope = err_var->child_scope;
IrInstruction *unwrapped_err_code_ptr = ir_build_unwrap_maybe(irb, err_scope, err_symbol_node,
ptr_opt_err_code, false);
@@ -16245,7 +16245,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
ConstExprValue *out_val = &result->value;
out_val->data.x_ptr.special = ConstPtrSpecialRef;
out_val->data.x_ptr.mut = val->data.x_ptr.mut;
- if (type_is_codegen_pointer(child_type)) {
+ if (types_have_same_zig_comptime_repr(type_entry, child_type)) {
out_val->data.x_ptr.data.ref.pointee = maybe_val;
} else {
out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional;
From 84f48a69c4060bf673d3ec62cd33d800654c37d7 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 7 Nov 2018 13:40:27 -0500
Subject: [PATCH 036/190] copy elision: for with aggregates
```zig
export fn entry() void {
var array: [10]Bar = undefined;
var x = for (array) |elem, i| {
if (i == 1) break elem;
} else bar2();
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%array = alloca [10 x %Bar], align 4
%x = alloca %Bar, align 4
%for_index = alloca i64, align 8
%0 = bitcast [10 x %Bar]* %array to i8*, !dbg !60
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 -86, i64 80, i1 false), !dbg !60
call void @llvm.dbg.declare(metadata [10 x %Bar]* %array, metadata !45, metadata !DIExpression()), !dbg !60
store i64 0, i64* %for_index, align 8, !dbg !61
call void @llvm.dbg.declare(metadata i64* %for_index, metadata !55, metadata !DIExpression()), !dbg !63
br label %ForCond, !dbg !61
ForCond: ; preds = %Else, %Entry
%1 = load i64, i64* %for_index, align 8, !dbg !61
%2 = icmp ne i64 %1, 10, !dbg !61
br i1 %2, label %ForBody, label %ForElse, !dbg !61
ForBody: ; preds = %ForCond
%3 = getelementptr inbounds [10 x %Bar], [10 x %Bar]* %array, i64 0, i64 %1, !dbg !61
call void @llvm.dbg.declare(metadata %Bar* %3, metadata !58, metadata !DIExpression()), !dbg !64
%4 = load i64, i64* %for_index, align 8, !dbg !65
%5 = icmp eq i64 %4, 1, !dbg !67
br i1 %5, label %Then, label %Else, !dbg !67
Then: ; preds = %ForBody
%6 = bitcast %Bar* %3 to i8*, !dbg !68
%7 = bitcast %Bar* %x to i8*, !dbg !68
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %7, i8* align 4 %6, i64 8, i1 false), !dbg !68
br label %ForEnd, !dbg !69
Else: ; preds = %ForBody
%8 = add nuw i64 %1, 1, !dbg !61
store i64 %8, i64* %for_index, align 8, !dbg !61
br label %ForCond, !dbg !61
ForElse: ; preds = %ForCond
call fastcc void @bar2(%Bar* sret %x), !dbg !70
br label %ForEnd, !dbg !71
ForEnd: ; preds = %ForElse, %Then
call void @llvm.dbg.declare(metadata %Bar* %x, metadata !59, metadata !DIExpression()), !dbg !72
ret void, !dbg !73
}
```
---
src/codegen.cpp | 14 ++++++++++++++
src/ir.cpp | 44 ++++++++++++++------------------------------
2 files changed, 28 insertions(+), 30 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index bc1375028364..78e137f5d552 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3236,6 +3236,20 @@ static bool value_is_all_undef(ConstExprValue *const_val) {
return false;
}
return true;
+ } else if (const_val->type->id == ZigTypeIdArray) {
+ switch (const_val->data.x_array.special) {
+ case ConstArraySpecialUndef:
+ return true;
+ case ConstArraySpecialBuf:
+ return false;
+ case ConstArraySpecialNone:
+ for (size_t i = 0; i < const_val->type->data.array.len; i += 1) {
+ if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i]))
+ return false;
+ }
+ return true;
+ }
+ zig_unreachable();
} else {
return false;
}
diff --git a/src/ir.cpp b/src/ir.cpp
index 4cf799298ce5..bd6ce25309d3 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5611,7 +5611,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
}
}
-static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node,
+static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval,
IrInstruction *result_loc)
{
assert(node->type == NodeTypeForExpr);
@@ -5650,9 +5650,6 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime);
Scope *child_scope = elem_var->child_scope;
- IrInstruction *elem_alloca = ir_build_alloca_src(irb, child_scope, elem_node, elem_var_type, nullptr, "for_elem");
- ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, elem_alloca);
-
AstNode *index_var_source_node;
ZigVar *index_var;
if (index_node) {
@@ -5676,7 +5673,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
IrBasicBlock *cond_block = ir_create_basic_block(irb, child_scope, "ForCond");
IrBasicBlock *body_block = ir_create_basic_block(irb, child_scope, "ForBody");
IrBasicBlock *end_block = ir_create_basic_block(irb, child_scope, "ForEnd");
- IrBasicBlock *else_block = else_node ? ir_create_basic_block(irb, child_scope, "ForElse") : end_block;
+ IrBasicBlock *else_block = ir_create_basic_block(irb, child_scope, "ForElse");
IrBasicBlock *continue_block = ir_create_basic_block(irb, child_scope, "ForContinue");
IrInstruction *len_val = ir_build_array_len(irb, child_scope, node, array_val);
@@ -5684,20 +5681,14 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_set_cursor_at_end_and_append_block(irb, cond_block);
IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca, nullptr);
- IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);
- IrBasicBlock *after_cond_block = irb->current_basic_block;
- IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
+ IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpNotEq, index_val, len_val, false);
ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, body_block);
IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false, PtrLenSingle);
- IrInstruction *elem_val;
- if (node->data.for_expr.elem_is_ptr) {
- elem_val = elem_ptr;
- } else {
- elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr, nullptr);
- }
- ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_alloca, elem_val));
+ IrInstruction *elem_var_ptr = node->data.for_expr.elem_is_ptr ?
+ ir_build_ref(irb, child_scope, elem_node, elem_ptr, true, false) : elem_ptr;
+ ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, elem_var_ptr);
ZigList incoming_values = {0};
ZigList incoming_blocks = {0};
@@ -5719,28 +5710,21 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_alloca, new_index_val));
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
+ ir_set_cursor_at_end_and_append_block(irb, else_block);
IrInstruction *else_result = nullptr;
if (else_node) {
- ir_set_cursor_at_end_and_append_block(irb, else_block);
-
else_result = ir_gen_node(irb, else_node, parent_scope, LValNone, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
- if (!instr_is_unreachable(else_result))
- ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime));
- }
- IrBasicBlock *after_else_block = irb->current_basic_block;
- ir_set_cursor_at_end_and_append_block(irb, end_block);
-
- if (else_result) {
- incoming_blocks.append(after_else_block);
- incoming_values.append(else_result);
} else {
- incoming_blocks.append(after_cond_block);
- incoming_values.append(void_else_value);
+ else_result = ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
+ ir_mark_gen(ir_build_store_ptr(irb, parent_scope, node, result_loc, else_result));
}
+ if (!instr_is_unreachable(else_result))
+ ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime));
- return ir_build_phi(irb, parent_scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
+ ir_set_cursor_at_end_and_append_block(irb, end_block);
+ return ir_gen_result(irb, parent_scope, node, lval, result_loc);
}
static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -7292,7 +7276,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_gen_while_expr(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeForExpr:
- return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node, result_loc), lval);
+ return ir_gen_for_expr(irb, scope, node, lval, result_loc);
case NodeTypeArrayAccessExpr:
return ir_gen_array_access(irb, scope, node, lval, result_loc);
case NodeTypeReturnExpr:
From 20f243919209c141618176f9a837d9fa08f50450 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 8 Nov 2018 00:30:58 -0500
Subject: [PATCH 037/190] copy elision: runtime and comptime array
initialization
```zig
export fn entry() void {
var array = []Bar.{Bar.{.x = 7, .y = 9}};
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%array = alloca [1 x %Bar], align 4
%0 = bitcast [1 x %Bar]* %array to i8*, !dbg !55
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast ([1 x %Bar]* @0 to i8*), i64 8, i1 false), !dbg !55
call void @llvm.dbg.declare(metadata [1 x %Bar]* %array, metadata !45, metadata !DIExpression()), !dbg !55
ret void, !dbg !56
}
```
```zig
export fn entry() void {
var x = i32(7);
var array = []Bar.{Bar.{.x = x, .y = 9}, bar2()};
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca i32, align 4
%array = alloca [2 x %Bar], align 4
store i32 7, i32* %x, align 4, !dbg !57
call void @llvm.dbg.declare(metadata i32* %x, metadata !45, metadata !DIExpression()), !dbg !57
%0 = getelementptr inbounds [2 x %Bar], [2 x %Bar]* %array, i64 0, i64 0, !dbg !58
%1 = getelementptr inbounds %Bar, %Bar* %0, i32 0, i32 0, !dbg !59
%2 = load i32, i32* %x, align 4, !dbg !60
store i32 %2, i32* %1, align 4, !dbg !60
%3 = getelementptr inbounds %Bar, %Bar* %0, i32 0, i32 1, !dbg !61
store i32 9, i32* %3, align 4, !dbg !61
%4 = getelementptr inbounds [2 x %Bar], [2 x %Bar]* %array, i64 0, i64 1, !dbg !62
call fastcc void @bar2(%Bar* sret %4), !dbg !62
call void @llvm.dbg.declare(metadata [2 x %Bar]* %array, metadata !48, metadata !DIExpression()), !dbg !63
ret void, !dbg !64
}
```
---
src/all_types.hpp | 12 ++-
src/codegen.cpp | 28 +----
src/ir.cpp | 267 ++++++++++++++++++++++++++--------------------
src/ir_print.cpp | 19 +++-
4 files changed, 178 insertions(+), 148 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index a958111ba3f4..b059599d431f 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2209,6 +2209,7 @@ enum IrInstructionId {
IrInstructionIdAssertNonError,
IrInstructionIdErrorUnionFieldErrorSet,
IrInstructionIdFirstArgResultLoc,
+ IrInstructionIdInferArrayType,
};
struct IrInstruction {
@@ -2473,8 +2474,8 @@ struct IrInstructionContainerInitList {
IrInstruction *container_type;
IrInstruction *result_loc;
- size_t item_count;
- IrInstruction **items;
+ size_t elem_count;
+ IrInstruction **elem_result_loc_list;
};
struct IrInstructionContainerInitFieldsField {
@@ -3407,6 +3408,13 @@ struct IrInstructionFirstArgResultLoc {
IrInstruction *fn_ref;
};
+struct IrInstructionInferArrayType {
+ IrInstruction base;
+
+ IrInstruction *src_type;
+ size_t elem_count;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 78e137f5d552..d1244158decc 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -4797,30 +4797,6 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
return result_ptr;
}
-static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable,
- IrInstructionContainerInitList *instruction)
-{
- ZigType *array_type = instruction->base.value.type;
- assert(array_type->id == ZigTypeIdArray);
- LLVMValueRef tmp_array_ptr = ir_llvm_value(g, instruction->result_loc);
- assert(tmp_array_ptr);
-
- size_t field_count = instruction->item_count;
-
- ZigType *child_type = array_type->data.array.child_type;
- for (size_t i = 0; i < field_count; i += 1) {
- LLVMValueRef elem_val = ir_llvm_value(g, instruction->items[i]);
- LLVMValueRef indices[] = {
- LLVMConstNull(g->builtin_types.entry_usize->type_ref),
- LLVMConstInt(g->builtin_types.entry_usize->type_ref, i, false),
- };
- LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, "");
- gen_assign_raw(g, elem_ptr, get_pointer_to_type(g, child_type, false), elem_val);
- }
-
- return tmp_array_ptr;
-}
-
static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope));
return nullptr;
@@ -5257,6 +5233,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdAllocaGen:
case IrInstructionIdFirstArgResultLoc:
case IrInstructionIdResultCast:
+ case IrInstructionIdContainerInitList:
+ case IrInstructionIdInferArrayType:
zig_unreachable();
case IrInstructionIdDeclVarGen:
@@ -5369,8 +5347,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_int_to_err(g, executable, (IrInstructionIntToErr *)instruction);
case IrInstructionIdErrToInt:
return ir_render_err_to_int(g, executable, (IrInstructionErrToInt *)instruction);
- case IrInstructionIdContainerInitList:
- return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction);
case IrInstructionIdPanic:
return ir_render_panic(g, executable, (IrInstructionPanic *)instruction);
case IrInstructionIdTagName:
diff --git a/src/ir.cpp b/src/ir.cpp
index bd6ce25309d3..c3876e7afb00 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -931,6 +931,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFirstArgResultLo
return IrInstructionIdFirstArgResultLoc;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionInferArrayType *) {
+ return IrInstructionIdInferArrayType;
+}
+
template
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate(1);
@@ -1335,17 +1339,20 @@ static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *sour
}
static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *container_type, size_t item_count, IrInstruction **items)
+ IrInstruction *container_type, size_t elem_count, IrInstruction **elem_result_loc_list,
+ IrInstruction *result_loc)
{
IrInstructionContainerInitList *container_init_list_instruction =
ir_build_instruction(irb, scope, source_node);
container_init_list_instruction->container_type = container_type;
- container_init_list_instruction->item_count = item_count;
- container_init_list_instruction->items = items;
+ container_init_list_instruction->elem_count = elem_count;
+ container_init_list_instruction->elem_result_loc_list = elem_result_loc_list;
+ container_init_list_instruction->result_loc = result_loc;
+ ir_ref_instruction(result_loc, irb->current_basic_block);
ir_ref_instruction(container_type, irb->current_basic_block);
- for (size_t i = 0; i < item_count; i += 1) {
- ir_ref_instruction(items[i], irb->current_basic_block);
+ for (size_t i = 0; i < elem_count; i += 1) {
+ ir_ref_instruction(elem_result_loc_list[i], irb->current_basic_block);
}
return &container_init_list_instruction->base;
@@ -2989,6 +2996,18 @@ static IrInstruction *ir_build_first_arg_result_loc(IrBuilder *irb, Scope *scope
return &instruction->base;
}
+static IrInstruction *ir_build_infer_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *src_type, size_t elem_count)
+{
+ IrInstructionInferArrayType *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->src_type = src_type;
+ instruction->elem_count = elem_count;
+
+ ir_ref_instruction(src_type, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -5284,20 +5303,23 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields, new_result_loc);
return ir_gen_result(irb, scope, node, lval, result_loc);
} else if (kind == ContainerInitKindArray) {
- size_t item_count = container_init_expr->entries.length;
- IrInstruction **values = allocate(item_count);
- for (size_t i = 0; i < item_count; i += 1) {
+ size_t elem_count = container_init_expr->entries.length;
+ IrInstruction *array_type = ir_build_infer_array_type(irb, scope, node, container_type, elem_count);
+ IrInstruction *new_result_loc = ir_build_result_cast(irb, scope, node, array_type, result_loc);
+
+ IrInstruction **result_locs = allocate(elem_count);
+ for (size_t i = 0; i < elem_count; i += 1) {
AstNode *expr_node = container_init_expr->entries.at(i);
IrInstruction *index_value = ir_build_const_usize(irb, scope, expr_node, i);
- IrInstruction *elem_result_loc = ir_build_elem_ptr(irb, scope, expr_node, result_loc, index_value, true,
- PtrLenSingle);
+ IrInstruction *elem_result_loc = ir_build_elem_ptr(irb, scope, expr_node, new_result_loc,
+ index_value, true, PtrLenSingle);
IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope, LValNone, elem_result_loc);
if (expr_value == irb->codegen->invalid_instruction)
return expr_value;
- values[i] = expr_value;
+ result_locs[i] = expr_value;
}
- ir_build_container_init_list(irb, scope, node, container_type, item_count, values);
+ ir_build_container_init_list(irb, scope, node, array_type, elem_count, result_locs, new_result_loc);
return ir_gen_result(irb, scope, node, lval, result_loc);
} else {
zig_unreachable();
@@ -14840,6 +14862,26 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
if (array_ptr_val == nullptr)
return ira->codegen->invalid_instruction;
+ if (orig_array_ptr_val->data.x_ptr.mut == ConstPtrMutInfer &&
+ array_ptr_val->special == ConstValSpecialUndef &&
+ array_type->id == ZigTypeIdArray)
+ {
+ array_ptr_val->data.x_array.special = ConstArraySpecialNone;
+ array_ptr_val->data.x_array.data.s_none.elements = create_const_vals(array_type->data.array.len);
+ array_ptr_val->special = ConstValSpecialStatic;
+ for (size_t i = 0; i != array_type->data.array.len; i += 1) {
+ ConstExprValue *elem_val = &array_ptr_val->data.x_array.data.s_none.elements[i];
+ elem_val->special = ConstValSpecialUndef;
+ elem_val->type = array_type->data.array.child_type;
+ ConstParent *parent = get_const_val_parent(ira->codegen, elem_val);
+ if (parent != nullptr) {
+ parent->id = ConstParentIdArray;
+ parent->data.p_array.array_val = array_ptr_val;
+ parent->data.p_array.elem_index = i;
+ }
+ }
+ }
+
if (array_ptr_val->special != ConstValSpecialRuntime &&
(array_type->id != ZigTypeIdPointer ||
array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr))
@@ -14951,7 +14993,16 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
}
return result;
} else if (array_type->id == ZigTypeIdArray) {
- IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type);
+ IrInstruction *result;
+ if (orig_array_ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope,
+ elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index,
+ false, elem_ptr_instruction->ptr_len);
+ result->value.type = return_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, &elem_ptr_instruction->base, return_type);
+ }
ConstExprValue *out_val = &result->value;
out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
out_val->data.x_ptr.mut = orig_array_ptr_val->data.x_ptr.mut;
@@ -15072,6 +15123,12 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
ConstExprValue *field_val = &struct_val->data.x_struct.fields[i];
field_val->special = ConstValSpecialUndef;
field_val->type = bare_type->data.structure.fields[i].type_entry;
+ ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
+ if (parent != nullptr) {
+ parent->id = ConstParentIdStruct;
+ parent->data.p_struct.struct_val = struct_val;
+ parent->data.p_struct.field_index = i;
+ }
}
}
ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index];
@@ -16933,7 +16990,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
if (const_ptrs.length == actual_field_count) {
result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
} else {
- result_loc->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
result_loc->value.special = ConstValSpecialRuntime;
for (size_t i = 0; i < const_ptrs.length; i += 1) {
IrInstruction *field_result_loc = const_ptrs.at(i);
@@ -16950,123 +17006,85 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
IrInstructionContainerInitList *instruction)
{
- IrInstruction *container_type_value = instruction->container_type->child;
- if (type_is_invalid(container_type_value->value.type))
+ ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child);
+ if (type_is_invalid(container_type))
return ira->codegen->invalid_instruction;
- size_t elem_count = instruction->item_count;
- if (container_type_value->value.type->id == ZigTypeIdMetaType) {
- ZigType *container_type = ir_resolve_type(ira, container_type_value);
- if (type_is_invalid(container_type))
- return ira->codegen->invalid_instruction;
-
- if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) {
- return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
- 0, nullptr, nullptr);
- } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) {
- // array is same as slice init but we make a compile error if the length is wrong
- ZigType *child_type;
- if (container_type->id == ZigTypeIdArray) {
- child_type = container_type->data.array.child_type;
- if (container_type->data.array.len != elem_count) {
- ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count);
-
- ir_add_error(ira, &instruction->base,
- buf_sprintf("expected %s literal, found %s literal",
- buf_ptr(&container_type->name), buf_ptr(&literal_type->name)));
- return ira->codegen->invalid_instruction;
- }
- } else {
- ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
- assert(pointer_type->id == ZigTypeIdPointer);
- child_type = pointer_type->data.pointer.child_type;
- }
-
- ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
+ // handled by IrInstructionInferArrayType
+ assert(!is_slice(container_type));
- ConstExprValue const_val = {};
- const_val.special = ConstValSpecialStatic;
- const_val.type = fixed_size_array_type;
- const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count);
-
- bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope);
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
- IrInstruction **new_items = allocate(elem_count);
+ size_t elem_count = instruction->elem_count;
- IrInstruction *first_non_const_instruction = nullptr;
+ if (container_type->id == ZigTypeIdStruct && elem_count == 0)
+ return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, nullptr);
- for (size_t i = 0; i < elem_count; i += 1) {
- IrInstruction *arg_value = instruction->items[i]->child;
- if (type_is_invalid(arg_value->value.type))
- return ira->codegen->invalid_instruction;
+ if (container_type->id == ZigTypeIdVoid) {
+ if (elem_count != 0) {
+ ir_add_error_node(ira, instruction->base.source_node,
+ buf_sprintf("void expression expects no arguments"));
+ return ira->codegen->invalid_instruction;
+ }
+ return ir_const_void(ira, &instruction->base);
+ }
- IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type);
- if (casted_arg == ira->codegen->invalid_instruction)
- return ira->codegen->invalid_instruction;
+ if (container_type->id != ZigTypeIdArray) {
+ ir_add_error_node(ira, instruction->base.source_node,
+ buf_sprintf("type '%s' does not support array initialization",
+ buf_ptr(&container_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
- new_items[i] = casted_arg;
+ // array is same as slice init but we make a compile error if the length is wrong
+ ZigType *child_type = container_type->data.array.child_type;
+ if (container_type->data.array.len != elem_count) {
+ ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count);
- if (const_val.special == ConstValSpecialStatic) {
- if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) {
- ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad);
- if (!elem_val)
- return ira->codegen->invalid_instruction;
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("expected %s literal, found %s literal",
+ buf_ptr(&container_type->name), buf_ptr(&literal_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
- copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true);
- } else {
- first_non_const_instruction = casted_arg;
- const_val.special = ConstValSpecialRuntime;
- }
- }
- }
+ // The Result Location Mechanism has already emitted runtime instructions to
+ // initialize runtime elements and has omitted instructions for the comptime
+ // elements. However it is only now that we find out whether the array initialization
+ // can be a comptime value. So we must clean up the situation. If it turns out
+ // array initialization can be a comptime value, overwrite ConstPtrMutInfer with
+ // ConstPtrMutComptimeConst. Otherwise, emit instructions to runtime-initialize the
+ // elements that have comptime-known values.
+ ZigList const_ptrs = {};
- if (const_val.special == ConstValSpecialStatic) {
- IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
- ConstExprValue *out_val = &result->value;
- // TODO copy_const_val?
- *out_val = const_val;
- result->value.type = fixed_size_array_type;
- for (size_t i = 0; i < elem_count; i += 1) {
- ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i];
- ConstParent *parent = get_const_val_parent(ira->codegen, elem_val);
- if (parent != nullptr) {
- parent->id = ConstParentIdArray;
- parent->data.p_array.array_val = out_val;
- parent->data.p_array.elem_index = i;
- }
- }
- return result;
- }
+ for (size_t i = 0; i < elem_count; i += 1) {
+ IrInstruction *elem_result_loc = instruction->elem_result_loc_list[i]->child;
+ if (type_is_invalid(elem_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
- if (is_comptime) {
- ir_add_error_node(ira, first_non_const_instruction->source_node,
- buf_sprintf("unable to evaluate constant expression"));
- return ira->codegen->invalid_instruction;
- }
+ if (instr_is_comptime(elem_result_loc) &&
+ elem_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ const_ptrs.append(elem_result_loc);
+ }
+ }
- IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node,
- container_type_value, elem_count, new_items);
- new_instruction->value.type = fixed_size_array_type;
- return new_instruction;
- } else if (container_type->id == ZigTypeIdVoid) {
- if (elem_count != 0) {
- ir_add_error_node(ira, instruction->base.source_node,
- buf_sprintf("void expression expects no arguments"));
- return ira->codegen->invalid_instruction;
- }
- return ir_const_void(ira, &instruction->base);
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (const_ptrs.length == elem_count) {
+ result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
} else {
- ir_add_error_node(ira, instruction->base.source_node,
- buf_sprintf("type '%s' does not support array initialization",
- buf_ptr(&container_type->name)));
- return ira->codegen->invalid_instruction;
+ result_loc->value.special = ConstValSpecialRuntime;
+ for (size_t i = 0; i < const_ptrs.length; i += 1) {
+ IrInstruction *elem_result_loc = const_ptrs.at(i);
+ IrInstruction *deref = ir_get_deref(ira, elem_result_loc, elem_result_loc);
+ elem_result_loc->value.special = ConstValSpecialRuntime;
+ ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref);
+ }
}
- } else {
- ir_add_error(ira, container_type_value,
- buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name)));
- return ira->codegen->invalid_instruction;
}
+
+ return ir_const_void(ira, &instruction->base);
}
static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira,
@@ -21751,6 +21769,22 @@ static IrInstruction *ir_analyze_instruction_first_arg_result_loc(IrAnalyze *ira
return &result->base;
}
+static IrInstruction *ir_analyze_instruction_infer_array_type(IrAnalyze *ira,
+ IrInstructionInferArrayType *instruction)
+{
+ ZigType *src_type = ir_resolve_type(ira, instruction->src_type->child);
+ if (type_is_invalid(src_type))
+ return ira->codegen->invalid_instruction;
+
+ if (!is_slice(src_type)) {
+ return ir_const_type(ira, &instruction->base, src_type);
+ }
+
+ ZigType *child_type = src_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type;
+ ZigType *array_type = get_array_type(ira->codegen, child_type, instruction->elem_count);
+ return ir_const_type(ira, &instruction->base, array_type);
+}
+
static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -22048,6 +22082,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_error_union_field_error_set(ira, (IrInstructionErrorUnionFieldErrorSet *)instruction);
case IrInstructionIdFirstArgResultLoc:
return ir_analyze_instruction_first_arg_result_loc(ira, (IrInstructionFirstArgResultLoc *)instruction);
+ case IrInstructionIdInferArrayType:
+ return ir_analyze_instruction_infer_array_type(ira, (IrInstructionInferArrayType *)instruction);
case IrInstructionIdResultBytesToSlice:
zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
@@ -22287,6 +22323,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdAllocaGen:
case IrInstructionIdErrorUnionFieldErrorSet:
case IrInstructionIdFirstArgResultLoc:
+ case IrInstructionIdInferArrayType:
return false;
case IrInstructionIdLoadPtr:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index aeacce36301b..07137c346c2f 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -268,14 +268,14 @@ static void ir_print_phi(IrPrint *irp, IrInstructionPhi *phi_instruction) {
static void ir_print_container_init_list(IrPrint *irp, IrInstructionContainerInitList *instruction) {
ir_print_other_instruction(irp, instruction->container_type);
fprintf(irp->f, "{");
- if (instruction->item_count > 50) {
- fprintf(irp->f, "...(%" ZIG_PRI_usize " items)...", instruction->item_count);
+ if (instruction->elem_count > 50) {
+ fprintf(irp->f, "...(%" ZIG_PRI_usize " items)...", instruction->elem_count);
} else {
- for (size_t i = 0; i < instruction->item_count; i += 1) {
- IrInstruction *item = instruction->items[i];
+ for (size_t i = 0; i < instruction->elem_count; i += 1) {
+ IrInstruction *elem_result_loc = instruction->elem_result_loc_list[i];
if (i != 0)
fprintf(irp->f, ", ");
- ir_print_other_instruction(irp, item);
+ ir_print_other_instruction(irp, elem_result_loc);
}
}
fprintf(irp->f, "}");
@@ -1417,6 +1417,12 @@ static void ir_print_first_arg_result_loc(IrPrint *irp, IrInstructionFirstArgRes
fprintf(irp->f, ")");
}
+static void ir_print_infer_array_type(IrPrint *irp, IrInstructionInferArrayType *instruction) {
+ fprintf(irp->f, "InferArrayType(src_type=");
+ ir_print_other_instruction(irp, instruction->src_type);
+ fprintf(irp->f, ",elem_count=%zu)", instruction->elem_count);
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1887,6 +1893,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdFirstArgResultLoc:
ir_print_first_arg_result_loc(irp, (IrInstructionFirstArgResultLoc *)instruction);
break;
+ case IrInstructionIdInferArrayType:
+ ir_print_infer_array_type(irp, (IrInstructionInferArrayType *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
From 2c65a5ad23d09d33836660e589b29b9d4ef35437 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 8 Nov 2018 11:18:37 -0500
Subject: [PATCH 038/190] copy elision: runtime and comptime union init
```zig
export fn entry() void {
var u = U.{.Bar = bar()};
}
```
```llvm
define void @entry() #2 !dbg !47 {
Entry:
%u = alloca %U, align 4
%0 = getelementptr inbounds %U, %U* %u, i32 0, i32 1, !dbg !71
store i2 1, i2* %0, align 1, !dbg !71
%1 = getelementptr inbounds %U, %U* %u, i32 0, i32 0, !dbg !71
%2 = bitcast %Foo* %1 to %Bar*, !dbg !71
call fastcc void @bar(%Bar* sret %2), !dbg !72
call void @llvm.dbg.declare(metadata %U* %u, metadata !51, metadata !DIExpression()), !dbg !73
ret void, !dbg !74
}
```
---
src/all_types.hpp | 32 ++-----
src/codegen.cpp | 86 ++++---------------
src/ir.cpp | 207 +++++++++++++++++++---------------------------
src/ir_print.cpp | 27 ------
4 files changed, 107 insertions(+), 245 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index b059599d431f..fff3c4e33f4f 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2077,8 +2077,6 @@ enum IrInstructionId {
IrInstructionIdCast,
IrInstructionIdContainerInitList,
IrInstructionIdContainerInitFields,
- IrInstructionIdStructInit,
- IrInstructionIdUnionInit,
IrInstructionIdUnreachable,
IrInstructionIdTypeOf,
IrInstructionIdToPtrType,
@@ -2406,11 +2404,18 @@ struct IrInstructionStructFieldPtr {
bool is_const;
};
+enum IrInstructionUnionFieldPtrId {
+ IrInstructionUnionFieldPtrIdRef,
+ IrInstructionUnionFieldPtrIdSwitch,
+ IrInstructionUnionFieldPtrIdResultPtr,
+};
+
struct IrInstructionUnionFieldPtr {
IrInstruction base;
IrInstruction *union_ptr;
TypeUnionField *field;
+ IrInstructionUnionFieldPtrId id;
bool is_const;
};
@@ -2494,29 +2499,6 @@ struct IrInstructionContainerInitFields {
IrInstruction *result_loc;
};
-struct IrInstructionStructInitField {
- IrInstruction *value;
- TypeStructField *type_struct_field;
-};
-
-struct IrInstructionStructInit {
- IrInstruction base;
-
- ZigType *struct_type;
- IrInstruction *result_loc;
- size_t field_count;
- IrInstructionStructInitField *fields;
-};
-
-struct IrInstructionUnionInit {
- IrInstruction base;
-
- ZigType *union_type;
- TypeUnionField *field;
- IrInstruction *init_value;
- IrInstruction *result_loc;
-};
-
struct IrInstructionUnreachable {
IrInstruction base;
};
diff --git a/src/codegen.cpp b/src/codegen.cpp
index d1244158decc..8c2461da4fe9 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3591,7 +3591,10 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
return bitcasted_union_field_ptr;
}
- if (ir_want_runtime_safety(g, &instruction->base)) {
+ bool safety_check_on = instruction->id == IrInstructionUnionFieldPtrIdRef &&
+ ir_want_runtime_safety(g, &instruction->base);
+
+ if (safety_check_on) {
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, "");
LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, "");
@@ -3609,7 +3612,16 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
- LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, "");
+ if (instruction->id == IrInstructionUnionFieldPtrIdResultPtr) {
+ LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr,
+ union_type->data.unionation.gen_tag_index, "");
+ LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
+ &field->enum_field->value);
+ gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
+ }
+
+ LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr,
+ union_type->data.unionation.gen_union_index, "");
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
return bitcasted_union_field_ptr;
}
@@ -4731,72 +4743,6 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir
return get_handle_value(g, tag_field_ptr, tag_type, ptr_type);
}
-static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
- IrInstructionStructInit *instruction)
-{
- LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
-
- for (size_t i = 0; i < instruction->field_count; i += 1) {
- IrInstructionStructInitField *field = &instruction->fields[i];
- TypeStructField *type_struct_field = field->type_struct_field;
- if (!type_has_bits(type_struct_field->type_entry))
- continue;
-
- LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
- (unsigned)type_struct_field->gen_index, "");
- LLVMValueRef value = ir_llvm_value(g, field->value);
-
- uint32_t field_align_bytes = get_abi_alignment(g, type_struct_field->type_entry);
- uint32_t host_int_bytes = get_host_int_bytes(g, instruction->struct_type, type_struct_field);
-
- ZigType *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry,
- false, false, PtrLenSingle, field_align_bytes,
- (uint32_t)type_struct_field->bit_offset_in_host, host_int_bytes);
-
- gen_assign_raw(g, field_ptr, ptr_type, value);
- }
- return result_ptr;
-}
-
-static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) {
- TypeUnionField *type_union_field = instruction->field;
-
- if (!type_has_bits(type_union_field->type_entry))
- return nullptr;
-
- uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry);
- ZigType *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry,
- false, false, PtrLenSingle, field_align_bytes,
- 0, 0);
-
- LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
-
- LLVMValueRef uncasted_union_ptr;
- // Even if safety is off in this block, if the union type has the safety field, we have to populate it
- // correctly. Otherwise safety code somewhere other than here could fail.
- ZigType *union_type = instruction->union_type;
- if (union_type->data.unionation.gen_tag_index != SIZE_MAX) {
- LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
- union_type->data.unionation.gen_tag_index, "");
-
- LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
- &type_union_field->enum_field->value);
- gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
-
- uncasted_union_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
- (unsigned)union_type->data.unionation.gen_union_index, "");
- } else {
- uncasted_union_ptr = LLVMBuildStructGEP(g->builder, result_ptr, (unsigned)0, "");
- }
-
- LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, ptr_type->type_ref, "");
- LLVMValueRef value = ir_llvm_value(g, instruction->init_value);
-
- gen_assign_raw(g, field_ptr, ptr_type, value);
-
- return result_ptr;
-}
-
static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope));
return nullptr;
@@ -5327,10 +5273,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);
case IrInstructionIdUnionTag:
return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction);
- case IrInstructionIdStructInit:
- return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
- case IrInstructionIdUnionInit:
- return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction);
case IrInstructionIdPtrCast:
return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction);
case IrInstructionIdBitCast:
diff --git a/src/ir.cpp b/src/ir.cpp
index c3876e7afb00..cee633f87e9a 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -515,14 +515,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionRef *) {
return IrInstructionIdRef;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) {
- return IrInstructionIdStructInit;
-}
-
-static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) {
- return IrInstructionIdUnionInit;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileErr *) {
return IrInstructionIdCompileErr;
}
@@ -1229,11 +1221,12 @@ static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, As
}
static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *union_ptr, TypeUnionField *field)
+ IrInstruction *union_ptr, TypeUnionField *field, IrInstructionUnionFieldPtrId id)
{
IrInstructionUnionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node);
instruction->union_ptr = union_ptr;
instruction->field = field;
+ instruction->id = id;
ir_ref_instruction(union_ptr, irb->current_basic_block);
@@ -1378,33 +1371,6 @@ static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scop
return &container_init_fields_instruction->base;
}
-//static IrInstruction *ir_build_struct_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
-// ZigType *struct_type, size_t field_count, IrInstructionStructInitField *fields)
-//{
-// IrInstructionStructInit *struct_init_instruction = ir_build_instruction(irb, scope, source_node);
-// struct_init_instruction->struct_type = struct_type;
-// struct_init_instruction->field_count = field_count;
-// struct_init_instruction->fields = fields;
-//
-// for (size_t i = 0; i < field_count; i += 1)
-// ir_ref_instruction(fields[i].value, irb->current_basic_block);
-//
-// return &struct_init_instruction->base;
-//}
-
-//static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
-// ZigType *union_type, TypeUnionField *field, IrInstruction *init_value)
-//{
-// IrInstructionUnionInit *union_init_instruction = ir_build_instruction(irb, scope, source_node);
-// union_init_instruction->union_type = union_type;
-// union_init_instruction->field = field;
-// union_init_instruction->init_value = init_value;
-//
-// ir_ref_instruction(init_value, irb->current_basic_block);
-//
-// return &union_init_instruction->base;
-//}
-
static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionUnreachable *unreachable_instruction =
ir_build_instruction(irb, scope, source_node);
@@ -4694,7 +4660,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *ptr_to_int = ir_build_ptr_to_int(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, ptr_to_int, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ptr_to_int);
}
case BuiltinFnIdTagName:
{
@@ -15183,22 +15149,37 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
if (type_is_invalid(union_val->type))
return ira->codegen->invalid_instruction;
- TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag);
- if (actual_field == nullptr)
- zig_unreachable();
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer &&
+ union_val->special == ConstValSpecialUndef)
+ {
+ ConstExprValue *payload_val = create_const_vals(1);
+ payload_val->special = ConstValSpecialUndef;
+ payload_val->type = field->type_entry;
+ ConstParent *parent = get_const_val_parent(ira->codegen, payload_val);
+ if (parent != nullptr) {
+ parent->id = ConstParentIdUnion;
+ parent->data.p_union.union_val = union_val;
+ }
- if (field != actual_field) {
- ir_add_error_node(ira, source_instr->source_node,
- buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name),
- buf_ptr(actual_field->name)));
- return ira->codegen->invalid_instruction;
- }
+ union_val->special = ConstValSpecialStatic;
+ bigint_init_bigint(&union_val->data.x_union.tag, &field->enum_field->value);
+ union_val->data.x_union.payload = payload_val;
+ } else {
+ TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag);
+ if (actual_field == nullptr)
+ zig_unreachable();
+ if (field != actual_field) {
+ ir_add_error_node(ira, source_instr->source_node,
+ buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name),
+ buf_ptr(actual_field->name)));
+ return ira->codegen->invalid_instruction;
+ }
+ }
ConstExprValue *payload_val = union_val->data.x_union.payload;
ZigType *field_type = field->type_entry;
- if (field_type->id == ZigTypeIdVoid) {
- assert(payload_val == nullptr);
+ if (field_type->id == ZigTypeIdVoid && payload_val == nullptr) {
payload_val = create_const_vals(1);
payload_val->special = ConstValSpecialStatic;
payload_val->type = field_type;
@@ -15207,16 +15188,26 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type,
is_const, is_volatile, PtrLenSingle, 0, 0, 0);
- IrInstruction *result = ir_const(ira, source_instr, ptr_type);
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, container_ptr, field,
+ IrInstructionUnionFieldPtrIdResultPtr);
+ result->value.type = ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, source_instr, ptr_type);
+ }
ConstExprValue *const_val = &result->value;
const_val->data.x_ptr.special = ConstPtrSpecialRef;
- const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut;
+ const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
const_val->data.x_ptr.data.ref.pointee = payload_val;
return result;
}
}
- IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field);
+ IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, container_ptr, field, IrInstructionUnionFieldPtrIdRef);
result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
PtrLenSingle, 0, 0, 0);
return result;
@@ -16720,7 +16711,8 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
}
IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node, target_value_ptr, field);
+ instruction->base.scope, instruction->base.source_node, target_value_ptr, field,
+ IrInstructionUnionFieldPtrIdSwitch);
result->value.type = get_pointer_to_type(ira->codegen, field->type_entry,
target_value_ptr->value.type->data.pointer.is_const);
return result;
@@ -16845,71 +16837,47 @@ static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRe
}
static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction,
- ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)
+ ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields,
+ IrInstruction *result_loc)
{
- zig_panic("TODO");
- //Error err;
- //assert(container_type->id == ZigTypeIdUnion);
-
- //if ((err = ensure_complete_type(ira->codegen, container_type)))
- // return ira->codegen->invalid_instruction;
-
- //if (instr_field_count != 1) {
- // ir_add_error(ira, instruction,
- // buf_sprintf("union initialization expects exactly one field"));
- // return ira->codegen->invalid_instruction;
- //}
-
- //IrInstructionContainerInitFieldsField *field = &fields[0];
- //IrInstruction *field_value = field->value->child;
- //if (type_is_invalid(field_value->value.type))
- // return ira->codegen->invalid_instruction;
-
- //TypeUnionField *type_field = find_union_type_field(container_type, field->name);
- //if (!type_field) {
- // ir_add_error_node(ira, field->source_node,
- // buf_sprintf("no member named '%s' in union '%s'",
- // buf_ptr(field->name), buf_ptr(&container_type->name)));
- // return ira->codegen->invalid_instruction;
- //}
-
- //if (type_is_invalid(type_field->type_entry))
- // return ira->codegen->invalid_instruction;
-
- //IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry);
- //if (casted_field_value == ira->codegen->invalid_instruction)
- // return ira->codegen->invalid_instruction;
-
- //if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown)))
- // return ira->codegen->invalid_instruction;
-
- //bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
- //if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime ||
- // !type_has_bits(casted_field_value->value.type))
- //{
- // ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
- // if (!field_val)
- // return ira->codegen->invalid_instruction;
-
- // IrInstruction *result = ir_const(ira, instruction, container_type);
- // ConstExprValue *out_val = &result->value;
- // out_val->data.x_union.payload = field_val;
- // out_val->data.x_union.tag = type_field->enum_field->value;
-
- // ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
- // if (parent != nullptr) {
- // parent->id = ConstParentIdUnion;
- // parent->data.p_union.union_val = out_val;
- // }
-
- // return result;
- //}
-
- //IrInstruction *new_instruction = ir_build_union_init(&ira->new_irb,
- // instruction->scope, instruction->source_node,
- // container_type, type_field, casted_field_value);
- //new_instruction->value.type = container_type;
- //return new_instruction;
+ Error err;
+ assert(container_type->id == ZigTypeIdUnion);
+
+ if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
+ return ira->codegen->invalid_instruction;
+
+ if (instr_field_count != 1) {
+ ir_add_error(ira, instruction,
+ buf_sprintf("union initialization expects exactly one field"));
+ return ira->codegen->invalid_instruction;
+ }
+
+ IrInstructionContainerInitFieldsField *field = &fields[0];
+ IrInstruction *field_result_loc = field->result_loc->child;
+ if (type_is_invalid(field_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ TypeUnionField *type_field = find_union_type_field(container_type, field->name);
+ if (!type_field) {
+ ir_add_error_node(ira, field->source_node,
+ buf_sprintf("no member named '%s' in union '%s'",
+ buf_ptr(field->name), buf_ptr(&container_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if (type_is_invalid(type_field->type_entry))
+ return ira->codegen->invalid_instruction;
+
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(field_result_loc) &&
+ field_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ result_loc->value.special = ConstValSpecialRuntime;
+ }
+ }
+ return ir_const_void(ira, instruction);
}
static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction,
@@ -16917,7 +16885,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
IrInstruction *result_loc)
{
if (container_type->id == ZigTypeIdUnion) {
- return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields);
+ return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count,
+ fields, result_loc);
}
if (container_type->id != ZigTypeIdStruct || is_slice(container_type)) {
ir_add_error(ira, instruction,
@@ -21789,8 +21758,6 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
switch (instruction->id) {
case IrInstructionIdInvalid:
case IrInstructionIdWidenOrShorten:
- case IrInstructionIdStructInit:
- case IrInstructionIdUnionInit:
case IrInstructionIdStructFieldPtr:
case IrInstructionIdUnionFieldPtr:
case IrInstructionIdOptionalWrap:
@@ -22228,8 +22195,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdBinOp:
case IrInstructionIdConst:
case IrInstructionIdCast:
- case IrInstructionIdStructInit:
- case IrInstructionIdUnionInit:
case IrInstructionIdFieldPtr:
case IrInstructionIdElemPtr:
case IrInstructionIdVarPtr:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 07137c346c2f..7c157272e235 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -294,27 +294,6 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI
ir_print_other_instruction(irp, instruction->result_loc);
}
-static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruction) {
- fprintf(irp->f, "%s {", buf_ptr(&instruction->struct_type->name));
- for (size_t i = 0; i < instruction->field_count; i += 1) {
- IrInstructionStructInitField *field = &instruction->fields[i];
- Buf *field_name = field->type_struct_field->name;
- const char *comma = (i == 0) ? "" : ", ";
- fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field_name));
- ir_print_other_instruction(irp, field->value);
- }
- fprintf(irp->f, "} // struct init");
-}
-
-static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) {
- Buf *field_name = instruction->field->enum_field->name;
-
- fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name));
- fprintf(irp->f, ".%s = ", buf_ptr(field_name));
- ir_print_other_instruction(irp, instruction->init_value);
- fprintf(irp->f, "} // union init");
-}
-
static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {
fprintf(irp->f, "unreachable");
}
@@ -1464,12 +1443,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdContainerInitFields:
ir_print_container_init_fields(irp, (IrInstructionContainerInitFields *)instruction);
break;
- case IrInstructionIdStructInit:
- ir_print_struct_init(irp, (IrInstructionStructInit *)instruction);
- break;
- case IrInstructionIdUnionInit:
- ir_print_union_init(irp, (IrInstructionUnionInit *)instruction);
- break;
case IrInstructionIdUnreachable:
ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction);
break;
From 65501f03b6e218ab02448e1c156128213b7da5b9 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 9 Nov 2018 13:33:01 -0500
Subject: [PATCH 039/190] copy elision: handle inferred comptime const with if
```zig
export fn entry() void {
var c = true;
var f = foo();
var x: Bar = if (c) undefined else f.y;
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%c = alloca i1, align 1
%f = alloca %Foo, align 4
%x = alloca %Bar, align 4
store i1 true, i1* %c, align 1, !dbg !61
call void @llvm.dbg.declare(metadata i1* %c, metadata !45, metadata !DIExpression()), !dbg !61
call fastcc void @foo(%Foo* sret %f), !dbg !62
call void @llvm.dbg.declare(metadata %Foo* %f, metadata !48, metadata !DIExpression()), !dbg !63
%0 = load i1, i1* %c, align 1, !dbg !64
br i1 %0, label %Then, label %Else, !dbg !64
Then: ; preds = %Entry
%1 = bitcast %Bar* %x to i8*, !dbg !65
call void @llvm.memset.p0i8.i64(i8* align 4 %1, i8 -86, i64 8, i1 false), !dbg !65
br label %EndIf, !dbg !66
Else: ; preds = %Entry
%2 = getelementptr inbounds %Foo, %Foo* %f, i32 0, i32 1, !dbg !67
%3 = bitcast %Bar* %2 to i8*, !dbg !67
%4 = bitcast %Bar* %x to i8*, !dbg !67
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %4, i8* align 4 %3, i64 8, i1 false), !dbg !67
br label %EndIf, !dbg !66
EndIf: ; preds = %Else, %Then
call void @llvm.dbg.declare(metadata %Bar* %x, metadata !59, metadata !DIExpression()), !dbg !68
ret void, !dbg !69
}
```
---
src/all_types.hpp | 1 +
src/ir.cpp | 155 +++++++++++++++++++++++++---------------------
2 files changed, 87 insertions(+), 69 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 1ea39fe652fa..08d3f40d69d4 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2252,6 +2252,7 @@ struct IrInstructionCondBr {
IrBasicBlock *then_block;
IrBasicBlock *else_block;
IrInstruction *is_comptime;
+ IrInstruction *result_loc;
};
struct IrInstructionBr {
diff --git a/src/ir.cpp b/src/ir.cpp
index ffe4b4da22f1..0bc79bf0ecae 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -960,7 +960,7 @@ static IrInstruction *ir_build_cast(IrBuilder *irb, Scope *scope, AstNode *sourc
}
static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *condition,
- IrBasicBlock *then_block, IrBasicBlock *else_block, IrInstruction *is_comptime)
+ IrBasicBlock *then_block, IrBasicBlock *else_block, IrInstruction *is_comptime, IrInstruction *result_loc)
{
IrInstructionCondBr *cond_br_instruction = ir_build_instruction(irb, scope, source_node);
cond_br_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
@@ -969,11 +969,13 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so
cond_br_instruction->then_block = then_block;
cond_br_instruction->else_block = else_block;
cond_br_instruction->is_comptime = is_comptime;
+ cond_br_instruction->result_loc = result_loc;
ir_ref_instruction(condition, irb->current_basic_block);
ir_ref_bb(then_block);
ir_ref_bb(else_block);
- if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block);
+ if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &cond_br_instruction->base;
}
@@ -3141,7 +3143,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, suspended_block);
ir_build_unreachable(irb, scope, node);
@@ -3150,7 +3152,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
// if we ever add null checking safety to the ptrtoint instruction, it needs to be disabled here
IrInstruction *have_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
- ir_build_cond_br(irb, scope, node, have_await_handle, store_awaiter_block, check_canceled_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, have_await_handle, store_awaiter_block, check_canceled_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, store_awaiter_block);
IrInstruction *await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, await_handle_addr);
@@ -3160,7 +3162,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
ir_set_cursor_at_end_and_append_block(irb, check_canceled_block);
IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
- return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime);
+ return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime, nullptr);
}
static IrInstruction *ir_gen_result(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
@@ -3277,7 +3279,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
}
- ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
+ ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime, nullptr));
IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
ir_set_cursor_at_end_and_append_block(irb, err_block);
@@ -3320,7 +3322,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
} else {
is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);
}
- ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
+ ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime, nullptr));
ir_set_cursor_at_end_and_append_block(irb, return_block);
if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
@@ -3550,7 +3552,7 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node
// block for when val1 == true (don't even evaluate the second part)
IrBasicBlock *true_block = ir_create_basic_block(irb, scope, "BoolOrTrue");
- ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, false_block);
IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
@@ -3592,7 +3594,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
// block for when val1 == false (don't even evaluate the second part)
IrBasicBlock *false_block = ir_create_basic_block(irb, scope, "BoolAndFalse");
- ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, true_block);
IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
@@ -3635,7 +3637,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode
IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "OrElseNull");
IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OrElseEnd");
- ir_build_cond_br(irb, parent_scope, node, is_non_null, end_block, null_block, is_comptime);
+ ir_build_cond_br(irb, parent_scope, node, is_non_null, end_block, null_block, is_comptime, result_loc);
ir_set_cursor_at_end_and_append_block(irb, null_block);
IrInstruction *null_result = ir_gen_node(irb, op2_node, parent_scope, LValNone, result_loc);
@@ -5084,7 +5086,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "Else");
IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "EndIf");
- ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_comptime);
+ ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_comptime, result_loc);
ir_set_cursor_at_end_and_append_block(irb, then_block);
@@ -5413,7 +5415,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (!instr_is_unreachable(is_err)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err,
- else_block, body_block, is_comptime));
+ else_block, body_block, is_comptime, result_loc));
}
ir_set_cursor_at_end_and_append_block(irb, body_block);
@@ -5492,7 +5494,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val);
if (!instr_is_unreachable(is_non_null)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null,
- body_block, else_block, is_comptime));
+ body_block, else_block, is_comptime, result_loc));
}
ir_set_cursor_at_end_and_append_block(irb, body_block);
@@ -5553,7 +5555,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
return cond_val;
if (!instr_is_unreachable(cond_val)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,
- body_block, else_block, is_comptime));
+ body_block, else_block, is_comptime, result_loc));
}
ir_set_cursor_at_end_and_append_block(irb, body_block);
@@ -5679,7 +5681,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_set_cursor_at_end_and_append_block(irb, cond_block);
IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca, nullptr);
IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpNotEq, index_val, len_val, false);
- ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime));
+ ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime, result_loc));
ir_set_cursor_at_end_and_append_block(irb, body_block);
IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false, PtrLenSingle);
@@ -5891,7 +5893,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
} else {
is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null);
}
- ir_build_cond_br(irb, scope, node, is_non_null, then_block, else_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_non_null, then_block, else_block, is_comptime, result_loc);
ir_set_cursor_at_end_and_append_block(irb, then_block);
@@ -5963,7 +5965,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
bool force_comptime = ir_should_inline(irb->exec, scope);
IrInstruction *is_comptime = force_comptime ?
ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err);
- ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime, result_loc);
ir_set_cursor_at_end_and_append_block(irb, ok_block);
@@ -6042,24 +6044,18 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
Buf *var_name = var_symbol_node->data.symbol_expr.symbol;
bool var_is_ptr = prong_node->data.switch_prong.var_is_ptr;
+ IrInstruction *var_type = nullptr; // infer the type
bool is_shadowable = false;
bool is_const = true;
ZigVar *var = ir_create_var(irb, var_symbol_node, scope,
var_name, is_const, is_const, is_shadowable, var_is_comptime);
+
+ IrInstruction *payload_ptr = (prong_value == nullptr) ? target_value_ptr :
+ ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
+ IrInstruction *var_ptr = var_is_ptr ?
+ ir_build_ref(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr;
+ ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_ptr);
child_scope = var->child_scope;
- IrInstruction *var_value;
- IrInstruction *payload_alloca = ir_build_alloca_src(irb, scope, var_symbol_node, nullptr, nullptr, "switch_payload");
- if (prong_value) {
- IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
- var_value = var_is_ptr ?
- var_ptr_value : ir_build_load_result(irb, scope, var_symbol_node, var_ptr_value, payload_alloca);
- } else {
- var_value = var_is_ptr ?
- target_value_ptr : ir_build_load_result(irb, scope, var_symbol_node, target_value_ptr, payload_alloca);
- }
- IrInstruction *var_type = nullptr; // infer the type
- ir_build_store_result(irb, scope, var_symbol_node, payload_alloca, var_value);
- ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, payload_alloca);
} else {
child_scope = scope;
}
@@ -6074,7 +6070,9 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
return true;
}
-static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
+static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeSwitchExpr);
AstNode *target_node = node->data.switch_expr.expr;
@@ -6187,7 +6185,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
assert(ok_bit);
assert(last_item_node);
ir_mark_gen(ir_build_cond_br(irb, scope, last_item_node, ok_bit, range_block_yes,
- range_block_no, is_comptime));
+ range_block_no, is_comptime, result_loc));
ir_set_cursor_at_end_and_append_block(irb, range_block_yes);
if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
@@ -6246,13 +6244,14 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
}
- IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length,
- else_prong != nullptr);
+ IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value,
+ check_ranges.items, check_ranges.length, else_prong != nullptr);
if (cases.length == 0) {
ir_build_br(irb, scope, node, else_block, is_comptime);
} else {
- ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items, is_comptime, switch_prongs_void);
+ ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items,
+ is_comptime, switch_prongs_void);
}
if (!else_prong) {
@@ -6262,11 +6261,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
ir_set_cursor_at_end_and_append_block(irb, end_block);
assert(incoming_blocks.length == incoming_values.length);
- if (incoming_blocks.length == 0) {
- return ir_build_const_void(irb, scope, node);
- } else {
- return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
- }
+ return ir_gen_result(irb, scope, node, lval, result_loc);
}
static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node,
@@ -6511,7 +6506,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
IrBasicBlock *err_block = ir_create_basic_block(irb, parent_scope, "CatchError");
IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "CatchEnd");
- ir_build_cond_br(irb, parent_scope, node, is_err, err_block, end_block, is_comptime);
+ ir_build_cond_br(irb, parent_scope, node, is_err, err_block, end_block, is_comptime, result_loc);
ir_set_cursor_at_end_and_append_block(irb, err_block);
Scope *err_scope;
@@ -6812,12 +6807,12 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
IrInstruction *awaiter_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
IrInstruction *is_returned_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpEq, awaiter_addr, ptr_mask, false);
- ir_build_cond_br(irb, scope, node, is_returned_bool, post_return_block, pre_return_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_returned_bool, post_return_block, pre_return_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, post_return_block);
if (cancel_awaited) {
@@ -6825,7 +6820,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
} else {
IrInstruction *is_awaited_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, await_mask, false);
IrInstruction *is_awaited_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_awaited_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_awaited_bool, done_block, do_cancel_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_awaited_bool, done_block, do_cancel_block, is_comptime, nullptr);
}
ir_set_cursor_at_end_and_append_block(irb, pre_return_block);
@@ -6835,7 +6830,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
} else {
IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_suspended_bool, do_cancel_block, done_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_suspended_bool, do_cancel_block, done_block, is_comptime, nullptr);
}
} else {
ir_build_br(irb, scope, node, done_block, is_comptime);
@@ -6890,12 +6885,12 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
ir_build_unreachable(irb, scope, node);
@@ -7007,7 +7002,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *is_awaited_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, await_mask, false);
IrInstruction *is_awaited_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_awaited_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_awaited_bool, already_awaited_block, not_awaited_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, is_awaited_bool, already_awaited_block, not_awaited_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, already_awaited_block);
ir_build_unreachable(irb, scope, node);
@@ -7017,10 +7012,10 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *is_non_null = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_canceled_bool, cancel_target_block, not_canceled_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, is_canceled_bool, cancel_target_block, not_canceled_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
- ir_build_cond_br(irb, scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, cancel_target_block);
ir_build_cancel(irb, scope, node, target_inst);
@@ -7051,7 +7046,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
AtomicRmwOp_or, AtomicOrderSeqCst);
IrInstruction *my_is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_suspended_mask, false);
IrInstruction *my_is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_suspended_value, zero, false);
- ir_build_cond_br(irb, scope, node, my_is_suspended_bool, my_suspended_block, my_not_suspended_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, my_is_suspended_bool, my_suspended_block, my_not_suspended_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, my_suspended_block);
ir_build_unreachable(irb, scope, node);
@@ -7059,7 +7054,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, my_not_suspended_block);
IrInstruction *my_is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_canceled_mask, false);
IrInstruction *my_is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_canceled_value, zero, false);
- ir_build_cond_br(irb, scope, node, my_is_canceled_bool, cleanup_block, do_suspend_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, my_is_canceled_bool, cleanup_block, do_suspend_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, do_suspend_block);
IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, save_token, const_bool_false);
@@ -7084,7 +7079,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *my_await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, b_my_prev_atomic_value, ptr_mask, false);
IrInstruction *dont_have_my_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpEq, my_await_handle_addr, zero, false);
IrInstruction *dont_destroy_ourselves = ir_build_bin_op(irb, scope, node, IrBinOpBoolAnd, dont_have_my_await_handle, is_canceled_bool, false);
- ir_build_cond_br(irb, scope, node, dont_have_my_await_handle, do_defers_block, do_cancel_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, dont_have_my_await_handle, do_defers_block, do_cancel_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, do_cancel_block);
IrInstruction *my_await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, my_await_handle_addr);
@@ -7093,7 +7088,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, do_defers_block);
ir_gen_defers_for_block(irb, scope, outer_scope, true);
- ir_mark_gen(ir_build_cond_br(irb, scope, node, dont_destroy_ourselves, irb->exec->coro_early_final, irb->exec->coro_final_cleanup_block, const_bool_false));
+ ir_mark_gen(ir_build_cond_br(irb, scope, node, dont_destroy_ourselves, irb->exec->coro_early_final, irb->exec->coro_final_cleanup_block, const_bool_false, nullptr));
ir_set_cursor_at_end_and_append_block(irb, resume_block);
ir_build_br(irb, scope, node, merge_block, const_bool_false);
@@ -7160,13 +7155,13 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
IrInstruction *is_canceled_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
IrInstruction *is_canceled_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
- ir_build_cond_br(irb, parent_scope, node, is_canceled_bool, canceled_block, not_canceled_block, const_bool_false);
+ ir_build_cond_br(irb, parent_scope, node, is_canceled_bool, canceled_block, not_canceled_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, canceled_block);
IrInstruction *await_handle_addr = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
IrInstruction *have_await_handle = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
IrBasicBlock *post_canceled_block = irb->current_basic_block;
- ir_build_cond_br(irb, parent_scope, node, have_await_handle, cancel_awaiter_block, cleanup_block, const_bool_false);
+ ir_build_cond_br(irb, parent_scope, node, have_await_handle, cancel_awaiter_block, cleanup_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, cancel_awaiter_block);
IrInstruction *await_handle = ir_build_int_to_ptr(irb, parent_scope, node, promise_type_val, await_handle_addr);
@@ -7177,7 +7172,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
IrInstruction *is_suspended_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
IrInstruction *is_suspended_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
- ir_build_cond_br(irb, parent_scope, node, is_suspended_bool, suspended_block, not_suspended_block, const_bool_false);
+ ir_build_cond_br(irb, parent_scope, node, is_suspended_bool, suspended_block, not_suspended_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, suspended_block);
ir_build_unreachable(irb, parent_scope, node);
@@ -7213,7 +7208,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
incoming_values[1] = const_bool_false;
IrInstruction *destroy_ourselves = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
- ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, destroy_ourselves, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, const_bool_false));
+ ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, destroy_ourselves, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, const_bool_false, nullptr));
ir_set_cursor_at_end_and_append_block(irb, resume_block);
return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
@@ -7321,11 +7316,11 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_gen_if_optional_expr(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeSwitchExpr:
- return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node, result_loc), lval);
+ return ir_gen_switch_expr(irb, scope, node, lval, result_loc);
case NodeTypeCompTime:
return ir_gen_comptime(irb, scope, node, lval, result_loc);
case NodeTypeErrorType:
- return ir_gen_value(irb, scope, node, lval, result_loc,ir_gen_error_type(irb, scope, node));
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_error_type(irb, scope, node));
case NodeTypeBreak:
return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval);
case NodeTypeContinue:
@@ -7451,7 +7446,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk");
- ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
+ ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
// we can return undefined here, because the caller passes a pointer to the error struct field
@@ -7613,7 +7608,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
nullptr, nullptr, nullptr);
IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
- ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, resume_block);
ir_gen_resume_target(irb, scope, node, awaiter_handle);
@@ -11420,6 +11415,11 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
}
}
+ // cast from undefined to anything
+ if (needed_child_type->id == ZigTypeIdUndefined) {
+ return result_loc;
+ }
+
if (allow_failure) {
return result_loc;
}
@@ -14492,9 +14492,14 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi
if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime))
return ir_unreach_error(ira);
- if (is_comptime || instr_is_comptime(condition)) {
+ ZigType *bool_type = ira->codegen->builtin_types.entry_bool;
+ IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type);
+ if (casted_condition == ira->codegen->invalid_instruction)
+ return ir_unreach_error(ira);
+
+ if (is_comptime || instr_is_comptime(casted_condition)) {
bool cond_is_true;
- if (!ir_resolve_bool(ira, condition, &cond_is_true))
+ if (!ir_resolve_bool(ira, casted_condition, &cond_is_true))
return ir_unreach_error(ira);
IrBasicBlock *old_dest_block = cond_is_true ?
@@ -14513,10 +14518,22 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi
return ir_finish_anal(ira, result);
}
- ZigType *bool_type = ira->codegen->builtin_types.entry_bool;
- IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type);
- if (casted_condition == ira->codegen->invalid_instruction)
- return ir_unreach_error(ira);
+ // The if condition is not comptime known. This means we must mark the result location
+ // as runtime known, in case it is ConstPtrMutInfer.
+ if (cond_br_instruction->result_loc != nullptr) {
+ IrInstruction *result_loc = cond_br_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ir_unreach_error(ira);
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *result_ptr = ir_resolve_const(ira, result_loc, UndefBad);
+ if (result_ptr == nullptr)
+ return ir_unreach_error(ira);
+ assert(result_ptr->type->id == ZigTypeIdPointer);
+ if (result_ptr->data.x_ptr.mut == ConstPtrMutInfer) {
+ result_ptr->special = ConstValSpecialRuntime;
+ }
+ }
+ }
assert(cond_br_instruction->then_block != cond_br_instruction->else_block);
IrBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base);
@@ -14529,7 +14546,7 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi
IrInstruction *result = ir_build_cond_br(&ira->new_irb,
cond_br_instruction->base.scope, cond_br_instruction->base.source_node,
- casted_condition, new_then_block, new_else_block, nullptr);
+ casted_condition, new_then_block, new_else_block, nullptr, nullptr);
result->value.type = ira->codegen->builtin_types.entry_unreachable;
return ir_finish_anal(ira, result);
}
From 40d6ca4854c416b29a8b9f6cdcbb64974419bb92 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 9 Nov 2018 14:32:30 -0500
Subject: [PATCH 040/190] copy elision: switch with aggregate
```zig
export fn entry() void {
var u: U = undefined;
var x: Bar = switch (u) {
U.Foo => |f| f.y,
U.Int => |x| bar2(),
else => undefined,
};
}
```
```llvm
define void @entry() #2 !dbg !47 {
Entry:
%u = alloca %U, align 4
%x = alloca %Bar, align 4
%0 = bitcast %U* %u to i8*, !dbg !75
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 -86, i64 16, i1 false), !dbg !75
call void @llvm.dbg.declare(metadata %U* %u, metadata !51, metadata !DIExpression()), !dbg !75
%1 = getelementptr inbounds %U, %U* %u, i32 0, i32 1, !dbg !76
%2 = load i2, i2* %1, align 1, !dbg !76
switch i2 %2, label %SwitchElse [
i2 0, label %SwitchProng
i2 -2, label %SwitchProng1
], !dbg !76
SwitchElse: ; preds = %Entry
%3 = bitcast %Bar* %x to i8*, !dbg !77
call void @llvm.memset.p0i8.i64(i8* align 4 %3, i8 -86, i64 8, i1 false), !dbg !77
br label %SwitchEnd, !dbg !76
SwitchProng: ; preds = %Entry
%4 = getelementptr inbounds %U, %U* %u, i32 0, i32 0, !dbg !78
call void @llvm.dbg.declare(metadata %Foo* %4, metadata !71, metadata !DIExpression()), !dbg !78
%5 = getelementptr inbounds %Foo, %Foo* %4, i32 0, i32 1, !dbg !79
%6 = bitcast %Bar* %5 to i8*, !dbg !79
%7 = bitcast %Bar* %x to i8*, !dbg !79
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %7, i8* align 4 %6, i64 8, i1 false), !dbg !79
br label %SwitchEnd, !dbg !76
SwitchProng1: ; preds = %Entry
%8 = getelementptr inbounds %U, %U* %u, i32 0, i32 0, !dbg !81
%9 = bitcast %Foo* %8 to i32*, !dbg !81
call void @llvm.dbg.declare(metadata i32* %9, metadata !73, metadata !DIExpression()), !dbg !81
call fastcc void @bar2(%Bar* sret %x), !dbg !82
br label %SwitchEnd, !dbg !76
SwitchEnd: ; preds = %SwitchProng1, %SwitchProng, %SwitchElse
call void @llvm.dbg.declare(metadata %Bar* %x, metadata !74, metadata !DIExpression()), !dbg !84
ret void, !dbg !85
}
```
---
src/all_types.hpp | 1 +
src/ir.cpp | 36 ++++++++++++++++++++++++++++--------
2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 08d3f40d69d4..e7092b9e3f35 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2276,6 +2276,7 @@ struct IrInstructionSwitchBr {
IrInstructionSwitchBrCase *cases;
IrInstruction *is_comptime;
IrInstruction *switch_prongs_void;
+ IrInstruction *result_loc;
};
struct IrInstructionSwitchVar {
diff --git a/src/ir.cpp b/src/ir.cpp
index 0bc79bf0ecae..ce22701b52ae 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1693,9 +1693,10 @@ static IrInstruction *ir_build_pop_count(IrBuilder *irb, Scope *scope, AstNode *
return &instruction->base;
}
-static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value,
- IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime,
- IrInstruction *switch_prongs_void)
+static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *target_value, IrBasicBlock *else_block,
+ size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime,
+ IrInstruction *switch_prongs_void, IrInstruction *result_loc)
{
IrInstructionSwitchBr *instruction = ir_build_instruction(irb, scope, source_node);
instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
@@ -1706,11 +1707,13 @@ static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *
instruction->cases = cases;
instruction->is_comptime = is_comptime;
instruction->switch_prongs_void = switch_prongs_void;
+ instruction->result_loc = result_loc;
ir_ref_instruction(target_value, irb->current_basic_block);
if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block);
ir_ref_bb(else_block);
if (switch_prongs_void) ir_ref_instruction(switch_prongs_void, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
for (size_t i = 0; i < case_count; i += 1) {
ir_ref_instruction(cases[i].value, irb->current_basic_block);
@@ -6251,7 +6254,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
ir_build_br(irb, scope, node, else_block, is_comptime);
} else {
ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items,
- is_comptime, switch_prongs_void);
+ is_comptime, switch_prongs_void, result_loc);
}
if (!else_prong) {
@@ -7065,7 +7068,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
cases[1].value = ir_build_const_u8(irb, scope, node, 1);
cases[1].block = destroy_block;
ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block,
- 2, cases, const_bool_false, nullptr);
+ 2, cases, const_bool_false, nullptr, nullptr);
ir_set_cursor_at_end_and_append_block(irb, destroy_block);
ir_gen_cancel_target(irb, scope, node, target_inst, false, true);
@@ -7197,7 +7200,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
cases[1].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 1));
cases[1].block = canceled_block;
ir_mark_gen(ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
- 2, cases, const_bool_false, nullptr));
+ 2, cases, const_bool_false, nullptr, nullptr));
ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
IrBasicBlock **incoming_blocks = allocate(2);
@@ -7524,7 +7527,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
cases[0].block = invalid_resume_block;
cases[1].value = ir_build_const_u8(irb, scope, node, 1);
cases[1].block = irb->exec->coro_final_cleanup_block;
- ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr);
+ ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr, nullptr);
ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_suspend_block);
ir_build_coro_end(irb, scope, node);
@@ -16552,10 +16555,27 @@ static IrInstruction *ir_analyze_instruction_switch_br(IrAnalyze *ira,
new_case->block->ref_instruction = &switch_br_instruction->base;
}
+ // The switch target is not comptime known. This means we must mark the result location
+ // as runtime known, in case it is ConstPtrMutInfer.
+ if (switch_br_instruction->result_loc != nullptr) {
+ IrInstruction *result_loc = switch_br_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ir_unreach_error(ira);
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *result_ptr = ir_resolve_const(ira, result_loc, UndefBad);
+ if (result_ptr == nullptr)
+ return ir_unreach_error(ira);
+ assert(result_ptr->type->id == ZigTypeIdPointer);
+ if (result_ptr->data.x_ptr.mut == ConstPtrMutInfer) {
+ result_ptr->special = ConstValSpecialRuntime;
+ }
+ }
+ }
+
IrBasicBlock *new_else_block = ir_get_new_bb(ira, switch_br_instruction->else_block, &switch_br_instruction->base);
IrInstruction *result = ir_build_switch_br(&ira->new_irb,
switch_br_instruction->base.scope, switch_br_instruction->base.source_node,
- target_value, new_else_block, case_count, cases, nullptr, nullptr);
+ target_value, new_else_block, case_count, cases, nullptr, nullptr, nullptr);
result->value.type = ira->codegen->builtin_types.entry_unreachable;
return ir_finish_anal(ira, result);
}
From d5df75f13b09512370df311545d6c89cede22149 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 9 Nov 2018 15:29:21 -0500
Subject: [PATCH 041/190] copy elision: fix invalid "unused expression" error
---
src/codegen.cpp | 4 +++-
src/ir.cpp | 5 +++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 833882856a7b..5770aec0e3fa 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -6330,7 +6330,9 @@ static void do_code_gen(CodeGen *g) {
ZigType *ptr_type = instruction->base.value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *child_type = ptr_type->data.pointer.child_type;
- if (type_has_bits(child_type) && instruction->base.value.special == ConstValSpecialRuntime) {
+ if (type_has_bits(child_type) && instruction->base.value.special == ConstValSpecialRuntime &&
+ child_type != g->builtin_types.entry_infer)
+ {
instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
get_ptr_align(g, ptr_type));
}
diff --git a/src/ir.cpp b/src/ir.cpp
index ce22701b52ae..e0a9116225ab 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -7319,7 +7319,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_gen_if_optional_expr(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeSwitchExpr:
- return ir_gen_switch_expr(irb, scope, node, lval, result_loc);
+ return ir_gen_switch_expr(irb, scope, node, lval,
+ ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeCompTime:
return ir_gen_comptime(irb, scope, node, lval, result_loc);
case NodeTypeErrorType:
@@ -20390,7 +20391,7 @@ static IrInstruction *ir_analyze_instruction_check_statement_is_void(IrAnalyze *
if (type_is_invalid(statement_type))
return ira->codegen->invalid_instruction;
- if (statement_type->id != ZigTypeIdVoid) {
+ if (statement_type->id != ZigTypeIdVoid && statement_type != ira->codegen->builtin_types.entry_infer) {
ir_add_error(ira, &instruction->base, buf_sprintf("expression value is ignored"));
}
From a2eb0fe1a1ff6bdd10d5113b42e4bdefb0d214dc Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 9 Nov 2018 18:03:31 -0500
Subject: [PATCH 042/190] copy elision: catch with error union function call
```zig
export fn entry() void {
var x = ebar() catch |err| bar2();
}
```
```llvm
define void @entry() #2 !dbg !42 {
Entry:
%error_return_trace_addresses = alloca [30 x i64], align 8
%error_return_trace = alloca %StackTrace, align 8
%x = alloca %Bar, align 4
%err = alloca i16, align 2
%0 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 0
store i64 0, i64* %0, align 8
%1 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 1
%2 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 0
%3 = getelementptr inbounds [30 x i64], [30 x i64]* %error_return_trace_addresses, i64 0, i64 0
store i64* %3, i64** %2, align 8
%4 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 1
store i64 30, i64* %4, align 8
%5 = call fastcc i16 @ebar(%Bar* %x, %StackTrace* %error_return_trace), !dbg !54
store i16 %5, i16* %err, align 2, !dbg !54
%6 = load i16, i16* %err, align 2, !dbg !55
%7 = icmp ne i16 %6, 0, !dbg !55
br i1 %7, label %CatchError, label %CatchEnd, !dbg !55
CatchError: ; preds = %Entry
call void @llvm.dbg.declare(metadata i16* %err, metadata !46, metadata !DIExpression()), !dbg !55
call fastcc void @bar2(%Bar* sret %x), !dbg !56
br label %CatchEnd, !dbg !58
CatchEnd: ; preds = %CatchError, %Entry
call void @llvm.dbg.declare(metadata %Bar* %x, metadata !48, metadata !DIExpression()), !dbg !59
ret void, !dbg !60
}
```
---
src/analyze.cpp | 8 +++++++
src/codegen.cpp | 50 +++++++++++++++++++++++++++++++++++------
src/ir.cpp | 60 +++++++++++++++++++++++++++++++++++++++++--------
3 files changed, 102 insertions(+), 16 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 82e6a8831ffa..76bc58724acd 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1137,6 +1137,14 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
ZigType *gen_return_type;
if (is_async) {
gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
+ } else if (fn_type_id->return_type->id == ZigTypeIdErrorUnion) {
+ ZigType *payload_type = fn_type_id->return_type->data.error_union.payload_type;
+ if (type_has_bits(payload_type)) {
+ ZigType *gen_type = get_pointer_to_type(g, payload_type, false);
+ gen_param_types.append(gen_type->type_ref);
+ param_di_types.append(gen_type->di_type);
+ }
+ gen_return_type = g->builtin_types.entry_global_error_set;
} else if (!type_has_bits(fn_type_id->return_type)) {
gen_return_type = g->builtin_types.entry_void;
} else if (first_arg_return) {
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 5770aec0e3fa..9f7bb38ea0c4 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -460,6 +460,21 @@ static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkag
}
}
+static bool cc_want_sret_attr(CallingConvention cc) {
+ switch (cc) {
+ case CallingConventionNaked:
+ zig_unreachable();
+ case CallingConventionC:
+ case CallingConventionCold:
+ case CallingConventionStdcall:
+ return true;
+ case CallingConventionAsync:
+ case CallingConventionUnspecified:
+ return false;
+ }
+ zig_unreachable();
+}
+
static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
if (fn_table_entry->llvm_value)
return fn_table_entry->llvm_value;
@@ -597,10 +612,18 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
} else if (type_is_codegen_pointer(return_type)) {
addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
} else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
- addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
- if (cc == CallingConventionC) {
+ if (cc_want_sret_attr(cc)) {
+ addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias");
+ } else {
+ ZigType *ret_type = fn_type->data.fn.fn_type_id.return_type;
+ if (ret_type->id == ZigTypeIdErrorUnion) {
+ uint64_t sz = type_size(g, ret_type->data.error_union.payload_type);
+ addLLVMArgAttrInt(fn_table_entry->llvm_value, 0, "dereferenceable", sz);
+ } else {
+ addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
+ }
}
init_gen_i = 1;
}
@@ -2240,8 +2263,17 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
ZigType *return_type = return_instruction->value->value.type;
+ FnTypeId *fn_type_id = &g->cur_fn->type_entry->data.fn.fn_type_id;
- if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {
+ if (fn_type_id->return_type->id == ZigTypeIdErrorUnion) {
+ ConstExprValue *val = &return_instruction->value->value;
+ if (val->special == ConstValSpecialStatic) {
+ LLVMValueRef const_error_val = gen_const_val(g, val->data.x_err_union.error_set, "");
+ LLVMBuildRet(g->builder, const_error_val);
+ } else {
+ zig_panic("TODO");
+ }
+ } else if (want_first_arg_sret(g, fn_type_id)) {
// Assume that the result location mechanism populated the value,
// unless the value is a comptime const.
if (return_instruction->value->value.special == ConstValSpecialStatic) {
@@ -3466,7 +3498,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
- bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id);
+ bool is_error_union = src_return_type->id == ZigTypeIdErrorUnion;
+ bool first_arg_ret = (is_error_union && type_has_bits(src_return_type->data.error_union.payload_type)) ||
+ (ret_has_bits && want_first_arg_sret(g, fn_type_id));
bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
bool is_var_args = fn_type_id->is_var_args;
ZigList gen_param_values = {};
@@ -3537,8 +3571,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
} else if (!ret_has_bits) {
return nullptr;
} else if (first_arg_ret) {
- set_call_instr_sret(g, result);
- return result_ptr;
+ if (cc_want_sret_attr(cc) || src_return_type->id != ZigTypeIdErrorUnion) {
+ set_call_instr_sret(g, result);
+ }
+ return is_error_union ? result : result_ptr;
} else if (handle_is_ptr(src_return_type)) {
auto store_instr = LLVMBuildStore(g->builder, result, result_ptr);
LLVMSetAlignment(store_instr, LLVMGetAlignment(result_ptr));
@@ -3785,8 +3821,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
assert(maybe_type->id == ZigTypeIdOptional);
ZigType *child_type = maybe_type->data.maybe.child_type;
LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
- LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
+ LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
diff --git a/src/ir.cpp b/src/ir.cpp
index e0a9116225ab..adc02c692f6c 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3183,9 +3183,29 @@ static IrInstruction *ir_gen_result(IrBuilder *irb, Scope *scope, AstNode *node,
zig_unreachable();
}
+static IrInstruction *ir_gen_multi(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc, IrInstruction *value)
+{
+ switch (lval) {
+ case LValNone:
+ case LValPtr:
+ return ir_gen_result(irb, scope, node, lval, result_loc);
+ case LValErrorUnion:
+ case LValOptional: {
+ IrInstruction *err_alloca = ir_build_alloca_src(irb, scope, value->source_node,
+ nullptr, nullptr, "err");
+ ir_build_store_ptr(irb, scope, value->source_node, err_alloca, value);
+ return err_alloca;
+ }
+ }
+ zig_unreachable();
+}
+
static IrInstruction *ir_gen_value(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc, IrInstruction *value)
{
+ if (value == irb->codegen->invalid_instruction)
+ return value;
if (result_loc != nullptr) {
ir_build_store_ptr(irb, scope, node, result_loc, value);
if (lval != LValNone) {
@@ -3193,7 +3213,18 @@ static IrInstruction *ir_gen_value(IrBuilder *irb, Scope *scope, AstNode *node,
return ir_gen_result(irb, scope, node, lval, result_loc);
}
}
- return ir_lval_wrap(irb, scope, value, lval);
+ switch (lval) {
+ case LValPtr:
+ // We needed a pointer to a value, but we got a value. So we create
+ // an instruction which just makes a pointer of it.
+ return ir_build_ref(irb, scope, value->source_node, value, false, false);
+ case LValNone:
+ return value;
+ case LValOptional:
+ case LValErrorUnion:
+ zig_panic("TODO");
+ }
+ zig_unreachable();
}
static IrInstruction *ir_gen_ptr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
@@ -3208,7 +3239,7 @@ static IrInstruction *ir_gen_ptr(IrBuilder *irb, Scope *scope, AstNode *node, LV
case LValErrorUnion: {
// ptr points to an error union;
// result_loc points to the result payload
- // must return the error code
+ // must return pointer to the error code
IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, node, ptr, false);
ir_build_load_ptr(irb, scope, node, payload_ptr, result_loc);
return ir_build_error_union_field_error_set(irb, scope, node, ptr);
@@ -5042,7 +5073,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
// it turns out to be an implicit cast.
IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
FnInlineAuto, false, nullptr, nullptr, result_loc);
- return ir_lval_wrap(irb, scope, fn_call, lval);
+ return ir_gen_multi(irb, scope, node, lval, result_loc, fn_call);
}
for (size_t i = 0; i < arg_count; i += 1) {
@@ -5063,7 +5094,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto,
is_async, async_allocator, nullptr, result_loc);
- return ir_lval_wrap(irb, scope, fn_call, lval);
+ return ir_gen_multi(irb, scope, node, lval, result_loc, fn_call);
}
static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
@@ -5135,7 +5166,7 @@ static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *
return value;
// We needed a pointer to a value, but we got a value. So we create
- // an instruction which just makes a const pointer of it.
+ // an instruction which just makes a pointer of it.
return ir_build_ref(irb, scope, value->source_node, value, false, false);
}
@@ -7336,7 +7367,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeSliceExpr:
return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node, result_loc), lval);
case NodeTypeUnwrapErrorExpr:
- return ir_gen_catch(irb, scope, node, lval, result_loc);
+ return ir_gen_catch(irb, scope, node, lval,
+ ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeContainerDecl:
return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
case NodeTypeFnProto:
@@ -14177,6 +14209,16 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
IrInstruction *casted_result_loc = nullptr;
+ ZigType *scalar_result_type;
+ ZigType *payload_result_type;
+ if (return_type->id == ZigTypeIdErrorUnion) {
+ scalar_result_type = get_optional_type(ira->codegen, return_type->data.error_union.err_set_type);
+ payload_result_type = return_type->data.error_union.payload_type;
+ } else {
+ payload_result_type = return_type;
+ scalar_result_type = return_type;
+ }
+
if (call_instruction->result_loc != nullptr) {
IrInstruction *prev_result_loc = call_instruction->result_loc->child;
if (type_is_invalid(prev_result_loc->value.type))
@@ -14190,7 +14232,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
}
}
- casted_result_loc = ir_implicit_cast_result(ira, prev_result_loc, return_type, false);
+ casted_result_loc = ir_implicit_cast_result(ira, prev_result_loc, payload_result_type, false);
if (type_is_invalid(casted_result_loc->value.type))
return ira->codegen->invalid_instruction;
}
@@ -14199,9 +14241,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
call_instruction->base.scope, call_instruction->base.source_node,
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
casted_new_stack, casted_result_loc);
- new_call_instruction->value.type = return_type;
+ new_call_instruction->value.type = scalar_result_type;
- if (!handle_is_ptr(return_type) && casted_result_loc != nullptr) {
+ if (return_type == payload_result_type && !handle_is_ptr(return_type) && casted_result_loc != nullptr) {
ir_analyze_store_ptr(ira, &call_instruction->base, casted_result_loc, new_call_instruction);
}
From f5c765478a10143426580ee6c879294737c218de Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 10 Nov 2018 22:28:42 -0500
Subject: [PATCH 043/190] copy elision: implicit `*[N]T` to `[]T`
---
src/all_types.hpp | 10 +-
src/codegen.cpp | 17 ++++
src/ir.cpp | 232 +++++++++++++++++++++++++++++++++-------------
src/ir_print.cpp | 16 +++-
4 files changed, 210 insertions(+), 65 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index e7092b9e3f35..58cf08d6fd4b 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2194,6 +2194,7 @@ enum IrInstructionId {
IrInstructionIdResultOptionalPayload,
IrInstructionIdResultErrorUnionPayload,
IrInstructionIdResultErrorUnionCode,
+ IrInstructionIdResultSlicePtr,
IrInstructionIdResultReturn,
IrInstructionIdResultBytesToSlice,
IrInstructionIdResultSliceToBytes,
@@ -2448,6 +2449,7 @@ struct IrInstructionCall {
IrInstruction *async_allocator;
IrInstruction *new_stack;
IrInstruction *result_loc;
+ IrInstruction *first_arg_result_loc;
FnInline fn_inline;
bool is_async;
bool is_comptime;
@@ -3037,7 +3039,6 @@ struct IrInstructionDeclRef {
IrInstruction base;
Tld *tld;
- LVal lval;
};
struct IrInstructionPanic {
@@ -3339,6 +3340,13 @@ struct IrInstructionResultSliceToBytes {
IrInstruction *prev_result_loc;
};
+struct IrInstructionResultSlicePtr {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ uint64_t len;
+};
+
struct IrInstructionResultReturn {
IrInstruction base;
};
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 9f7bb38ea0c4..ad5c1fa6d133 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5098,6 +5098,21 @@ static LLVMValueRef ir_render_result_optional_payload(CodeGen *g, IrExecutable *
return LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_child_index, "");
}
+static LLVMValueRef ir_render_result_slice_ptr(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultSlicePtr *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ assert(instruction->prev_result_loc->value.type->id == ZigTypeIdPointer);
+ ZigType *slice_type = instruction->prev_result_loc->value.type->data.pointer.child_type;
+ assert(slice_type->id == ZigTypeIdStruct && slice_type->data.structure.is_slice);
+ size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
+ LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, (unsigned)len_field_index, "");
+ LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, instruction->len, false);
+ gen_store_untyped(g, len_val, len_field_ptr, 0, false);
+ size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
+ return LLVMBuildStructGEP(g->builder, prev_result_loc, (unsigned)ptr_field_index, "");
+}
+
static LLVMValueRef ir_render_result_error_union_payload(CodeGen *g, IrExecutable *executable,
IrInstructionResultErrorUnionPayload *instruction)
{
@@ -5379,6 +5394,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_result_return(g, executable, (IrInstructionResultReturn *)instruction);
case IrInstructionIdResultOptionalPayload:
return ir_render_result_optional_payload(g, executable, (IrInstructionResultOptionalPayload *)instruction);
+ case IrInstructionIdResultSlicePtr:
+ return ir_render_result_slice_ptr(g, executable, (IrInstructionResultSlicePtr *)instruction);
case IrInstructionIdResultErrorUnionPayload:
return ir_render_result_error_union_payload(g, executable, (IrInstructionResultErrorUnionPayload *)instruction);
case IrInstructionIdResultErrorUnionCode:
diff --git a/src/ir.cpp b/src/ir.cpp
index adc02c692f6c..56b91901f723 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -879,6 +879,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResultOptionalPa
return IrInstructionIdResultOptionalPayload;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultSlicePtr *) {
+ return IrInstructionIdResultSlicePtr;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionResultReturn *) {
return IrInstructionIdResultReturn;
}
@@ -1238,7 +1242,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast
static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
- IrInstruction *new_stack, IrInstruction *result_loc)
+ IrInstruction *new_stack, IrInstruction *result_loc, IrInstruction *first_arg_result_loc)
{
IrInstructionCall *call_instruction = ir_build_instruction(irb, scope, source_node);
call_instruction->fn_entry = fn_entry;
@@ -1251,6 +1255,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
call_instruction->async_allocator = async_allocator;
call_instruction->new_stack = new_stack;
call_instruction->result_loc = result_loc;
+ call_instruction->first_arg_result_loc = first_arg_result_loc;
if (fn_ref) ir_ref_instruction(fn_ref, irb->current_basic_block);
for (size_t i = 0; i < arg_count; i += 1)
@@ -1258,6 +1263,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block);
if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);
if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
+ if (first_arg_result_loc != nullptr) ir_ref_instruction(first_arg_result_loc, irb->current_basic_block);
return &call_instruction->base;
}
@@ -2359,13 +2365,10 @@ static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode *
return &instruction->base;
}
-static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node,
- Tld *tld, LVal lval)
-{
+static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, Tld *tld) {
IrInstructionDeclRef *instruction = ir_build_instruction(
irb, scope, source_node);
instruction->tld = tld;
- instruction->lval = lval;
return &instruction->base;
}
@@ -2820,6 +2823,18 @@ static IrInstruction *ir_build_result_optional_payload(IrBuilder *irb, Scope *sc
return &instruction->base;
}
+static IrInstruction *ir_build_result_slice_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, uint64_t len)
+{
+ IrInstructionResultSlicePtr *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->len = len;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_result_error_union_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *prev_result_loc)
{
@@ -3232,7 +3247,9 @@ static IrInstruction *ir_gen_ptr(IrBuilder *irb, Scope *scope, AstNode *node, LV
{
switch (lval) {
case LValPtr:
- assert(result_loc == nullptr);
+ if (result_loc != nullptr) {
+ ir_build_store_ptr(irb, scope, node, result_loc, ptr);
+ }
return ptr;
case LValNone:
return ir_build_load_ptr(irb, scope, node, ptr, result_loc);
@@ -3863,8 +3880,22 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
}
Tld *tld = find_decl(irb->codegen, scope, variable_name);
- if (tld)
- return ir_build_decl_ref(irb, scope, node, tld, lval);
+ if (tld) {
+ switch (tld->id) {
+ case TldIdContainer:
+ case TldIdCompTime:
+ zig_unreachable();
+ case TldIdVar: {
+ IrInstruction *var_ptr = ir_build_decl_ref(irb, scope, node, tld);
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, var_ptr);
+ }
+ case TldIdFn: {
+ IrInstruction *fn_inst = ir_build_decl_ref(irb, scope, node, tld);
+ return ir_gen_value(irb, scope, node, lval, result_loc, fn_inst);
+ }
+ }
+ zig_unreachable();
+ }
if (node->owner->any_imports_failed) {
// skip the error message since we had a failing import in this file
@@ -4803,7 +4834,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
- fn_inline, false, nullptr, nullptr, result_loc);
+ fn_inline, false, nullptr, nullptr, result_loc, nullptr);
return ir_lval_wrap(irb, scope, call, lval);
}
case BuiltinFnIdNewStackCall:
@@ -4835,7 +4866,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args,
- false, FnInlineAuto, false, nullptr, new_stack, result_loc);
+ false, FnInlineAuto, false, nullptr, new_stack, result_loc, nullptr);
return ir_lval_wrap(irb, scope, call, lval);
}
case BuiltinFnIdTypeId:
@@ -5072,7 +5103,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
// In the analysis, this call instruction will be a simple LoadPtr instruction if
// it turns out to be an implicit cast.
IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
- FnInlineAuto, false, nullptr, nullptr, result_loc);
+ FnInlineAuto, false, nullptr, nullptr, result_loc, arg_result_loc);
return ir_gen_multi(irb, scope, node, lval, result_loc, fn_call);
}
@@ -5093,7 +5124,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
}
IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto,
- is_async, async_allocator, nullptr, result_loc);
+ is_async, async_allocator, nullptr, result_loc, nullptr);
return ir_gen_multi(irb, scope, node, lval, result_loc, fn_call);
}
@@ -5250,7 +5281,9 @@ static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_bool_not(irb, scope, node, value);
}
-static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypePrefixOpExpr);
PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op;
@@ -5270,7 +5303,10 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval);
case PrefixOpAddrOf: {
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
- return ir_lval_wrap(irb, scope, ir_gen_node(irb, expr_node, scope, LValPtr, nullptr), lval);
+ IrInstruction *inst = ir_gen_node(irb, expr_node, scope, LValPtr, result_loc);
+ if (inst == irb->codegen->invalid_instruction)
+ return inst;
+ return ir_gen_result(irb, scope, expr_node, lval, result_loc);
}
}
zig_unreachable();
@@ -7289,7 +7325,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_gen_if_bool_expr(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
case NodeTypePrefixOpExpr:
- return ir_gen_prefix_op_expr(irb, scope, node, lval);
+ return ir_gen_prefix_op_expr(irb, scope, node, lval, result_loc);
case NodeTypeContainerInitExpr:
return ir_gen_container_init_expr(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
@@ -7641,7 +7677,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
args[0] = implicit_allocator_ptr; // self
args[1] = mem_slice; // old_mem
ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false,
- nullptr, nullptr, nullptr);
+ nullptr, nullptr, nullptr, nullptr);
IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false, nullptr);
@@ -9983,6 +10019,74 @@ static IrInstruction *ir_analyze_result_optional_payload(IrAnalyze *ira, IrInstr
return result;
}
+static IrInstruction *ir_analyze_result_slice_ptr(IrAnalyze *ira, IrInstruction *result_loc,
+ ZigType *ptr_to_array_type, uint64_t len)
+{
+ ZigType *slice_type = result_loc->value.type->data.pointer.child_type;
+ assert(is_slice(slice_type));
+ ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry;
+ assert(slice_ptr_type->id == ZigTypeIdPointer);
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, slice_ptr_type,
+ false, result_loc->value.type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (ptr_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
+ ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *slice_val = const_ptr_pointee(ira->codegen, ptr_val);
+ assert(is_slice(slice_val->type));
+ if (slice_val->special == ConstValSpecialUndef) {
+ slice_val->data.x_struct.fields = create_const_vals(2);
+ ConstExprValue *slice_ptr_val = &slice_val->data.x_struct.fields[slice_ptr_index];
+ ConstExprValue *slice_len_val = &slice_val->data.x_struct.fields[slice_len_index];
+
+ slice_ptr_val->type = slice_ptr_type;
+ slice_ptr_val->special = ConstValSpecialUndef;
+ ConstParent *slice_ptr_parent = get_const_val_parent(ira->codegen, slice_ptr_val);
+ if (slice_ptr_parent != nullptr) {
+ slice_ptr_parent->id = ConstParentIdStruct;
+ slice_ptr_parent->data.p_struct.struct_val = slice_val;
+ slice_ptr_parent->data.p_struct.field_index = slice_ptr_index;
+ }
+
+ slice_len_val->type = ira->codegen->builtin_types.entry_usize;
+ slice_len_val->special = ConstValSpecialStatic;
+ bigint_init_unsigned(&slice_len_val->data.x_bigint, len);
+ ConstParent *slice_len_parent = get_const_val_parent(ira->codegen, slice_len_val);
+ if (slice_len_parent != nullptr) {
+ slice_len_parent->id = ConstParentIdStruct;
+ slice_len_parent->data.p_struct.struct_val = slice_val;
+ slice_len_parent->data.p_struct.field_index = slice_len_index;
+ }
+ slice_val->special = ConstValSpecialStatic;
+ }
+ assert(slice_val->data.x_struct.fields != nullptr);
+
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_result_slice_ptr(&ira->new_irb, result_loc->scope, result_loc->source_node,
+ result_loc, len);
+ result->value.type = new_ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, result_loc, new_ptr_type);
+ }
+ ConstExprValue *result_val = &result->value;
+ result_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
+ result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ result_val->data.x_ptr.data.base_struct.struct_val = slice_val;
+ result_val->data.x_ptr.data.base_struct.field_index = slice_ptr_index;
+ return result;
+ }
+ }
+ IrInstruction *result = ir_build_result_slice_ptr(&ira->new_irb, result_loc->scope, result_loc->source_node,
+ result_loc, len);
+ result->value.type = new_ptr_type;
+ return result;
+}
+
static void init_if_undef_err_union(IrAnalyze *ira, ConstExprValue *error_union_val) {
if (error_union_val->special != ConstValSpecialUndef)
return;
@@ -10954,25 +11058,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
}
- // cast from *const [N]T to []const T
- if (is_slice(wanted_type) &&
- actual_type->id == ZigTypeIdPointer &&
- actual_type->data.pointer.is_const &&
- actual_type->data.pointer.child_type->id == ZigTypeIdArray)
- {
- ZigType *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
- assert(ptr_type->id == ZigTypeIdPointer);
-
- ZigType *array_type = actual_type->data.pointer.child_type;
-
- if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
- types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type,
- source_node, false).id == ConstCastResultIdOk)
- {
- return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
- }
- }
-
// cast from [N]T to ?[]const T
if (wanted_type->id == ZigTypeIdOptional &&
is_slice(wanted_type->data.maybe.child_type) &&
@@ -11405,6 +11490,25 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
return ir_analyze_ptr_cast(ira, result_loc, result_loc, new_ptr_type, result_loc);
}
+ // cast from *[N]T to []T
+ if (is_slice(have_child_type) &&
+ needed_child_type->id == ZigTypeIdPointer &&
+ needed_child_type->data.pointer.ptr_len == PtrLenSingle &&
+ needed_child_type->data.pointer.child_type->id == ZigTypeIdArray)
+ {
+ ZigType *slice_ptr_type = have_child_type->data.structure.fields[slice_ptr_index].type_entry;
+ assert(slice_ptr_type->id == ZigTypeIdPointer);
+ ZigType *array_type = needed_child_type->data.pointer.child_type;
+ bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0
+ || !needed_child_type->data.pointer.is_const);
+ if (const_ok && types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
+ array_type->data.array.child_type, source_node,
+ !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk)
+ {
+ return ir_analyze_result_slice_ptr(ira, result_loc, needed_child_type, array_type->data.array.len);
+ }
+ }
+
// cast from T to ?T
if (have_child_type->id == ZigTypeIdOptional) {
if (types_match_const_cast_only(ira, have_child_type->data.maybe.child_type, needed_child_type, source_node,
@@ -13391,7 +13495,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c
IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope,
call_instruction->base.source_node, fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true,
- async_allocator_inst, nullptr, nullptr);
+ async_allocator_inst, nullptr, nullptr, nullptr);
result->value.type = async_return_type;
return result;
}
@@ -13646,6 +13750,9 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
}
if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) {
ptr->value.special = ConstValSpecialRuntime;
+ if (instr_is_comptime(uncasted_ptr) && uncasted_ptr->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ uncasted_ptr->value.special = ConstValSpecialRuntime;
+ }
} else {
ir_add_error(ira, source_instr,
buf_sprintf("cannot store runtime value in compile time variable"));
@@ -14111,7 +14218,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
call_instruction->base.scope, call_instruction->base.source_node,
impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
- call_instruction->is_async, nullptr, casted_new_stack, nullptr);
+ call_instruction->is_async, nullptr, casted_new_stack, nullptr, nullptr);
new_call_instruction->value.type = return_type;
@@ -14240,7 +14347,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
call_instruction->base.scope, call_instruction->base.source_node,
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
- casted_new_stack, casted_result_loc);
+ casted_new_stack, casted_result_loc, nullptr);
new_call_instruction->value.type = scalar_result_type;
if (return_type == payload_result_type && !handle_is_ptr(return_type) && casted_result_loc != nullptr) {
@@ -14273,14 +14380,30 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC
return ira->codegen->invalid_instruction;
}
- // This is handled with the result location mechanism. So all we need to do here is
- // a LoadPtr on the result location.
IrInstruction *result_loc = call_instruction->result_loc->child;
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
if ((err = resolve_possible_alloca_inference(ira, result_loc, dest_type)))
return ira->codegen->invalid_instruction;
+ if (is_slice(dest_type)) {
+ IrInstruction *first_arg_result_loc = call_instruction->first_arg_result_loc->child;
+ if (type_is_invalid(first_arg_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ // If this is a slice cast, this is the equivalent of a container init fields instruction.
+ // Deal with ConstPtrMutInfer.
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(first_arg_result_loc)) {
+ result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ result_loc->value.special = ConstValSpecialRuntime;
+ }
+ }
+ return ir_const_void(ira, &call_instruction->base);
+ }
+
+ // This is handled with the result location mechanism. So all we need to do here is
+ // a LoadPtr on the result location.
IrInstruction *deref = ir_get_deref(ira, &call_instruction->base, result_loc);
if (type_is_invalid(deref->value.type))
return ira->codegen->invalid_instruction;
@@ -20910,9 +21033,8 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
IrInstructionDeclRef *instruction)
{
Tld *tld = instruction->tld;
- LVal lval = instruction->lval;
- resolve_top_level_decl(ira->codegen, tld, lval == LValPtr, instruction->base.source_node);
+ resolve_top_level_decl(ira->codegen, tld, true, instruction->base.source_node);
if (tld->resolution == TldResolutionInvalid)
return ira->codegen->invalid_instruction;
@@ -20920,27 +21042,17 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
case TldIdContainer:
case TldIdCompTime:
zig_unreachable();
- case TldIdVar:
- {
+ case TldIdVar: {
TldVar *tld_var = (TldVar *)tld;
ZigVar *var = tld_var->var;
- IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var);
- if (type_is_invalid(var_ptr->value.type))
- return ira->codegen->invalid_instruction;
-
if (tld_var->extern_lib_name != nullptr) {
add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, instruction->base.source_node);
}
- if (lval == LValPtr) {
- return var_ptr;
- } else {
- return ir_get_deref(ira, &instruction->base, var_ptr);
- }
+ return ir_get_var_ptr(ira, &instruction->base, var);
}
- case TldIdFn:
- {
+ case TldIdFn: {
TldFn *tld_fn = (TldFn *)tld;
ZigFn *fn_entry = tld_fn->fn_entry;
assert(fn_entry->type_entry);
@@ -20949,13 +21061,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, instruction->base.source_node);
}
- IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, fn_entry);
- if (lval == LValPtr) {
- return ir_get_ref(ira, &instruction->base, ref_instruction, true, false);
- } else {
- return ref_instruction;
- }
+ return ir_create_const_fn(&ira->new_irb, instruction->base.scope, instruction->base.source_node, fn_entry);
}
}
zig_unreachable();
@@ -21852,6 +21958,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdDeclVarGen:
case IrInstructionIdAllocaGen:
case IrInstructionIdResultOptionalPayload:
+ case IrInstructionIdResultSlicePtr:
case IrInstructionIdResultErrorUnionPayload:
case IrInstructionIdResultErrorUnionCode:
zig_unreachable();
@@ -22361,6 +22468,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdBoolToInt:
case IrInstructionIdEnumToInt:
case IrInstructionIdResultOptionalPayload:
+ case IrInstructionIdResultSlicePtr:
case IrInstructionIdResultErrorUnionPayload:
case IrInstructionIdResultErrorUnionCode:
case IrInstructionIdResultReturn:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 7c157272e235..fb4113ad974d 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -227,6 +227,10 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
}
fprintf(irp->f, ") result=");
ir_print_other_instruction(irp, call_instruction->result_loc);
+ if (call_instruction->first_arg_result_loc != nullptr) {
+ fprintf(irp->f, ", first_arg_result=");
+ ir_print_other_instruction(irp, call_instruction->first_arg_result_loc);
+ }
}
static void ir_print_cond_br(IrPrint *irp, IrInstructionCondBr *cond_br_instruction) {
@@ -981,8 +985,7 @@ static void ir_print_ptr_type(IrPrint *irp, IrInstructionPtrType *instruction) {
}
static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) {
- const char *ptr_str = (instruction->lval == LValPtr) ? "ptr " : "";
- fprintf(irp->f, "declref %s%s", ptr_str, buf_ptr(instruction->tld->name));
+ fprintf(irp->f, "declref %s", buf_ptr(instruction->tld->name));
}
static void ir_print_panic(IrPrint *irp, IrInstructionPanic *instruction) {
@@ -1312,6 +1315,12 @@ static void ir_print_result_optional_payload(IrPrint *irp, IrInstructionResultOp
fprintf(irp->f, ")");
}
+static void ir_print_result_slice_ptr(IrPrint *irp, IrInstructionResultSlicePtr *instruction) {
+ fprintf(irp->f, "ResultSlicePtr(");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",len=%" ZIG_PRI_u64 ")", instruction->len);
+}
+
static void ir_print_result_error_union_payload(IrPrint *irp, IrInstructionResultErrorUnionPayload *instruction) {
fprintf(irp->f, "ResultErrorUnionPayload(");
ir_print_other_instruction(irp, instruction->prev_result_loc);
@@ -1821,6 +1830,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdResultOptionalPayload:
ir_print_result_optional_payload(irp, (IrInstructionResultOptionalPayload *)instruction);
break;
+ case IrInstructionIdResultSlicePtr:
+ ir_print_result_slice_ptr(irp, (IrInstructionResultSlicePtr *)instruction);
+ break;
case IrInstructionIdResultErrorUnionPayload:
ir_print_result_error_union_payload(irp, (IrInstructionResultErrorUnionPayload *)instruction);
break;
From aa1b99d58c9292db8c1d2866bcf7e7638c98ac22 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 14 Nov 2018 21:26:31 -0500
Subject: [PATCH 044/190] copy elision: multiple implicit cast of scalar
```zig
export fn entry() void {
var x = i32(u16(nine()));
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca i32, align 4
%0 = call fastcc i8 @nine(), !dbg !48
%1 = zext i8 %0 to i16, !dbg !48
%2 = zext i16 %1 to i32, !dbg !48
store i32 %2, i32* %x, align 4, !dbg !49
call void @llvm.dbg.declare(metadata i32* %x, metadata !45, metadata !DIExpression()), !dbg !50
ret void, !dbg !51
}
```
---
src/ir.cpp | 103 +++++++++++++++++++++++++++++++----------------
src/ir_print.cpp | 2 +-
2 files changed, 70 insertions(+), 35 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index e381eee4fc92..067eaaaca6d5 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3203,8 +3203,9 @@ static IrInstruction *ir_gen_multi(IrBuilder *irb, Scope *scope, AstNode *node,
{
switch (lval) {
case LValNone:
+ return value;
case LValPtr:
- return ir_gen_result(irb, scope, node, lval, result_loc);
+ return result_loc;
case LValErrorUnion:
case LValOptional: {
IrInstruction *err_alloca = ir_build_alloca_src(irb, scope, value->source_node,
@@ -11553,6 +11554,8 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
{
IrInstruction *cast1 = ir_implicit_cast_result(ira, result_loc,
have_child_type->data.error_union.payload_type, allow_failure);
+ if (cast1 == nullptr)
+ return nullptr;
if (type_is_invalid(cast1->value.type))
return ira->codegen->invalid_instruction;
@@ -11566,7 +11569,7 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *res
}
if (allow_failure) {
- return result_loc;
+ return nullptr;
}
ErrorMsg *parent_msg = ir_add_error_node(ira, source_node,
@@ -13722,6 +13725,8 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
}
IrInstruction *ptr = ir_implicit_cast_result(ira, uncasted_ptr, uncasted_value->value.type, true);
+ if (ptr == nullptr)
+ ptr = uncasted_ptr;
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
@@ -14331,7 +14336,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
scalar_result_type = return_type;
}
- if (call_instruction->result_loc != nullptr) {
+ bool need_store_ptr = (return_type == payload_result_type) && !handle_is_ptr(return_type) &&
+ call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr;
+
+ if (call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr) {
IrInstruction *prev_result_loc = call_instruction->result_loc->child;
if (type_is_invalid(prev_result_loc->value.type))
return ira->codegen->invalid_instruction;
@@ -14344,7 +14352,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
}
}
- casted_result_loc = ir_implicit_cast_result(ira, prev_result_loc, payload_result_type, false);
+ casted_result_loc = ir_implicit_cast_result(ira, prev_result_loc, payload_result_type, need_store_ptr);
+ if (casted_result_loc == nullptr)
+ casted_result_loc = prev_result_loc;
if (type_is_invalid(casted_result_loc->value.type))
return ira->codegen->invalid_instruction;
}
@@ -14355,7 +14365,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
casted_new_stack, casted_result_loc, nullptr);
new_call_instruction->value.type = scalar_result_type;
- if (return_type == payload_result_type && !handle_is_ptr(return_type) && casted_result_loc != nullptr) {
+ if (need_store_ptr) {
ir_analyze_store_ptr(ira, &call_instruction->base, casted_result_loc, new_call_instruction);
}
@@ -14385,34 +14395,53 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC
return ira->codegen->invalid_instruction;
}
- IrInstruction *result_loc = call_instruction->result_loc->child;
- if (type_is_invalid(result_loc->value.type))
- return ira->codegen->invalid_instruction;
- if ((err = resolve_possible_alloca_inference(ira, result_loc, dest_type)))
- return ira->codegen->invalid_instruction;
-
- if (is_slice(dest_type)) {
- IrInstruction *first_arg_result_loc = call_instruction->first_arg_result_loc->child;
- if (type_is_invalid(first_arg_result_loc->value.type))
+ IrInstruction *first_arg_result_loc = call_instruction->first_arg_result_loc->child;
+ if (first_arg_result_loc != nullptr) {
+ IrInstruction *result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
- // If this is a slice cast, this is the equivalent of a container init fields instruction.
- // Deal with ConstPtrMutInfer.
- if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
- if (instr_is_comptime(first_arg_result_loc)) {
- result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
- } else {
- result_loc->value.special = ConstValSpecialRuntime;
+ if ((err = resolve_possible_alloca_inference(ira, result_loc, dest_type)))
+ return ira->codegen->invalid_instruction;
+
+ if (is_slice(dest_type)) {
+ if (type_is_invalid(first_arg_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ // If this is a slice cast, this is the equivalent of a container init fields instruction.
+ // Deal with ConstPtrMutInfer.
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(first_arg_result_loc)) {
+ result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ result_loc->value.special = ConstValSpecialRuntime;
+ }
}
+ return ir_const_void(ira, &call_instruction->base);
}
- return ir_const_void(ira, &call_instruction->base);
+
+ // This is handled with the result location mechanism. So all we need to do here is
+ // a LoadPtr on the result location.
+ IrInstruction *deref = ir_get_deref(ira, &call_instruction->base, result_loc);
+ if (type_is_invalid(deref->value.type))
+ return ira->codegen->invalid_instruction;
+ return ir_finish_anal(ira, deref);
}
+ IrInstruction *arg_value = call_instruction->args[0]->child;
+ if (type_is_invalid(arg_value->value.type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *result = ir_implicit_cast(ira, arg_value, dest_type);
- // This is handled with the result location mechanism. So all we need to do here is
- // a LoadPtr on the result location.
- IrInstruction *deref = ir_get_deref(ira, &call_instruction->base, result_loc);
- if (type_is_invalid(deref->value.type))
+ if (call_instruction->result_loc == nullptr || call_instruction->result_loc->child == nullptr) {
+ return ir_finish_anal(ira, result);
+ }
+
+ // we must store into the result loc
+ IrInstruction *result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if ((err = resolve_possible_alloca_inference(ira, result_loc, dest_type)))
return ira->codegen->invalid_instruction;
- return ir_finish_anal(ira, deref);
+ ir_analyze_store_ptr(ira, &call_instruction->base, result_loc, result);
+ return result;
} else if (fn_ref->value.type->id == ZigTypeIdFn) {
ZigFn *fn_table_entry = ir_resolve_fn(ira, fn_ref);
if (fn_table_entry == nullptr)
@@ -21909,6 +21938,10 @@ static IrInstruction *ir_analyze_instruction_first_arg_result_loc(IrAnalyze *ira
if (type_is_invalid(dest_type))
return ira->codegen->invalid_instruction;
+ if (!handle_is_ptr(dest_type)) {
+ return nullptr;
+ }
+
IrInstruction *new_result_loc = ir_implicit_cast_result(ira, instruction->prev_result_loc->child,
dest_type, false);
if (type_is_invalid(new_result_loc->value.type))
@@ -22258,7 +22291,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *old_instruction) {
IrInstruction *new_instruction = ir_analyze_instruction_nocast(ira, old_instruction);
- assert(new_instruction->value.type != nullptr);
+ assert(new_instruction == nullptr || new_instruction->value.type != nullptr);
old_instruction->child = new_instruction;
return new_instruction;
}
@@ -22308,13 +22341,15 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
}
IrInstruction *new_instruction = ir_analyze_instruction(ira, old_instruction);
- if (type_is_invalid(new_instruction->value.type) && ir_should_inline(new_exec, old_instruction->scope)) {
- return ira->codegen->builtin_types.entry_invalid;
- }
+ if (new_instruction != nullptr) {
+ if (type_is_invalid(new_instruction->value.type) && ir_should_inline(new_exec, old_instruction->scope)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
- // unreachable instructions do their own control flow.
- if (new_instruction->value.type->id == ZigTypeIdUnreachable)
- continue;
+ // unreachable instructions do their own control flow.
+ if (new_instruction->value.type->id == ZigTypeIdUnreachable)
+ continue;
+ }
ira->instruction_index += 1;
}
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index fb4113ad974d..9e01ec537701 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -881,7 +881,7 @@ static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
}
static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
- fprintf(irp->f, "@widenOrShorten(");
+ fprintf(irp->f, "WidenOrShorten(");
ir_print_other_instruction(irp, instruction->target);
fprintf(irp->f, ")");
}
From 80fb0f662eff5eed0e77d7884ea5f4772301b008 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 15 Nov 2018 13:57:53 -0500
Subject: [PATCH 045/190] copy elision: fix a couple regressions
---
src/ir.cpp | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 067eaaaca6d5..1079b69b3754 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5100,7 +5100,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
size_t arg_count = node->data.fn_call_expr.params.length;
IrInstruction **args = allocate(arg_count);
bool is_async = node->data.fn_call_expr.is_async;
- if (arg_count == 1 && !is_async) {
+ if (arg_count == 1 && !is_async && result_loc != nullptr) {
AstNode *arg_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg_result_loc = ir_build_first_arg_result_loc(irb, scope, arg_node, result_loc, fn_ref);
args[0] = ir_gen_node(irb, arg_node, scope, LValNone, arg_result_loc);
@@ -14395,7 +14395,8 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC
return ira->codegen->invalid_instruction;
}
- IrInstruction *first_arg_result_loc = call_instruction->first_arg_result_loc->child;
+ IrInstruction *first_arg_result_loc = (call_instruction->first_arg_result_loc == nullptr) ?
+ nullptr : call_instruction->first_arg_result_loc->child;
if (first_arg_result_loc != nullptr) {
IrInstruction *result_loc = call_instruction->result_loc->child;
if (type_is_invalid(result_loc->value.type))
@@ -15938,6 +15939,8 @@ static IrInstruction *ir_analyze_instruction_load_result(IrAnalyze *ira, IrInstr
static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) {
IrInstruction *ptr = instruction->ptr->child;
+ if (ptr == nullptr)
+ return ir_const_void(ira, &instruction->base);
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
From 99a2e8b88fe83532e93080106d247c323db47f1f Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 15 Nov 2018 15:11:00 -0500
Subject: [PATCH 046/190] copy elision: null result loc for addr-of
```zig
export fn entry() void {
if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
abort();
}
}
```
```llvm
define void @entry() #2 !dbg !62 {
Entry:
%0 = atomicrmw xchg i8* @panicking, i8 1 seq_cst, !dbg !66
%1 = icmp eq i8 %0, 1, !dbg !68
br i1 %1, label %Then, label %Else, !dbg !68
Then: ; preds = %Entry
call void @abort(), !dbg !69
unreachable, !dbg !69
Else: ; preds = %Entry
br label %EndIf, !dbg !71
EndIf: ; preds = %Else
ret void, !dbg !72
}
```
---
src/ir.cpp | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 1079b69b3754..72983b7cc99f 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5287,6 +5287,12 @@ static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_bool_not(irb, scope, node, value);
}
+static IrInstruction *ensure_result_loc(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
+ if (result_loc)
+ return result_loc;
+ return ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
+}
+
static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc)
{
@@ -5309,10 +5315,11 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval);
case PrefixOpAddrOf: {
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
- IrInstruction *inst = ir_gen_node(irb, expr_node, scope, LValPtr, result_loc);
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, expr_node, result_loc);
+ IrInstruction *inst = ir_gen_node(irb, expr_node, scope, LValPtr, ensured_result_loc);
if (inst == irb->codegen->invalid_instruction)
return inst;
- return ir_gen_result(irb, scope, expr_node, lval, result_loc);
+ return ir_gen_result(irb, scope, expr_node, lval, ensured_result_loc);
}
}
zig_unreachable();
@@ -7291,12 +7298,6 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
}
-static IrInstruction *ensure_result_loc(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
- if (result_loc)
- return result_loc;
- return ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
-}
-
static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
IrInstruction *result_loc)
{
From b81abfa559c982244e426e1a6ffbf3d346e588a8 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 16 Nov 2018 11:30:08 -0500
Subject: [PATCH 047/190] copy elision: fix comptime fn call regression
```zig
export fn entry() void {
const T = Type();
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
ret void, !dbg !45
}
```
---
src/ir.cpp | 41 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 39 insertions(+), 2 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index f6deb143d4f7..0420421d9cc8 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3284,7 +3284,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
IrInstruction *return_value;
if (expr_node) {
IrInstruction *return_result_loc = nullptr;
- if (handle_is_ptr(fn_entry->type_entry->data.fn.fn_type_id.return_type)) {
+ ZigType *return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
+ if (type_has_bits(return_type) && handle_is_ptr(return_type)) {
return_result_loc = ir_build_result_return(irb, scope, node);
}
// Temporarily set this so that if we return a type it gets the name of the function
@@ -13949,10 +13950,46 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
return ira->codegen->invalid_instruction;
}
+ ZigType *scalar_result_type;
+ ZigType *payload_result_type;
+ if (return_type->id == ZigTypeIdErrorUnion) {
+ scalar_result_type = get_optional_type(ira->codegen, return_type->data.error_union.err_set_type);
+ payload_result_type = return_type->data.error_union.payload_type;
+ } else {
+ payload_result_type = return_type;
+ scalar_result_type = return_type;
+ }
+
IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->value.type);
// TODO should we use copy_const_val?
new_instruction->value = result->value;
- new_instruction->value.type = return_type;
+ new_instruction->value.type = scalar_result_type;
+
+ if (call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr) {
+ IrInstruction *prev_result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if (instr_is_comptime(prev_result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, prev_result_loc, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr_val->special = ConstValSpecialStatic;
+ }
+ }
+
+ bool need_store_ptr = (return_type == payload_result_type) &&
+ (!type_has_bits(return_type) || !handle_is_ptr(return_type));
+ IrInstruction *casted_result_loc = ir_implicit_cast_result(ira, prev_result_loc, payload_result_type, need_store_ptr);
+ if (casted_result_loc == nullptr)
+ casted_result_loc = prev_result_loc;
+ if (type_is_invalid(casted_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if (need_store_ptr) {
+ ir_analyze_store_ptr(ira, &call_instruction->base, casted_result_loc, new_instruction);
+ }
+ }
+
return ir_finish_anal(ira, new_instruction);
}
From 5f206368fcbc629fa497bd4bcb43c1ba4987ed71 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 16 Nov 2018 14:57:00 -0500
Subject: [PATCH 048/190] copy elision: fix regression: function call with 1
arg
```zig
export fn entry() void {
_ = raise(1);
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%0 = call fastcc i64 @raise(i32 1), !dbg !45
ret void, !dbg !47
}
```
---
src/ir.cpp | 10 +++++++++-
test.zig | 1 -
2 files changed, 9 insertions(+), 2 deletions(-)
delete mode 100644 test.zig
diff --git a/src/ir.cpp b/src/ir.cpp
index 0420421d9cc8..8061cd382137 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3285,7 +3285,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
if (expr_node) {
IrInstruction *return_result_loc = nullptr;
ZigType *return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
- if (type_has_bits(return_type) && handle_is_ptr(return_type)) {
+ if (return_type != nullptr && type_has_bits(return_type) && handle_is_ptr(return_type)) {
return_result_loc = ir_build_result_return(irb, scope, node);
}
// Temporarily set this so that if we return a type it gets the name of the function
@@ -11397,6 +11397,7 @@ static Error resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *al
Error err;
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
return err;
+ assert(alloca->base.value.data.x_ptr.special != ConstPtrSpecialInvalid);
alloca->base.value.data.x_ptr.data.ref.pointee->type = child_type;
alloca->base.value.type = get_pointer_to_type_extra(ira->codegen, child_type, false, false,
PtrLenSingle, alloca->align, 0, 0);
@@ -21948,8 +21949,15 @@ static IrInstruction *ir_analyze_instruction_first_arg_result_loc(IrAnalyze *ira
// Result of this instruction should be the result location for the first argument of the function call.
// This means it should be a stack allocation.
+ ConstExprValue *pointee = create_const_vals(1);
+ pointee->special = ConstValSpecialUndef;
+
IrInstructionAllocaGen *result = ir_create_alloca_gen(&ira->new_irb, instruction->base.scope,
instruction->base.source_node, 0, "");
+ result->base.value.special = ConstValSpecialStatic;
+ result->base.value.data.x_ptr.special = ConstPtrSpecialRef;
+ result->base.value.data.x_ptr.mut = ConstPtrMutInfer;
+ result->base.value.data.x_ptr.data.ref.pointee = pointee;
assert(fn_ref->value.type->id == ZigTypeIdFn);
ZigType *param_type = fn_ref->value.type->data.fn.fn_type_id.param_info[0].type;
diff --git a/test.zig b/test.zig
deleted file mode 100644
index 566bb24d16bc..000000000000
--- a/test.zig
+++ /dev/null
@@ -1 +0,0 @@
-const a = [][]const u8{};
From c30908dbaccb6c2613989b63160b539247e454eb Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 16 Nov 2018 16:57:12 -0500
Subject: [PATCH 049/190] copy elision: slice syntax with no result loc
```zig
export fn entry() void {
const fmt: []const u8 = "oaeu";
var i: usize = 1;
slice(fmt[0..i]);
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%i = alloca i64, align 8
%0 = alloca %"[]u8", align 8
call void @llvm.dbg.declare(metadata %"[]u8"* @3, metadata !45, metadata !DIExpression()), !dbg !49
store i64 1, i64* %i, align 8, !dbg !50
call void @llvm.dbg.declare(metadata i64* %i, metadata !47, metadata !DIExpression()), !dbg !50
%1 = load i64, i64* %i, align 8, !dbg !51
%2 = load i64, i64* getelementptr inbounds (%"[]u8", %"[]u8"* @3, i32 0, i32 1), align 8, !dbg !53
%3 = icmp ule i64 0, %1, !dbg !53
br i1 %3, label %BoundsCheckOk, label %BoundsCheckFail, !dbg !53
BoundsCheckFail: ; preds = %Entry
tail call fastcc void @panic(%"[]u8"* @7, %StackTrace* null), !dbg !53
unreachable, !dbg !53
BoundsCheckOk: ; preds = %Entry
%4 = icmp ule i64 %1, %2, !dbg !53
br i1 %4, label %BoundsCheckOk2, label %BoundsCheckFail1, !dbg !53
BoundsCheckFail1: ; preds = %BoundsCheckOk
tail call fastcc void @panic(%"[]u8"* @7, %StackTrace* null), !dbg !53
unreachable, !dbg !53
BoundsCheckOk2: ; preds = %BoundsCheckOk
%5 = load i8*, i8** getelementptr inbounds (%"[]u8", %"[]u8"* @3, i32 0, i32 0), align 8, !dbg !53
%6 = getelementptr inbounds %"[]u8", %"[]u8"* %0, i32 0, i32 0, !dbg !53
%7 = getelementptr inbounds i8, i8* %5, i64 0, !dbg !53
store i8* %7, i8** %6, align 8, !dbg !53
%8 = getelementptr inbounds %"[]u8", %"[]u8"* %0, i32 0, i32 1, !dbg !53
%9 = sub nsw i64 %1, 0, !dbg !53
store i64 %9, i64* %8, align 8, !dbg !53
call fastcc void @slice(%"[]u8"* %0), !dbg !54
ret void, !dbg !55
}
```
---
src/codegen.cpp | 2 ++
src/ir.cpp | 36 +++++++++++++++++++++++++++++-------
src/ir_print.cpp | 1 +
3 files changed, 32 insertions(+), 7 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 7069f57fa3a1..06db8d6cea5a 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -4348,6 +4348,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
+ assert(LLVMGetTypeKind(LLVMTypeOf(tmp_struct_ptr)) == LLVMPointerTypeKind);
bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
@@ -4421,6 +4422,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
assert(array_type->data.structure.is_slice);
assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
+ assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind);
size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index;
assert(ptr_index != SIZE_MAX);
diff --git a/src/ir.cpp b/src/ir.cpp
index 8061cd382137..57d985fc057f 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -6517,8 +6517,11 @@ static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode
return ir_build_const_void(irb, parent_scope, node);
}
-static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
+static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeSliceExpr);
+ assert(result_loc != nullptr);
AstNodeSliceExpr *slice_expr = &node->data.slice_expr;
AstNode *array_node = slice_expr->array_ref_expr;
@@ -6542,7 +6545,8 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node,
end_value = nullptr;
}
- return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true, result_loc);
+ IrInstruction *result = ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true, result_loc);
+ return ir_gen_multi(irb, scope, node, lval, result_loc, result);
}
static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval,
@@ -7398,7 +7402,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeDefer:
return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval);
case NodeTypeSliceExpr:
- return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node, result_loc), lval);
+ return ir_gen_slice(irb, scope, node, lval,
+ ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeUnwrapErrorExpr:
return ir_gen_catch(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
@@ -19413,14 +19418,12 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
}
static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice *instruction) {
+ Error err;
+
IrInstruction *ptr_ptr = instruction->ptr->child;
if (type_is_invalid(ptr_ptr->value.type))
return ira->codegen->invalid_instruction;
- IrInstruction *result_loc = instruction->result_loc->child;
- if (type_is_invalid(result_loc->value.type))
- return ira->codegen->invalid_instruction;
-
ZigType *ptr_type = ptr_ptr->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *array_type = ptr_type->data.pointer.child_type;
@@ -19487,6 +19490,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
return ira->codegen->invalid_instruction;
}
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if ((err = resolve_possible_alloca_inference(ira, result_loc, return_type)))
+ return ira->codegen->invalid_instruction;
+
if (instr_is_comptime(ptr_ptr) &&
value_is_comptime(&casted_start->value) &&
(!end || value_is_comptime(&end->value)))
@@ -19637,6 +19646,10 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
return ira->codegen->invalid_instruction;
}
+ if (result_loc->value.special != ConstValSpecialRuntime) {
+ zig_panic("TODO slice with comptime ptr and values");
+ }
+
IrInstruction *result = ir_const(ira, &instruction->base, return_type);
ConstExprValue *out_val = &result->value;
out_val->data.x_struct.fields = create_const_vals(2);
@@ -19690,6 +19703,15 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
return result;
}
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr_val->special = ConstValSpecialRuntime;
+ }
+ }
+
IrInstruction *new_instruction = ir_build_slice(&ira->new_irb,
instruction->base.scope, instruction->base.source_node,
ptr_ptr, casted_start, end, instruction->safety_check_on,
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 291e161372cd..5a5e378b66b8 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -203,6 +203,7 @@ static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
}
static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
+ fprintf(irp->f, "Call ");
if (call_instruction->is_async) {
fprintf(irp->f, "async");
if (call_instruction->async_allocator != nullptr) {
From d534f38b9ee9ba18e727049c9b431d25f9bce17e Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 19 Nov 2018 12:10:19 -0500
Subject: [PATCH 050/190] copy elision: remove LoadResult and StoreResult
instructions
---
src/all_types.hpp | 16 ---------
src/codegen.cpp | 4 ---
src/ir.cpp | 90 +++++------------------------------------------
src/ir_print.cpp | 18 ----------
4 files changed, 8 insertions(+), 120 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index e67fe74a198f..e029a6e43b75 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2194,8 +2194,6 @@ enum IrInstructionId {
IrInstructionIdResultParam,
IrInstructionIdResultPtrCast,
IrInstructionIdResultCast,
- IrInstructionIdLoadResult,
- IrInstructionIdStoreResult,
IrInstructionIdAllocaSrc,
IrInstructionIdAllocaGen,
IrInstructionIdAssertNonError,
@@ -2368,20 +2366,6 @@ struct IrInstructionStorePtr {
IrInstruction *value;
};
-struct IrInstructionLoadResult {
- IrInstruction base;
-
- IrInstruction *ptr;
- IrInstruction *result_loc;
-};
-
-struct IrInstructionStoreResult {
- IrInstruction base;
-
- IrInstruction *result_loc;
- IrInstruction *value;
-};
-
struct IrInstructionFieldPtr {
IrInstruction base;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 06db8d6cea5a..a6b98312d186 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5411,10 +5411,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
zig_panic("TODO");
case IrInstructionIdResultPtrCast:
zig_panic("TODO");
- case IrInstructionIdLoadResult:
- zig_panic("TODO");
- case IrInstructionIdStoreResult:
- zig_panic("TODO");
}
zig_unreachable();
}
diff --git a/src/ir.cpp b/src/ir.cpp
index 57d985fc057f..deb397a863a3 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -363,14 +363,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStorePtr *) {
return IrInstructionIdStorePtr;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadResult *) {
- return IrInstructionIdLoadResult;
-}
-
-static constexpr IrInstructionId ir_instruction_id(IrInstructionStoreResult *) {
- return IrInstructionIdStoreResult;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldPtr *) {
return IrInstructionIdFieldPtr;
}
@@ -1461,32 +1453,6 @@ static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *s
return &instruction->base;
}
-static IrInstruction *ir_build_load_result(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *ptr, IrInstruction *result_loc)
-{
- IrInstructionLoadResult *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->ptr = ptr;
- instruction->result_loc = result_loc;
-
- ir_ref_instruction(ptr, irb->current_basic_block);
- ir_ref_instruction(result_loc, irb->current_basic_block);
-
- return &instruction->base;
-}
-
-static IrInstruction *ir_build_store_result(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *result_loc, IrInstruction *value)
-{
- IrInstructionStoreResult *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->result_loc = result_loc;
- instruction->value = value;
-
- ir_ref_instruction(result_loc, irb->current_basic_block);
- ir_ref_instruction(value, irb->current_basic_block);
-
- return &instruction->base;
-}
-
static IrInstruction *ir_build_typeof(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
IrInstructionTypeOf *instruction = ir_build_instruction(irb, scope, source_node);
instruction->value = value;
@@ -3920,10 +3886,8 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction,
subscript_instruction, true, PtrLenSingle);
- if (lval == LValPtr)
- return ptr_instruction;
- return ir_build_load_result(irb, scope, node, ptr_instruction, result_loc);
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, ptr_instruction);
}
static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
@@ -4415,9 +4379,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- if (lval == LValPtr)
- return result_loc;
- return ir_build_load_result(irb, scope, node, result_loc, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
}
case BuiltinFnIdToBytes:
{
@@ -4428,9 +4390,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- if (lval == LValPtr)
- return result_loc;
- return ir_build_load_result(irb, scope, node, result_loc, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
}
case BuiltinFnIdIntToFloat:
{
@@ -4601,12 +4561,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node, arg0_value, arg1_value);
-
- if (lval == LValPtr)
- return ptr_instruction;
-
- return ir_build_load_result(irb, scope, node, ptr_instruction, result_loc);
+ IrInstruction *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node,
+ arg0_value, arg1_value);
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, ptr_instruction);
}
case BuiltinFnIdTypeInfo:
{
@@ -4701,10 +4658,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- if (lval == LValPtr)
- return result_loc;
-
- return ir_build_load_result(irb, scope, node, result_loc, result_loc);
+ return ir_gen_result(irb, scope, node, lval, result_loc);
}
case BuiltinFnIdIntToPtr:
{
@@ -7566,7 +7520,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero,
nullptr, false, addrs_slice_ptr);
- ir_build_store_result(irb, scope, node, addrs_slice_ptr, slice_value);
+ ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value);
}
@@ -15960,10 +15914,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
}
}
-static IrInstruction *ir_analyze_instruction_load_result(IrAnalyze *ira, IrInstructionLoadResult *instruction) {
- zig_panic("TODO");
-}
-
static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) {
IrInstruction *ptr = instruction->ptr->child;
if (ptr == nullptr)
@@ -15978,24 +15928,6 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
}
-static IrInstruction *ir_analyze_store_result(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
- IrInstruction *uncasted_result_loc)
-{
- zig_panic("TODO delete this instruction");
-}
-
-static IrInstruction *ir_analyze_instruction_store_result(IrAnalyze *ira, IrInstructionStoreResult *instruction) {
- IrInstruction *value = instruction->value->child;
- if (type_is_invalid(value->value.type))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *result_loc = instruction->result_loc->child;
- if (type_is_invalid(result_loc->value.type))
- return ira->codegen->invalid_instruction;
-
- return ir_analyze_store_result(ira, &instruction->base, value, result_loc);
-}
-
static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) {
IrInstruction *ptr = instruction->ptr->child;
if (type_is_invalid(ptr->value.type))
@@ -22042,10 +21974,6 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction);
case IrInstructionIdStorePtr:
return ir_analyze_instruction_store_ptr(ira, (IrInstructionStorePtr *)instruction);
- case IrInstructionIdLoadResult:
- return ir_analyze_instruction_load_result(ira, (IrInstructionLoadResult *)instruction);
- case IrInstructionIdStoreResult:
- return ir_analyze_instruction_store_result(ira, (IrInstructionStoreResult *)instruction);
case IrInstructionIdElemPtr:
return ir_analyze_instruction_elem_ptr(ira, (IrInstructionElemPtr *)instruction);
case IrInstructionIdVarPtr:
@@ -22440,8 +22368,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdMergeErrRetTraces:
case IrInstructionIdMarkErrRetTracePtr:
case IrInstructionIdAtomicRmw:
- case IrInstructionIdLoadResult:
- case IrInstructionIdStoreResult:
case IrInstructionIdAssertNonError:
case IrInstructionIdContainerInitFields:
case IrInstructionIdContainerInitList:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 5a5e378b66b8..75ea96bbe0d5 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1357,18 +1357,6 @@ static void ir_print_result_cast(IrPrint *irp, IrInstructionResultCast *instruct
fprintf(irp->f, ")");
}
-static void ir_print_load_result(IrPrint *irp, IrInstructionLoadResult *instruction) {
- fprintf(irp->f, "LoadResult");
-}
-
-static void ir_print_store_result(IrPrint *irp, IrInstructionStoreResult *instruction) {
- fprintf(irp->f, "StoreResult(result=");
- ir_print_other_instruction(irp, instruction->result_loc);
- fprintf(irp->f, ",value=");
- ir_print_other_instruction(irp, instruction->value);
- fprintf(irp->f, ")");
-}
-
static void ir_print_alloca_src(IrPrint *irp, IrInstructionAllocaSrc *instruction) {
fprintf(irp->f, "AllocaSrc(ty=");
ir_print_other_instruction(irp, instruction->child_type);
@@ -1850,12 +1838,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdResultCast:
ir_print_result_cast(irp, (IrInstructionResultCast *)instruction);
break;
- case IrInstructionIdLoadResult:
- ir_print_load_result(irp, (IrInstructionLoadResult *)instruction);
- break;
- case IrInstructionIdStoreResult:
- ir_print_store_result(irp, (IrInstructionStoreResult *)instruction);
- break;
case IrInstructionIdAllocaSrc:
ir_print_alloca_src(irp, (IrInstructionAllocaSrc *)instruction);
break;
From 0e41e9098dfadea68ea1a3a36cc3b2c6a8d1229e Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 19 Nov 2018 16:51:22 -0500
Subject: [PATCH 051/190] copy elision: remove all uses of ir_lval_wrap
---
src/all_types.hpp | 1 -
src/ir.cpp | 378 +++++++++++++++++++++++++---------------------
2 files changed, 207 insertions(+), 172 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index e029a6e43b75..4c8477497708 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -3022,7 +3022,6 @@ struct IrInstructionTagName {
IrInstruction base;
IrInstruction *target;
- IrInstruction *result_loc;
};
struct IrInstructionTagType {
diff --git a/src/ir.cpp b/src/ir.cpp
index deb397a863a3..02fe8cc681b3 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -148,7 +148,6 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type);
static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var);
static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);
-static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align);
static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align);
static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);
@@ -2338,14 +2337,12 @@ static IrInstruction *ir_build_panic(IrBuilder *irb, Scope *scope, AstNode *sour
}
static IrInstruction *ir_build_tag_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *target, IrInstruction *result_loc)
+ IrInstruction *target)
{
IrInstructionTagName *instruction = ir_build_instruction(irb, scope, source_node);
instruction->target = target;
- instruction->result_loc = result_loc;
ir_ref_instruction(target, irb->current_basic_block);
- ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -3421,7 +3418,7 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n
return var;
}
-static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node,
+static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node, LVal lval,
IrInstruction *result_loc)
{
assert(block_node->type == NodeTypeBlock);
@@ -3441,7 +3438,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
if (block_node->data.block.statements.length == 0) {
// {}
- return ir_build_const_void(irb, child_scope, block_node);
+ return ir_gen_value(irb, parent_scope, block_node, lval, result_loc,
+ ir_build_const_void(irb, child_scope, block_node));
}
if (block_node->data.block.name != nullptr) {
@@ -3449,7 +3447,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
scope_block->incoming_blocks = &incoming_blocks;
scope_block->incoming_values = &incoming_values;
scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd");
- scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope));
+ scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node,
+ ir_should_inline(irb->exec, parent_scope));
}
bool is_continuation_unreachable = false;
@@ -3484,20 +3483,21 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
}
ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
- return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
- } else {
- incoming_blocks.append(irb->current_basic_block);
- incoming_values.append(ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node)));
+ return ir_gen_result(irb, parent_scope, block_node, lval, result_loc);
}
if (block_node->data.block.name != nullptr) {
+ IrInstruction *continuation_expr_result = ir_build_const_void(irb, parent_scope, block_node);
+ ir_build_store_ptr(irb, parent_scope, block_node, result_loc, continuation_expr_result);
+
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
- return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
+ return ir_gen_result(irb, parent_scope, block_node, lval, result_loc);
} else {
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
- return ir_mark_gen(ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)));
+ return ir_gen_value(irb, parent_scope, block_node, lval, result_loc,
+ ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)));
}
}
@@ -3688,87 +3688,125 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node,
case BinOpTypeInvalid:
zig_unreachable();
case BinOpTypeAssign:
- return ir_lval_wrap(irb, scope, ir_gen_assign(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_assign(irb, scope, node));
case BinOpTypeAssignTimes:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMult), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpMult));
case BinOpTypeAssignTimesWrap:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap));
case BinOpTypeAssignDiv:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpDivUnspecified), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpDivUnspecified));
case BinOpTypeAssignMod:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpRemUnspecified), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpRemUnspecified));
case BinOpTypeAssignPlus:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpAdd), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpAdd));
case BinOpTypeAssignPlusWrap:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap));
case BinOpTypeAssignMinus:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpSub), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpSub));
case BinOpTypeAssignMinusWrap:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap));
case BinOpTypeAssignBitShiftLeft:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy));
case BinOpTypeAssignBitShiftRight:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy));
case BinOpTypeAssignBitAnd:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd));
case BinOpTypeAssignBitXor:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinXor), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpBinXor));
case BinOpTypeAssignBitOr:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinOr), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpBinOr));
case BinOpTypeAssignMergeErrorSets:
- return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets));
case BinOpTypeBoolOr:
- return ir_lval_wrap(irb, scope, ir_gen_bool_or(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_bool_or(irb, scope, node));
case BinOpTypeBoolAnd:
- return ir_lval_wrap(irb, scope, ir_gen_bool_and(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_bool_and(irb, scope, node));
case BinOpTypeCmpEq:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq));
case BinOpTypeCmpNotEq:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq));
case BinOpTypeCmpLessThan:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan));
case BinOpTypeCmpGreaterThan:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan));
case BinOpTypeCmpLessOrEq:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq));
case BinOpTypeCmpGreaterOrEq:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq));
case BinOpTypeBinOr:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr));
case BinOpTypeBinXor:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor));
case BinOpTypeBinAnd:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd));
case BinOpTypeBitShiftLeft:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy));
case BinOpTypeBitShiftRight:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy));
case BinOpTypeAdd:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd));
case BinOpTypeAddWrap:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap));
case BinOpTypeSub:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpSub), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpSub));
case BinOpTypeSubWrap:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap));
case BinOpTypeMult:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMult), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpMult));
case BinOpTypeMultWrap:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap));
case BinOpTypeDiv:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpDivUnspecified), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpDivUnspecified));
case BinOpTypeMod:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpRemUnspecified), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpRemUnspecified));
case BinOpTypeArrayCat:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat));
case BinOpTypeArrayMult:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult));
case BinOpTypeMergeErrorSets:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets));
+ case BinOpTypeErrorUnion:
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_error_union(irb, scope, node));
+
case BinOpTypeUnwrapOptional:
return ir_gen_orelse(irb, scope, node, lval, result_loc);
- case BinOpTypeErrorUnion:
- return ir_lval_wrap(irb, scope, ir_gen_error_union(irb, scope, node), lval);
}
zig_unreachable();
}
@@ -3829,7 +3867,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
}
} else {
IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type);
- return ir_lval_wrap(irb, scope, value, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, value);
}
ScopeFnDef *crossed_fndef_scope;
@@ -3986,7 +4024,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg;
IrInstruction *type_of = ir_build_typeof(irb, scope, node, arg);
- return ir_lval_wrap(irb, scope, type_of, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, type_of);
}
case BuiltinFnIdSetCold:
{
@@ -3996,7 +4034,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *set_cold = ir_build_set_cold(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, set_cold, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, set_cold);
}
case BuiltinFnIdSetRuntimeSafety:
{
@@ -4006,7 +4044,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *set_safety = ir_build_set_runtime_safety(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, set_safety, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, set_safety);
}
case BuiltinFnIdSetFloatMode:
{
@@ -4016,7 +4054,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, set_float_mode, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, set_float_mode);
}
case BuiltinFnIdSizeof:
{
@@ -4026,7 +4064,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, size_of, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, size_of);
}
case BuiltinFnIdCtz:
{
@@ -4036,7 +4074,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *ctz = ir_build_ctz(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, ctz, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ctz);
}
case BuiltinFnIdPopCount:
{
@@ -4046,7 +4084,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *instr = ir_build_pop_count(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, instr, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, instr);
}
case BuiltinFnIdClz:
{
@@ -4056,7 +4094,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *clz = ir_build_clz(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, clz, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, clz);
}
case BuiltinFnIdImport:
{
@@ -4066,12 +4104,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *import = ir_build_import(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, import, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, import);
}
case BuiltinFnIdCImport:
{
IrInstruction *c_import = ir_build_c_import(irb, scope, node);
- return ir_lval_wrap(irb, scope, c_import, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, c_import);
}
case BuiltinFnIdCInclude:
{
@@ -4086,7 +4124,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
IrInstruction *c_include = ir_build_c_include(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, c_include, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, c_include);
}
case BuiltinFnIdCDefine:
{
@@ -4106,7 +4144,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
IrInstruction *c_define = ir_build_c_define(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, c_define, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, c_define);
}
case BuiltinFnIdCUndef:
{
@@ -4121,7 +4159,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
IrInstruction *c_undef = ir_build_c_undef(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, c_undef, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, c_undef);
}
case BuiltinFnIdCompileErr:
{
@@ -4131,7 +4169,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *compile_err = ir_build_compile_err(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, compile_err, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, compile_err);
}
case BuiltinFnIdCompileLog:
{
@@ -4145,7 +4183,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
IrInstruction *compile_log = ir_build_compile_log(irb, scope, node, actual_param_count, args);
- return ir_lval_wrap(irb, scope, compile_log, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, compile_log);
}
case BuiltinFnIdErrName:
{
@@ -4155,7 +4193,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *err_name = ir_build_err_name(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, err_name, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, err_name);
}
case BuiltinFnIdEmbedFile:
{
@@ -4165,7 +4203,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *embed_file = ir_build_embed_file(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, embed_file, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, embed_file);
}
case BuiltinFnIdCmpxchgWeak:
case BuiltinFnIdCmpxchgStrong:
@@ -4203,7 +4241,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak),
nullptr, AtomicOrderUnordered, AtomicOrderUnordered, result_loc);
- return ir_lval_wrap(irb, scope, cmpxchg, lval);
+ return ir_gen_multi(irb, scope, node, lval, result_loc, cmpxchg);
}
case BuiltinFnIdFence:
{
@@ -4213,7 +4251,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *fence = ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);
- return ir_lval_wrap(irb, scope, fence, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, fence);
}
case BuiltinFnIdDivExact:
{
@@ -4228,7 +4266,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdDivTrunc:
{
@@ -4243,7 +4281,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdDivFloor:
{
@@ -4258,7 +4296,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdRem:
{
@@ -4273,7 +4311,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdMod:
{
@@ -4288,7 +4326,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdSqrt:
{
@@ -4303,7 +4341,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *ir_sqrt = ir_build_sqrt(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, ir_sqrt, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_sqrt);
}
case BuiltinFnIdTruncate:
{
@@ -4318,7 +4356,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *truncate = ir_build_truncate(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, truncate, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, truncate);
}
case BuiltinFnIdIntCast:
{
@@ -4333,7 +4371,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *result = ir_build_int_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdFloatCast:
{
@@ -4348,7 +4386,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdErrSetCast:
{
@@ -4363,7 +4401,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdFromBytes:
{
@@ -4405,7 +4443,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *result = ir_build_int_to_float(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdFloatToInt:
{
@@ -4420,7 +4458,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdErrToInt:
{
@@ -4430,7 +4468,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *result = ir_build_err_to_int(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdIntToErr:
{
@@ -4440,7 +4478,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *result = ir_build_int_to_err(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdBoolToInt:
{
@@ -4450,7 +4488,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *result = ir_build_bool_to_int(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdIntType:
{
@@ -4465,7 +4503,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, int_type, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, int_type);
}
case BuiltinFnIdMemcpy:
{
@@ -4485,7 +4523,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg2_value;
IrInstruction *ir_memcpy = ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value);
- return ir_lval_wrap(irb, scope, ir_memcpy, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_memcpy);
}
case BuiltinFnIdMemset:
{
@@ -4505,7 +4543,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg2_value;
IrInstruction *ir_memset = ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value);
- return ir_lval_wrap(irb, scope, ir_memset, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_memset);
}
case BuiltinFnIdMemberCount:
{
@@ -4515,7 +4553,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *member_count = ir_build_member_count(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, member_count, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, member_count);
}
case BuiltinFnIdMemberType:
{
@@ -4531,7 +4569,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction *member_type = ir_build_member_type(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, member_type, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, member_type);
}
case BuiltinFnIdMemberName:
{
@@ -4545,9 +4583,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
-
IrInstruction *member_name = ir_build_member_name(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, member_name, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, member_name);
}
case BuiltinFnIdField:
{
@@ -4573,14 +4610,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *type_info = ir_build_type_info(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, type_info, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, type_info);
}
case BuiltinFnIdBreakpoint:
- return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_breakpoint(irb, scope, node));
case BuiltinFnIdReturnAddress:
- return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_return_address(irb, scope, node));
case BuiltinFnIdFrameAddress:
- return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_frame_address(irb, scope, node));
case BuiltinFnIdHandle:
if (!irb->exec->fn_entry) {
add_node_error(irb->codegen, node, buf_sprintf("@handle() called outside of function definition"));
@@ -4590,7 +4627,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
add_node_error(irb->codegen, node, buf_sprintf("@handle() in non-async function"));
return irb->codegen->invalid_instruction;
}
- return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_handle(irb, scope, node));
case BuiltinFnIdAlignOf:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
@@ -4599,16 +4636,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *align_of = ir_build_align_of(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, align_of, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, align_of);
}
case BuiltinFnIdAddWithOverflow:
- return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd));
case BuiltinFnIdSubWithOverflow:
- return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub));
case BuiltinFnIdMulWithOverflow:
- return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul));
case BuiltinFnIdShlWithOverflow:
- return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl));
case BuiltinFnIdTypeName:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
@@ -4617,7 +4658,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value, result_loc);
- return ir_lval_wrap(irb, scope, type_name, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, type_name);
}
case BuiltinFnIdPanic:
{
@@ -4627,7 +4668,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *panic = ir_build_panic(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, panic, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, panic);
}
case BuiltinFnIdPtrCast:
{
@@ -4642,7 +4683,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *ptr_cast = ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, ptr_cast, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ptr_cast);
}
case BuiltinFnIdBitCast:
{
@@ -4673,7 +4714,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *int_to_ptr = ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, int_to_ptr, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, int_to_ptr);
}
case BuiltinFnIdPtrToInt:
{
@@ -4693,8 +4734,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
- IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag, result_loc);
- return ir_lval_wrap(irb, scope, tag_name, lval);
+ IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag);
+ return ir_gen_value(irb, scope, node, lval, result_loc, tag_name);
}
case BuiltinFnIdTagType:
{
@@ -4704,7 +4745,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *tag_type = ir_build_tag_type(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, tag_type, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, tag_type);
}
case BuiltinFnIdFieldParentPtr:
{
@@ -4723,8 +4764,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
- IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr);
- return ir_lval_wrap(irb, scope, field_parent_ptr, lval);
+ IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node,
+ arg0_value, arg1_value, arg2_value, nullptr);
+ return ir_gen_value(irb, scope, node, lval, result_loc, field_parent_ptr);
}
case BuiltinFnIdByteOffsetOf:
{
@@ -4739,7 +4781,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *offset_of = ir_build_byte_offset_of(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, offset_of, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, offset_of);
}
case BuiltinFnIdBitOffsetOf:
{
@@ -4754,7 +4796,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *offset_of = ir_build_bit_offset_of(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, offset_of, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, offset_of);
}
case BuiltinFnIdInlineCall:
case BuiltinFnIdNoInlineCall:
@@ -4783,7 +4825,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
fn_inline, false, nullptr, nullptr, result_loc, nullptr);
- return ir_lval_wrap(irb, scope, call, lval);
+ return ir_gen_multi(irb, scope, node, lval, result_loc, call);
}
case BuiltinFnIdNewStackCall:
{
@@ -4815,7 +4857,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args,
false, FnInlineAuto, false, nullptr, new_stack, result_loc, nullptr);
- return ir_lval_wrap(irb, scope, call, lval);
+ return ir_gen_multi(irb, scope, node, lval, result_loc, call);
}
case BuiltinFnIdTypeId:
{
@@ -4825,7 +4867,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *type_id = ir_build_type_id(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, type_id, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, type_id);
}
case BuiltinFnIdShlExact:
{
@@ -4839,8 +4881,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact,
+ arg0_value, arg1_value, true);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdShrExact:
{
@@ -4854,8 +4897,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact,
+ arg0_value, arg1_value, true);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdSetEvalBranchQuota:
{
@@ -4865,7 +4909,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *set_eval_branch_quota = ir_build_set_eval_branch_quota(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, set_eval_branch_quota, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, set_eval_branch_quota);
}
case BuiltinFnIdAlignCast:
{
@@ -4880,17 +4924,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *align_cast = ir_build_align_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, align_cast, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, align_cast);
}
case BuiltinFnIdOpaqueType:
{
IrInstruction *opaque_type = ir_build_opaque_type(irb, scope, node);
- return ir_lval_wrap(irb, scope, opaque_type, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, opaque_type);
}
case BuiltinFnIdThis:
{
IrInstruction *this_inst = ir_gen_this(irb, scope, node);
- return ir_lval_wrap(irb, scope, this_inst, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, this_inst);
}
case BuiltinFnIdSetAlignStack:
{
@@ -4900,7 +4944,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *set_align_stack = ir_build_set_align_stack(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, set_align_stack, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, set_align_stack);
}
case BuiltinFnIdArgType:
{
@@ -4915,7 +4959,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *arg_type = ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, arg_type, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, arg_type);
}
case BuiltinFnIdExport:
{
@@ -4935,12 +4979,13 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg2_value;
IrInstruction *ir_export = ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);
- return ir_lval_wrap(irb, scope, ir_export, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_export);
}
case BuiltinFnIdErrorReturnTrace:
{
- IrInstruction *error_return_trace = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
- return ir_lval_wrap(irb, scope, error_return_trace, lval);
+ IrInstruction *error_return_trace = ir_build_error_return_trace(irb, scope, node,
+ IrInstructionErrorReturnTrace::Null);
+ return ir_gen_value(irb, scope, node, lval, result_loc, error_return_trace);
}
case BuiltinFnIdAtomicRmw:
{
@@ -4969,10 +5014,11 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg4_value == irb->codegen->invalid_instruction)
return arg4_value;
- return ir_build_atomic_rmw(irb, scope, node, arg0_value, arg1_value, arg2_value, arg3_value,
- arg4_value,
+ IrInstruction *result = ir_build_atomic_rmw(irb, scope, node, arg0_value, arg1_value,
+ arg2_value, arg3_value, arg4_value,
// these 2 values don't mean anything since we passed non-null values for other args
AtomicRmwOp_xchg, AtomicOrderMonotonic);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdAtomicLoad:
{
@@ -4991,9 +5037,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
- return ir_build_atomic_load(irb, scope, node, arg0_value, arg1_value, arg2_value,
+ IrInstruction *result = ir_build_atomic_load(irb, scope, node, arg0_value, arg1_value, arg2_value,
// this value does not mean anything since we passed non-null values for other arg
AtomicOrderMonotonic);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdIntToEnum:
{
@@ -5008,7 +5055,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg1_value;
IrInstruction *result = ir_build_int_to_enum(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdEnumToInt:
{
@@ -5018,7 +5065,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
}
zig_unreachable();
@@ -5138,17 +5185,6 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode
return ir_build_un_op(irb, scope, node, op_id, value);
}
-static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval) {
- if (lval != LValPtr)
- return value;
- if (value == irb->codegen->invalid_instruction)
- return value;
-
- // We needed a pointer to a value, but we got a value. So we create
- // an instruction which just makes a pointer of it.
- return ir_build_ref(irb, scope, value->source_node, value, false, false);
-}
-
static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypePointerType);
PtrLen ptr_len = (node->data.pointer_type.star_token->id == TokenIdStar ||
@@ -5246,15 +5282,19 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
case PrefixOpInvalid:
zig_unreachable();
case PrefixOpBoolNot:
- return ir_lval_wrap(irb, scope, ir_gen_bool_not(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_bool_not(irb, scope, node));
case PrefixOpBinNot:
- return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot));
case PrefixOpNegation:
- return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation));
case PrefixOpNegationWrap:
- return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap));
case PrefixOpOptional:
- return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional));
case PrefixOpAddrOf: {
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, expr_node, result_loc);
@@ -7261,7 +7301,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeTestDecl:
zig_unreachable();
case NodeTypeBlock:
- return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node, result_loc), lval);
+ return ir_gen_block(irb, scope, node, lval, result_loc);
case NodeTypeGroupedExpr:
return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_loc);
case NodeTypeBinOpExpr:
@@ -7285,7 +7325,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_gen_container_init_expr(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeVariableDeclaration:
- return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_var_decl(irb, scope, node));
case NodeTypeWhileExpr:
return ir_gen_while_expr(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
@@ -7348,13 +7388,13 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeErrorType:
return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_error_type(irb, scope, node));
case NodeTypeBreak:
- return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_break(irb, scope, node));
case NodeTypeContinue:
- return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_continue(irb, scope, node));
case NodeTypeUnreachable:
- return ir_lval_wrap(irb, scope, ir_build_unreachable(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_unreachable(irb, scope, node));
case NodeTypeDefer:
- return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_defer(irb, scope, node));
case NodeTypeSliceExpr:
return ir_gen_slice(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
@@ -7362,19 +7402,19 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_gen_catch(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeContainerDecl:
- return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_container_decl(irb, scope, node));
case NodeTypeFnProto:
return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_fn_proto(irb, scope, node));
case NodeTypeErrorSetDecl:
return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_err_set_decl(irb, scope, node));
case NodeTypeCancel:
- return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_cancel(irb, scope, node));
case NodeTypeResume:
- return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_resume(irb, scope, node));
case NodeTypeAwaitExpr:
- return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_await_expr(irb, scope, node));
case NodeTypeSuspend:
- return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_suspend(irb, scope, node));
}
zig_unreachable();
}
@@ -17299,7 +17339,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- IrInstruction *casted_value = ir_implicit_cast(ira, value, value->value.type);
+ IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_error_set);
if (type_is_invalid(casted_value->value.type))
return ira->codegen->invalid_instruction;
@@ -17332,10 +17372,6 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
if (type_is_invalid(target->value.type))
return ira->codegen->invalid_instruction;
- IrInstruction *result_loc = instruction->result_loc->child;
- if (type_is_invalid(result_loc->value.type))
- return ira->codegen->invalid_instruction;
-
assert(target->value.type->id == ZigTypeIdEnum);
if (instr_is_comptime(target)) {
@@ -17349,7 +17385,7 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
}
IrInstruction *result = ir_build_tag_name(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, target, result_loc);
+ instruction->base.source_node, target);
ZigType *u8_ptr_type = get_pointer_to_type_extra(
ira->codegen, ira->codegen->builtin_types.entry_u8,
true, false, PtrLenUnknown,
From 6299526c466e6496cd10968c181bd92cd316ad11 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 19 Nov 2018 17:00:18 -0500
Subject: [PATCH 052/190] copy elision: match ir_gen_result with
ensure_result_loc
---
src/ir.cpp | 41 +++++++++++++++++++++++------------------
1 file changed, 23 insertions(+), 18 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 02fe8cc681b3..a794ae80d338 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3418,6 +3418,12 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n
return var;
}
+static IrInstruction *ensure_result_loc(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
+ if (result_loc)
+ return result_loc;
+ return ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
+}
+
static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node, LVal lval,
IrInstruction *result_loc)
{
@@ -3443,7 +3449,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
}
if (block_node->data.block.name != nullptr) {
- scope_block->result_loc = result_loc;
+ scope_block->result_loc = ensure_result_loc(irb, parent_scope, block_node, result_loc);
scope_block->incoming_blocks = &incoming_blocks;
scope_block->incoming_values = &incoming_values;
scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd");
@@ -3483,17 +3489,17 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
}
ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
- return ir_gen_result(irb, parent_scope, block_node, lval, result_loc);
+ return ir_gen_result(irb, parent_scope, block_node, lval, scope_block->result_loc);
}
if (block_node->data.block.name != nullptr) {
IrInstruction *continuation_expr_result = ir_build_const_void(irb, parent_scope, block_node);
- ir_build_store_ptr(irb, parent_scope, block_node, result_loc, continuation_expr_result);
+ ir_build_store_ptr(irb, parent_scope, block_node, scope_block->result_loc, continuation_expr_result);
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
- return ir_gen_result(irb, parent_scope, block_node, lval, result_loc);
+ return ir_gen_result(irb, parent_scope, block_node, lval, scope_block->result_loc);
} else {
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
return ir_gen_value(irb, parent_scope, block_node, lval, result_loc,
@@ -3806,7 +3812,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node,
ir_gen_error_union(irb, scope, node));
case BinOpTypeUnwrapOptional:
- return ir_gen_orelse(irb, scope, node, lval, result_loc);
+ return ir_gen_orelse(irb, scope, node, lval, ensure_result_loc(irb, scope, node, result_loc));
}
zig_unreachable();
}
@@ -4410,25 +4416,28 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- IrInstruction *new_result_loc = ir_build_result_slice_to_bytes(irb, scope, node, arg0_value, result_loc);
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, result_loc);
+ IrInstruction *new_result_loc = ir_build_result_slice_to_bytes(irb, scope, node, arg0_value,
+ ensured_result_loc);
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, new_result_loc);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- return ir_gen_result(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, ensured_result_loc);
}
case BuiltinFnIdToBytes:
{
- IrInstruction *new_result_loc = ir_build_result_bytes_to_slice(irb, scope, node, result_loc);
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, result_loc);
+ IrInstruction *new_result_loc = ir_build_result_bytes_to_slice(irb, scope, node, ensured_result_loc);
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, new_result_loc);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- return ir_gen_result(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, ensured_result_loc);
}
case BuiltinFnIdIntToFloat:
{
@@ -4692,14 +4701,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- IrInstruction *new_result_loc = ir_build_result_ptr_cast(irb, scope, node, arg0_value, result_loc);
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, result_loc);
+ IrInstruction *new_result_loc = ir_build_result_ptr_cast(irb, scope, node, arg0_value,
+ ensured_result_loc);
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, new_result_loc);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- return ir_gen_result(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, ensured_result_loc);
}
case BuiltinFnIdIntToPtr:
{
@@ -5265,12 +5276,6 @@ static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_bool_not(irb, scope, node, value);
}
-static IrInstruction *ensure_result_loc(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
- if (result_loc)
- return result_loc;
- return ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
-}
-
static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc)
{
@@ -7330,7 +7335,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_gen_while_expr(irb, scope, node, lval,
ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeForExpr:
- return ir_gen_for_expr(irb, scope, node, lval, result_loc);
+ return ir_gen_for_expr(irb, scope, node, lval, ensure_result_loc(irb, scope, node, result_loc));
case NodeTypeArrayAccessExpr:
return ir_gen_array_access(irb, scope, node, lval, result_loc);
case NodeTypeReturnExpr:
From 2cd43513913d6817d41434fc5673840b6da330d4 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 21 Nov 2018 16:43:29 -0500
Subject: [PATCH 053/190] copy elision: @bitCast with runtime value
```zig
export fn entry() void {
var y: u32 = 1234;
var x = @bitCast(f32, y);
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%y = alloca i32, align 4
%x = alloca float, align 4
store i32 1234, i32* %y, align 4, !dbg !51
call void @llvm.dbg.declare(metadata i32* %y, metadata !45, metadata !DIExpression()), !dbg !51
%0 = load i32, i32* %y, align 4, !dbg !52
%1 = bitcast float* %x to i32*, !dbg !53
store i32 %0, i32* %1, align 4, !dbg !52
call void @llvm.dbg.declare(metadata float* %x, metadata !48, metadata !DIExpression()), !dbg !54
ret void, !dbg !55
}
```
---
src/all_types.hpp | 27 ++++-
src/codegen.cpp | 8 +-
src/ir.cpp | 294 +++++++++++++++++++++++++++++-----------------
src/ir_print.cpp | 32 ++++-
4 files changed, 241 insertions(+), 120 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 4c8477497708..82b289e65845 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -34,6 +34,7 @@ struct CodeGen;
struct ConstExprValue;
struct IrInstruction;
struct IrInstructionAllocaGen;
+struct IrInstructionResultPtrCast;
struct IrBasicBlock;
struct ScopeDecls;
struct ZigWindowsSDK;
@@ -2129,7 +2130,8 @@ enum IrInstructionId {
IrInstructionIdErrWrapPayload,
IrInstructionIdFnProto,
IrInstructionIdTestComptime,
- IrInstructionIdPtrCast,
+ IrInstructionIdPtrCastSrc,
+ IrInstructionIdPtrCastGen,
IrInstructionIdBitCast,
IrInstructionIdWidenOrShorten,
IrInstructionIdIntToPtr,
@@ -2200,6 +2202,7 @@ enum IrInstructionId {
IrInstructionIdErrorUnionFieldErrorSet,
IrInstructionIdFirstArgResultLoc,
IrInstructionIdInferArrayType,
+ IrInstructionIdInferCompTime,
};
struct IrInstruction {
@@ -2914,13 +2917,26 @@ struct IrInstructionTestComptime {
IrInstruction *value;
};
-struct IrInstructionPtrCast {
+struct IrInstructionPtrCastSrc {
IrInstruction base;
IrInstruction *dest_type;
IrInstruction *ptr;
};
+struct IrInstructionPtrCastGen {
+ IrInstruction base;
+
+ IrInstruction *ptr;
+
+ // This instruction supports being created with the child
+ // type of the pointer being "infer" which means that a later
+ // instruction will replace this one.
+ // so we have a reference here to the pass-1 instruction so that
+ // the child pointer can be updated to the new pass-2 instruction.
+ IrInstructionResultPtrCast *pass1_parent;
+};
+
struct IrInstructionBitCast {
IrInstruction base;
@@ -3377,6 +3393,13 @@ struct IrInstructionInferArrayType {
size_t elem_count;
};
+struct IrInstructionInferCompTime {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ IrInstruction *new_result_loc;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index a6b98312d186..badad23471dd 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3024,7 +3024,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
}
static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
- IrInstructionPtrCast *instruction)
+ IrInstructionPtrCastGen *instruction)
{
ZigType *wanted_type = instruction->base.value.type;
if (!type_has_bits(wanted_type)) {
@@ -5233,6 +5233,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdResultCast:
case IrInstructionIdContainerInitList:
case IrInstructionIdInferArrayType:
+ case IrInstructionIdPtrCastSrc:
+ case IrInstructionIdInferCompTime:
zig_unreachable();
case IrInstructionIdDeclVarGen:
@@ -5325,8 +5327,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);
case IrInstructionIdUnionTag:
return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction);
- case IrInstructionIdPtrCast:
- return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction);
+ case IrInstructionIdPtrCastGen:
+ return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction);
case IrInstructionIdBitCast:
return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction);
case IrInstructionIdWidenOrShorten:
diff --git a/src/ir.cpp b/src/ir.cpp
index a794ae80d338..620b53ad3db2 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -642,8 +642,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *)
return IrInstructionIdTestComptime;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) {
- return IrInstructionIdPtrCast;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastSrc *) {
+ return IrInstructionIdPtrCastSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) {
+ return IrInstructionIdPtrCastGen;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) {
@@ -918,6 +922,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionInferArrayType *
return IrInstructionIdInferArrayType;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionInferCompTime *) {
+ return IrInstructionIdInferCompTime;
+}
+
template
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate(1);
@@ -982,16 +990,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou
return &return_instruction->base;
}
-static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node,
- ZigType *type_entry)
-{
- assert(type_entry);
- IrInstructionConst *const_instruction = ir_create_instruction(irb, scope, source_node);
- const_instruction->base.value.type = type_entry;
- const_instruction->base.value.special = ConstValSpecialStatic;
- return &const_instruction->base;
-}
-
static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node);
const_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
@@ -2153,20 +2151,33 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo
return &instruction->base;
}
-static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *dest_type, IrInstruction *ptr)
{
- IrInstructionPtrCast *instruction = ir_build_instruction(
+ IrInstructionPtrCastSrc *instruction = ir_build_instruction(
irb, scope, source_node);
instruction->dest_type = dest_type;
instruction->ptr = ptr;
- if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
+ ir_ref_instruction(dest_type, irb->current_basic_block);
ir_ref_instruction(ptr, irb->current_basic_block);
return &instruction->base;
}
+static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instr,
+ ZigType *ptr_type, IrInstruction *ptr)
+{
+ IrInstructionPtrCastGen *instruction = ir_build_instruction(
+ &ira->new_irb, source_instr->scope, source_instr->source_node);
+ instruction->ptr = ptr;
+ instruction->base.value.type = ptr_type;
+
+ ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *dest_type, IrInstruction *value)
{
@@ -2944,6 +2955,19 @@ static IrInstruction *ir_build_infer_array_type(IrBuilder *irb, Scope *scope, As
return &instruction->base;
}
+static IrInstruction *ir_build_infer_comptime(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, IrInstruction *new_result_loc)
+{
+ IrInstructionInferCompTime *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->new_result_loc = new_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ ir_ref_instruction(new_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -4691,7 +4715,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *ptr_cast = ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
+ IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value);
return ir_gen_value(irb, scope, node, lval, result_loc, ptr_cast);
}
case BuiltinFnIdBitCast:
@@ -4710,6 +4734,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
+ ir_build_infer_comptime(irb, scope, node, ensured_result_loc, new_result_loc);
+
return ir_gen_result(irb, scope, node, lval, ensured_result_loc);
}
case BuiltinFnIdIntToPtr:
@@ -6871,7 +6897,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
// TODO relies on Zig not re-ordering fields
- IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
+ IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst);
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
@@ -6949,7 +6975,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode
get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void));
// TODO relies on Zig not re-ordering fields
- IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
+ IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst);
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
@@ -7344,11 +7370,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_gen_field_access(irb, scope, node, lval, result_loc);
case NodeTypePtrDeref: {
AstNode *expr_node = node->data.ptr_deref_expr.target;
- IrInstruction *value = ir_gen_node(irb, expr_node, scope, lval, nullptr);
- if (value == irb->codegen->invalid_instruction)
- return value;
-
- return ir_build_un_op(irb, scope, node, IrUnOpDereference, value);
+ IrInstruction *ptr_inst = ir_gen_node(irb, expr_node, scope, LValNone, nullptr);
+ if (ptr_inst == irb->codegen->invalid_instruction)
+ return ptr_inst;
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, ptr_inst);
}
case NodeTypeUnwrapOptional: {
AstNode *expr_node = node->data.unwrap_optional.expr;
@@ -7497,7 +7522,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
- IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
+ IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
@@ -7527,7 +7552,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ir_build_return(irb, coro_scope, node, undef);
ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
- IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
+ IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
@@ -7612,8 +7637,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, nullptr);
- IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
- IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len,
+ IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
+ IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
irb->exec->coro_result_field_ptr);
IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
fn_entry->type_entry->data.fn.fn_type_id.return_type);
@@ -7666,7 +7691,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
- IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
+ IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr, nullptr);
@@ -9588,14 +9613,23 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_
}
return true;
}
+
+static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) {
+ IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
+ old_instruction->scope, old_instruction->source_node);
+ IrInstruction *new_instruction = &const_instruction->base;
+ new_instruction->value.type = ty;
+ new_instruction->value.special = ConstValSpecialStatic;
+ return new_instruction;
+}
+
static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
ZigType *wanted_type, CastOp cast_op, bool need_alloca)
{
if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) &&
cast_op != CastOpResizeSlice && cast_op != CastOpBytesToSlice)
{
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type,
&result->value, wanted_type))
{
@@ -9629,8 +9663,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
if (pointee == nullptr)
return ira->codegen->invalid_instruction;
if (pointee->special != ConstValSpecialRuntime) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.type = wanted_type;
result->value.data.x_ptr.special = ConstPtrSpecialBaseArray;
result->value.data.x_ptr.mut = value->value.data.x_ptr.mut;
@@ -9670,8 +9703,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
assert(is_slice(wanted_type));
bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const);
result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut =
value->value.data.x_ptr.mut;
@@ -9805,15 +9837,6 @@ static IrInstruction *ir_finish_anal(IrAnalyze *ira, IrInstruction *instruction)
return instruction;
}
-static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) {
- IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
- old_instruction->scope, old_instruction->source_node);
- IrInstruction *new_instruction = &const_instruction->base;
- new_instruction->value.type = ty;
- new_instruction->value.special = ConstValSpecialStatic;
- return new_instruction;
-}
-
static IrInstruction *ir_const_type(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) {
IrInstruction *result = ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_type);
result->value.data.x_type = ty;
@@ -10417,19 +10440,16 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
assert(array_type->id == ZigTypeIdArray);
if (instr_is_comptime(array)) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_slice(ira->codegen, &result->value, &array->value, 0, array_type->data.array.len, true);
result->value.type = wanted_type;
return result;
}
- IrInstruction *start = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, ira->codegen->builtin_types.entry_usize);
+ IrInstruction *start = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize);
init_const_usize(ira->codegen, &start->value, 0);
- IrInstruction *end = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, ira->codegen->builtin_types.entry_usize);
+ IrInstruction *end = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize);
init_const_usize(ira->codegen, &end->value, array_type->data.array.len);
if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false);
@@ -10469,8 +10489,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
return result;
}
@@ -10480,8 +10499,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
actual_type->data.enumeration.src_field_count == 1)
{
assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_bigint(&result->value, wanted_type,
&actual_type->data.enumeration.fields[0].value);
return result;
@@ -10504,8 +10522,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.special = ConstValSpecialStatic;
result->value.type = wanted_type;
bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_union.tag);
@@ -10516,8 +10533,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
if (wanted_type->data.enumeration.layout == ContainerLayoutAuto &&
wanted_type->data.enumeration.src_field_count == 1)
{
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.special = ConstValSpecialStatic;
result->value.type = wanted_type;
TypeEnumField *enum_field = target->value.type->data.unionation.fields[0].enum_field;
@@ -10534,8 +10550,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *target, ZigType *wanted_type)
{
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_undefined(ira->codegen, &result->value);
return result;
}
@@ -10567,8 +10582,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so
buf_sprintf("field '%s' declared here", buf_ptr(union_field->name)));
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.special = ConstValSpecialStatic;
result->value.type = wanted_type;
bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag);
@@ -10623,8 +10637,7 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction
return ira->codegen->invalid_instruction;
}
}
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.type = wanted_type;
if (wanted_type->id == ZigTypeIdInt) {
bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint);
@@ -10678,8 +10691,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint);
return result;
}
@@ -10697,8 +10709,7 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
if (wanted_type->id == ZigTypeIdComptimeFloat) {
float_init_float(&result->value, val);
} else if (wanted_type->id == ZigTypeIdComptimeInt) {
@@ -10721,8 +10732,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) {
return ira->codegen->invalid_instruction;
@@ -10786,8 +10796,7 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
ErrorTableEntry *err;
if (err_type->id == ZigTypeIdErrorUnion) {
@@ -10826,14 +10835,12 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
return ira->codegen->invalid_instruction;
}
if (err_set_type->data.error_set.err_count == 0) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.type = wanted_type;
bigint_init_unsigned(&result->value.data.x_bigint, 0);
return result;
} else if (err_set_type->data.error_set.err_count == 1) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.type = wanted_type;
ErrorTableEntry *err = err_set_type->data.error_set.errors[0];
bigint_init_unsigned(&result->value.data.x_bigint, err->value);
@@ -11397,7 +11404,9 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig
return ir_analyze_cast(ira, value, expected_type, value);
}
-static Error resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *alloca, ZigType *child_type) {
+static Error resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *alloca,
+ ZigType *child_type)
+{
Error err;
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
return err;
@@ -11408,15 +11417,29 @@ static Error resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *al
return ErrorNone;
}
-static Error resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type) {
+static IrInstruction *resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type) {
Error err;
assert(base->value.type->id == ZigTypeIdPointer);
ZigType *infer_child = base->value.type->data.pointer.child_type;
- if (base->id == IrInstructionIdAllocaGen && infer_child == ira->codegen->builtin_types.entry_infer) {
- if ((err = resolve_alloca_inference(ira, reinterpret_cast(base), child_type)))
- return err;
+ if (infer_child == ira->codegen->builtin_types.entry_infer) {
+ if (base->id == IrInstructionIdAllocaGen) {
+ if ((err = resolve_alloca_inference(ira, reinterpret_cast(base), child_type)))
+ return ira->codegen->invalid_instruction;
+ } else if (base->id == IrInstructionIdPtrCastGen) {
+ IrInstructionPtrCastGen *ptr_cast = reinterpret_cast(base);
+ // When the ptr cast instruction was made it didn't have the destination type, so
+ // we had to set it to "infer". Now we have the destination type, so we re-do
+ // analysis, and rely on the ref_count being 0 so that it is not emitted.
+ assert(ptr_cast->base.ref_count == 0);
+ ZigType *prev_ptr_type = ptr_cast->ptr->value.type;
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, false, false,
+ PtrLenSingle, prev_ptr_type->data.pointer.explicit_alignment, 0, 0);
+ IrInstruction *new_ptr_cast = ir_analyze_ptr_cast(ira, base, ptr_cast->ptr, new_ptr_type, base);
+ ptr_cast->pass1_parent->base.child = new_ptr_cast;
+ return new_ptr_cast;
+ }
}
- return ErrorNone;
+ return base;
}
static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) {
@@ -11456,13 +11479,13 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
}
-static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *result_loc,
+static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *unresolved_result_loc,
ZigType *needed_child_type, bool allow_failure)
{
- Error err;
- if (type_is_invalid(result_loc->value.type) || type_is_invalid(needed_child_type))
+ if (type_is_invalid(unresolved_result_loc->value.type) || type_is_invalid(needed_child_type))
return ira->codegen->invalid_instruction;
- if ((err = resolve_possible_alloca_inference(ira, result_loc, needed_child_type)))
+ IrInstruction *result_loc = resolve_possible_alloca_inference(ira, unresolved_result_loc, needed_child_type);
+ if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
if (needed_child_type == nullptr)
@@ -11579,8 +11602,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
ZigType *child_type = type_entry->data.pointer.child_type;
// dereferencing a *u0 is comptime known to be 0
if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, child_type);
+ IrInstruction *result = ir_const(ira, source_instruction, child_type);
init_const_unsigned_negative(&result->value, child_type, 0, false);
return result;
}
@@ -11594,8 +11616,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
{
ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
if (pointee->special != ConstValSpecialRuntime) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, child_type);
+ IrInstruction *result = ir_const(ira, source_instruction, child_type);
if ((err = ir_read_const_ptr(ira, source_instruction->source_node, &result->value,
&ptr->value)))
@@ -13739,7 +13760,9 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
return ira->codegen->invalid_instruction;
if (dest_val->special != ConstValSpecialRuntime) {
*dest_val = value->value;
- if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
+ if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr &&
+ type_has_bits(child_type))
+ {
ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
}
if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) {
@@ -14399,7 +14422,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
}
static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) {
- Error err;
IrInstruction *fn_ref = call_instruction->fn_ref->child;
if (type_is_invalid(fn_ref->value.type))
return ira->codegen->invalid_instruction;
@@ -14427,7 +14449,8 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC
IrInstruction *result_loc = call_instruction->result_loc->child;
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
- if ((err = resolve_possible_alloca_inference(ira, result_loc, dest_type)))
+ result_loc = resolve_possible_alloca_inference(ira, result_loc, dest_type);
+ if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
if (is_slice(dest_type)) {
@@ -14465,7 +14488,8 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC
IrInstruction *result_loc = call_instruction->result_loc->child;
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
- if ((err = resolve_possible_alloca_inference(ira, result_loc, dest_type)))
+ result_loc = resolve_possible_alloca_inference(ira, result_loc, dest_type);
+ if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
ir_analyze_store_ptr(ira, &call_instruction->base, result_loc, result);
return result;
@@ -15570,7 +15594,8 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
ZigType *container_type = ir_resolve_type(ira, field_ptr_instruction->container_type->child);
if (type_is_invalid(container_type))
return ira->codegen->invalid_instruction;
- if ((err = resolve_possible_alloca_inference(ira, container_ptr, container_type)))
+ container_ptr = resolve_possible_alloca_inference(ira, container_ptr, container_type);
+ if (type_is_invalid(container_ptr->value.type))
return ira->codegen->invalid_instruction;
}
@@ -19391,8 +19416,6 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
}
static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice *instruction) {
- Error err;
-
IrInstruction *ptr_ptr = instruction->ptr->child;
if (type_is_invalid(ptr_ptr->value.type))
return ira->codegen->invalid_instruction;
@@ -19466,7 +19489,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
IrInstruction *result_loc = instruction->result_loc->child;
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
- if ((err = resolve_possible_alloca_inference(ira, result_loc, return_type)))
+ result_loc = resolve_possible_alloca_inference(ira, result_loc, return_type);
+ if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
if (instr_is_comptime(ptr_ptr) &&
@@ -20673,7 +20697,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type);
+ IrInstruction *result = ir_const(ira, target, result_type);
copy_const_val(&result->value, val, false);
result->value.type = result_type;
return result;
@@ -20721,8 +20745,12 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node,
- dest_type);
+ IrInstruction *result;
+ if (val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr);
+ } else {
+ result = ir_const(ira, source_instr, dest_type);
+ }
copy_const_val(&result->value, val, false);
result->value.type = dest_type;
return result;
@@ -20745,9 +20773,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
return ira->codegen->invalid_instruction;
}
- IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope,
- source_instr->source_node, nullptr, ptr);
- casted_ptr->value.type = dest_type;
+ IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr);
if (type_has_bits(dest_type) && !type_has_bits(src_type)) {
ErrorMsg *msg = ir_add_error(ira, source_instr,
@@ -20773,7 +20799,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
return result;
}
-static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
+static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCastSrc *instruction) {
IrInstruction *dest_type_value = instruction->dest_type->child;
ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
if (type_is_invalid(dest_type))
@@ -21119,8 +21145,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru
if (!val)
return ira->codegen->invalid_instruction;
if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
- IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, usize);
+ IrInstruction *result = ir_const(ira, &instruction->base, usize);
bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr);
result->value.type = usize;
return result;
@@ -21854,8 +21879,27 @@ static IrInstruction *ir_analyze_instruction_result_param(IrAnalyze *ira, IrInst
zig_panic("TODO");
}
-static IrInstruction *ir_analyze_instruction_result_ptr_cast(IrAnalyze *ira, IrInstructionResultPtrCast *instruction) {
- zig_panic("TODO");
+static IrInstruction *ir_analyze_instruction_result_ptr_cast(IrAnalyze *ira,
+ IrInstructionResultPtrCast *instruction)
+{
+ ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child);
+ if (type_is_invalid(elem_type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = ir_implicit_cast_result(ira, prev_result_loc, elem_type, false);
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *new_ptr_type = adjust_ptr_child(ira->codegen, new_result_loc->value.type,
+ ira->codegen->builtin_types.entry_infer);
+ IrInstruction *ptr_cast = ir_build_ptr_cast_gen(ira, &instruction->base, new_ptr_type, new_result_loc);
+ reinterpret_cast(ptr_cast)->pass1_parent = instruction;
+
+ return ptr_cast;
}
static IrInstruction *ir_analyze_instruction_result_cast(IrAnalyze *ira, IrInstructionResultCast *instruction) {
@@ -21983,6 +22027,29 @@ static IrInstruction *ir_analyze_instruction_infer_array_type(IrAnalyze *ira,
return ir_const_type(ira, &instruction->base, array_type);
}
+static IrInstruction *ir_analyze_instruction_infer_comptime(IrAnalyze *ira,
+ IrInstructionInferCompTime *instruction)
+{
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = instruction->new_result_loc->child;
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ if (prev_result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(new_result_loc) &&
+ new_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ prev_result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ prev_result_loc->value.special = ConstValSpecialRuntime;
+ }
+ }
+ return ir_const_void(ira, &instruction->base);
+}
+
static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -21999,6 +22066,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdResultSlicePtr:
case IrInstructionIdResultErrorUnionPayload:
case IrInstructionIdResultErrorUnionCode:
+ case IrInstructionIdPtrCastGen:
zig_unreachable();
case IrInstructionIdReturn:
@@ -22163,8 +22231,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction);
case IrInstructionIdPanic:
return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction);
- case IrInstructionIdPtrCast:
- return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction);
+ case IrInstructionIdPtrCastSrc:
+ return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction);
case IrInstructionIdBitCast:
return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction);
case IrInstructionIdIntToPtr:
@@ -22275,6 +22343,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_first_arg_result_loc(ira, (IrInstructionFirstArgResultLoc *)instruction);
case IrInstructionIdInferArrayType:
return ir_analyze_instruction_infer_array_type(ira, (IrInstructionInferArrayType *)instruction);
+ case IrInstructionIdInferCompTime:
+ return ir_analyze_instruction_infer_comptime(ira, (IrInstructionInferCompTime *)instruction);
case IrInstructionIdResultBytesToSlice:
zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
@@ -22412,6 +22482,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdAssertNonError:
case IrInstructionIdContainerInitFields:
case IrInstructionIdContainerInitList:
+ case IrInstructionIdInferCompTime:
return true;
case IrInstructionIdPhi:
@@ -22459,7 +22530,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdErrWrapPayload:
case IrInstructionIdFnProto:
case IrInstructionIdTestComptime:
- case IrInstructionIdPtrCast:
+ case IrInstructionIdPtrCastSrc:
+ case IrInstructionIdPtrCastGen:
case IrInstructionIdBitCast:
case IrInstructionIdWidenOrShorten:
case IrInstructionIdPtrToInt:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 75ea96bbe0d5..8c208c79c8db 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -856,7 +856,7 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst
fprintf(irp->f, ")");
}
-static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
+static void ir_print_ptr_cast_src(IrPrint *irp, IrInstructionPtrCastSrc *instruction) {
fprintf(irp->f, "@ptrCast(");
if (instruction->dest_type) {
ir_print_other_instruction(irp, instruction->dest_type);
@@ -866,6 +866,12 @@ static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruction) {
+ fprintf(irp->f, "@ptrCast(");
+ ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
fprintf(irp->f, "@bitCast(");
if (instruction->dest_type) {
@@ -1346,7 +1352,11 @@ static void ir_print_result_param(IrPrint *irp, IrInstructionResultParam *instru
}
static void ir_print_result_ptr_cast(IrPrint *irp, IrInstructionResultPtrCast *instruction) {
- fprintf(irp->f, "ResultPtrCast");
+ fprintf(irp->f, "ResultPtrCast(ty=");
+ ir_print_other_instruction(irp, instruction->elem_type);
+ fprintf(irp->f, ",prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ")");
}
static void ir_print_result_cast(IrPrint *irp, IrInstructionResultCast *instruction) {
@@ -1395,6 +1405,14 @@ static void ir_print_infer_array_type(IrPrint *irp, IrInstructionInferArrayType
fprintf(irp->f, ",elem_count=%zu)", instruction->elem_count);
}
+static void ir_print_infer_comptime(IrPrint *irp, IrInstructionInferCompTime *instruction) {
+ fprintf(irp->f, "InferCompTime(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",new_result=");
+ ir_print_other_instruction(irp, instruction->new_result_loc);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1643,8 +1661,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdTestComptime:
ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction);
break;
- case IrInstructionIdPtrCast:
- ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction);
+ case IrInstructionIdPtrCastSrc:
+ ir_print_ptr_cast_src(irp, (IrInstructionPtrCastSrc *)instruction);
+ break;
+ case IrInstructionIdPtrCastGen:
+ ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction);
break;
case IrInstructionIdBitCast:
ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
@@ -1856,6 +1877,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdInferArrayType:
ir_print_infer_array_type(irp, (IrInstructionInferArrayType *)instruction);
break;
+ case IrInstructionIdInferCompTime:
+ ir_print_infer_comptime(irp, (IrInstructionInferCompTime *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
From 522780e6d637ab92dfdee1677ccf46df88f83618 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 21 Nov 2018 17:28:47 -0500
Subject: [PATCH 054/190] copy elision: @bitCast with comptime value
```zig
export fn entry() void {
const y: u32 = 1234;
var x = @bitCast(f32, y);
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%x = alloca float, align 4
call void @llvm.dbg.declare(metadata i32* @1, metadata !45, metadata !DIExpression()), !dbg !51
store float 0x3743480000000000, float* %x, align 4, !dbg !52
call void @llvm.dbg.declare(metadata float* %x, metadata !48, metadata !DIExpression()), !dbg !52
ret void, !dbg !53
}
```
---
src/all_types.hpp | 16 ----
src/codegen.cpp | 15 +---
src/ir.cpp | 212 ++++++----------------------------------------
src/ir_print.cpp | 20 -----
4 files changed, 28 insertions(+), 235 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 82b289e65845..e02161a485b6 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2132,7 +2132,6 @@ enum IrInstructionId {
IrInstructionIdTestComptime,
IrInstructionIdPtrCastSrc,
IrInstructionIdPtrCastGen,
- IrInstructionIdBitCast,
IrInstructionIdWidenOrShorten,
IrInstructionIdIntToPtr,
IrInstructionIdPtrToInt,
@@ -2193,7 +2192,6 @@ enum IrInstructionId {
IrInstructionIdResultReturn,
IrInstructionIdResultBytesToSlice,
IrInstructionIdResultSliceToBytes,
- IrInstructionIdResultParam,
IrInstructionIdResultPtrCast,
IrInstructionIdResultCast,
IrInstructionIdAllocaSrc,
@@ -2937,13 +2935,6 @@ struct IrInstructionPtrCastGen {
IrInstructionResultPtrCast *pass1_parent;
};
-struct IrInstructionBitCast {
- IrInstruction base;
-
- IrInstruction *dest_type;
- IrInstruction *value;
-};
-
struct IrInstructionWidenOrShorten {
IrInstruction base;
@@ -3337,13 +3328,6 @@ struct IrInstructionResultReturn {
IrInstruction base;
};
-struct IrInstructionResultParam {
- IrInstruction base;
-
- IrInstruction *fn_ref;
- size_t param_index;
-};
-
struct IrInstructionResultPtrCast {
IrInstruction base;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index badad23471dd..249d2963b318 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3034,14 +3034,6 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
}
-static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable,
- IrInstructionBitCast *instruction)
-{
- ZigType *wanted_type = instruction->base.value.type;
- LLVMValueRef value = ir_llvm_value(g, instruction->value);
- return LLVMBuildBitCast(g->builder, value, wanted_type->type_ref, "");
-}
-
static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable,
IrInstructionWidenOrShorten *instruction)
{
@@ -5235,6 +5227,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdInferArrayType:
case IrInstructionIdPtrCastSrc:
case IrInstructionIdInferCompTime:
+ case IrInstructionIdResultPtrCast:
zig_unreachable();
case IrInstructionIdDeclVarGen:
@@ -5329,8 +5322,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction);
case IrInstructionIdPtrCastGen:
return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction);
- case IrInstructionIdBitCast:
- return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction);
case IrInstructionIdWidenOrShorten:
return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction);
case IrInstructionIdPtrToInt:
@@ -5409,10 +5400,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
zig_panic("TODO");
case IrInstructionIdResultBytesToSlice:
zig_panic("TODO");
- case IrInstructionIdResultParam:
- zig_panic("TODO");
- case IrInstructionIdResultPtrCast:
- zig_panic("TODO");
}
zig_unreachable();
}
diff --git a/src/ir.cpp b/src/ir.cpp
index 620b53ad3db2..b6fc4536224e 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -218,9 +218,8 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
ConstExprValue *result = const_ptr_pointee_unchecked(g, const_val);
- if (const_val->type->id == ZigTypeIdPointer) {
- assert(types_have_same_zig_comptime_repr(const_val->type->data.pointer.child_type, result->type));
- }
+ assert(result != nullptr);
+ assert(const_val->type->id == ZigTypeIdPointer);
return result;
}
@@ -650,10 +649,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) {
return IrInstructionIdPtrCastGen;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) {
- return IrInstructionIdBitCast;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) {
return IrInstructionIdWidenOrShorten;
}
@@ -878,10 +873,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResultReturn *)
return IrInstructionIdResultReturn;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionResultParam *) {
- return IrInstructionIdResultParam;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtrCast *) {
return IrInstructionIdResultPtrCast;
}
@@ -2178,20 +2169,6 @@ static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *sourc
return &instruction->base;
}
-static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *dest_type, IrInstruction *value)
-{
- IrInstructionBitCast *instruction = ir_build_instruction(
- irb, scope, source_node);
- instruction->dest_type = dest_type;
- instruction->value = value;
-
- if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
- ir_ref_instruction(value, irb->current_basic_block);
-
- return &instruction->base;
-}
-
static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *target)
{
@@ -2823,17 +2800,6 @@ static IrInstruction *ir_build_result_return(IrBuilder *irb, Scope *scope, AstNo
return &instruction->base;
}
-static IrInstruction *ir_build_result_param(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *fn_ref, size_t param_index)
-{
- IrInstructionResultParam *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->fn_ref = fn_ref;
-
- ir_ref_instruction(fn_ref, irb->current_basic_block);
-
- return &instruction->base;
-}
-
static IrInstruction *ir_build_result_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *elem_type, IrInstruction *prev_result_loc)
{
@@ -4852,9 +4818,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction **args = allocate(arg_count);
for (size_t i = 0; i < arg_count; i += 1) {
- IrInstruction *param_result_loc = ir_build_result_param(irb, scope, node, fn_ref, i);
AstNode *arg_node = node->data.fn_call_expr.params.at(i + 1);
- args[i] = ir_gen_node(irb, arg_node, scope, LValNone, param_result_loc);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, nullptr);
if (args[i] == irb->codegen->invalid_instruction)
return args[i];
}
@@ -4885,9 +4850,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction **args = allocate(arg_count);
for (size_t i = 0; i < arg_count; i += 1) {
- IrInstruction *param_result_loc = ir_build_result_param(irb, scope, node, fn_ref, i);
AstNode *arg_node = node->data.fn_call_expr.params.at(i + 2);
- args[i] = ir_gen_node(irb, arg_node, scope, LValNone, param_result_loc);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, nullptr);
if (args[i] == irb->codegen->invalid_instruction)
return args[i];
}
@@ -7751,19 +7715,6 @@ static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction,
return ir_add_error_node(ira, source_instruction->source_node, msg);
}
-static ConstExprValue *ir_const_ptr_pointee(IrAnalyze *ira, ConstExprValue *const_val, AstNode *source_node) {
- ConstExprValue *val = const_ptr_pointee_unchecked(ira->codegen, const_val);
- assert(val != nullptr);
- assert(const_val->type->id == ZigTypeIdPointer);
- ZigType *expected_type = const_val->type->data.pointer.child_type;
- if (!types_have_same_zig_comptime_repr(val->type, expected_type)) {
- ir_add_error_node(ira, source_node,
- buf_sprintf("TODO handle comptime reinterpreted pointer. See https://github.com/ziglang/zig/issues/955"));
- return nullptr;
- }
- return val;
-}
-
static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) {
IrBasicBlock *bb = exec->basic_block_list.at(0);
for (size_t i = 0; i < bb->instruction_list.length; i += 1) {
@@ -9659,7 +9610,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type));
if (instr_is_comptime(value)) {
- ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node);
+ ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
if (pointee == nullptr)
return ira->codegen->invalid_instruction;
if (pointee->special != ConstValSpecialRuntime) {
@@ -9694,7 +9645,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type));
if (instr_is_comptime(value)) {
- ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node);
+ ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
if (pointee == nullptr)
return ira->codegen->invalid_instruction;
if (pointee->special != ConstValSpecialRuntime) {
@@ -10879,7 +10830,7 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou
return ira->codegen->invalid_instruction;
assert(val->type->id == ZigTypeIdPointer);
- ConstExprValue *pointee = ir_const_ptr_pointee(ira, val, source_instr->source_node);
+ ConstExprValue *pointee = const_ptr_pointee(ira->codegen, val);
if (pointee == nullptr)
return ira->codegen->invalid_instruction;
if (pointee->special != ConstValSpecialRuntime) {
@@ -13755,7 +13706,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
ptr->value.data.x_ptr.mut == ConstPtrMutInfer)
{
if (instr_is_comptime(value)) {
- ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, source_instr->source_node);
+ ConstExprValue *dest_val = const_ptr_pointee(ira->codegen, &ptr->value);
if (dest_val == nullptr)
return ira->codegen->invalid_instruction;
if (dest_val->special != ConstValSpecialRuntime) {
@@ -14973,8 +14924,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
array_type = array_type->data.pointer.child_type;
ptr_type = ptr_type->data.pointer.child_type;
if (orig_array_ptr_val->special != ConstValSpecialRuntime) {
- orig_array_ptr_val = ir_const_ptr_pointee(ira, orig_array_ptr_val,
- elem_ptr_instruction->base.source_node);
+ orig_array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val);
if (orig_array_ptr_val == nullptr)
return ira->codegen->invalid_instruction;
}
@@ -15017,7 +14967,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
ConstExprValue *ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);
if (!ptr_val)
return ira->codegen->invalid_instruction;
- ConstExprValue *args_val = ir_const_ptr_pointee(ira, ptr_val, elem_ptr_instruction->base.source_node);
+ ConstExprValue *args_val = const_ptr_pointee(ira->codegen, ptr_val);
if (args_val == nullptr)
return ira->codegen->invalid_instruction;
size_t start = args_val->data.x_arg_tuple.start_index;
@@ -15099,8 +15049,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
(orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar ||
array_type->id == ZigTypeIdArray))
{
- ConstExprValue *array_ptr_val = ir_const_ptr_pointee(ira, orig_array_ptr_val,
- elem_ptr_instruction->base.source_node);
+ ConstExprValue *array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val);
if (array_ptr_val == nullptr)
return ira->codegen->invalid_instruction;
@@ -15350,7 +15299,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
return ira->codegen->invalid_instruction;
if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
- ConstExprValue *struct_val = ir_const_ptr_pointee(ira, ptr_val, source_instr->source_node);
+ ConstExprValue *struct_val = const_ptr_pointee(ira->codegen, ptr_val);
if (struct_val == nullptr)
return ira->codegen->invalid_instruction;
if (type_is_invalid(struct_val->type))
@@ -15419,7 +15368,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
return ira->codegen->invalid_instruction;
if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
- ConstExprValue *union_val = ir_const_ptr_pointee(ira, ptr_val, source_instr->source_node);
+ ConstExprValue *union_val = const_ptr_pointee(ira->codegen, ptr_val);
if (union_val == nullptr)
return ira->codegen->invalid_instruction;
if (type_is_invalid(union_val->type))
@@ -15651,7 +15600,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
return ira->codegen->invalid_instruction;
assert(container_ptr->value.type->id == ZigTypeIdPointer);
- ConstExprValue *child_val = ir_const_ptr_pointee(ira, container_ptr_val, source_node);
+ ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val);
if (child_val == nullptr)
return ira->codegen->invalid_instruction;
@@ -15677,7 +15626,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
return ira->codegen->invalid_instruction;
assert(container_ptr->value.type->id == ZigTypeIdPointer);
- ConstExprValue *child_val = ir_const_ptr_pointee(ira, container_ptr_val, source_node);
+ ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val);
if (child_val == nullptr)
return ira->codegen->invalid_instruction;
ZigType *child_type = child_val->data.x_type;
@@ -15952,8 +15901,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
if (!container_ptr_val)
return ira->codegen->invalid_instruction;
- ConstExprValue *namespace_val = ir_const_ptr_pointee(ira, container_ptr_val,
- field_ptr_instruction->base.source_node);
+ ConstExprValue *namespace_val = const_ptr_pointee(ira->codegen, container_ptr_val);
if (namespace_val == nullptr)
return ira->codegen->invalid_instruction;
assert(namespace_val->special == ConstValSpecialStatic);
@@ -16527,7 +16475,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- ConstExprValue *maybe_val = ir_const_ptr_pointee(ira, val, unwrap_maybe_instruction->base.source_node);
+ ConstExprValue *maybe_val = const_ptr_pointee(ira->codegen, val);
if (maybe_val == nullptr)
return ira->codegen->invalid_instruction;
@@ -16841,7 +16789,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type;
ConstExprValue *pointee_val = nullptr;
if (instr_is_comptime(target_value_ptr)) {
- pointee_val = ir_const_ptr_pointee(ira, &target_value_ptr->value, target_value_ptr->source_node);
+ pointee_val = const_ptr_pointee(ira->codegen, &target_value_ptr->value);
if (pointee_val == nullptr)
return ira->codegen->invalid_instruction;
@@ -16976,7 +16924,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
if (!target_value_ptr)
return ira->codegen->invalid_instruction;
- ConstExprValue *pointee_val = ir_const_ptr_pointee(ira, target_val_ptr, instruction->base.source_node);
+ ConstExprValue *pointee_val = const_ptr_pointee(ira->codegen, target_val_ptr);
if (pointee_val == nullptr)
return ira->codegen->invalid_instruction;
@@ -19508,18 +19456,18 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
if (array_type->id == ZigTypeIdPointer) {
ZigType *child_array_type = array_type->data.pointer.child_type;
assert(child_array_type->id == ZigTypeIdArray);
- parent_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node);
+ parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
if (parent_ptr == nullptr)
return ira->codegen->invalid_instruction;
- array_val = ir_const_ptr_pointee(ira, parent_ptr, instruction->base.source_node);
+ array_val = const_ptr_pointee(ira->codegen, parent_ptr);
if (array_val == nullptr)
return ira->codegen->invalid_instruction;
rel_end = child_array_type->data.array.len;
abs_offset = 0;
} else {
- array_val = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node);
+ array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
if (array_val == nullptr)
return ira->codegen->invalid_instruction;
rel_end = array_type->data.array.len;
@@ -19528,7 +19476,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
}
} else if (array_type->id == ZigTypeIdPointer) {
assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
- parent_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node);
+ parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
if (parent_ptr == nullptr)
return ira->codegen->invalid_instruction;
@@ -19572,7 +19520,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
zig_panic("TODO slice of ptr cast from function");
}
} else if (is_slice(array_type)) {
- ConstExprValue *slice_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node);
+ ConstExprValue *slice_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
if (slice_ptr == nullptr)
return ira->codegen->invalid_instruction;
@@ -20002,7 +19950,7 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr
{
BigInt *op1_bigint = &casted_op1->value.data.x_bigint;
BigInt *op2_bigint = &casted_op2->value.data.x_bigint;
- ConstExprValue *pointee_val = ir_const_ptr_pointee(ira, &casted_result_ptr->value, casted_result_ptr->source_node);
+ ConstExprValue *pointee_val = const_ptr_pointee(ira->codegen, &casted_result_ptr->value);
if (pointee_val == nullptr)
return ira->codegen->invalid_instruction;
BigInt *dest_bigint = &pointee_val->data.x_bigint;
@@ -20173,7 +20121,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
if (!ptr_val)
return ira->codegen->invalid_instruction;
- ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node);
+ ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val);
if (err_union_val == nullptr)
return ira->codegen->invalid_instruction;
if (err_union_val->special != ConstValSpecialRuntime) {
@@ -20226,7 +20174,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
if (!ptr_val)
return ira->codegen->invalid_instruction;
if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
- ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node);
+ ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val);
if (err_union_val == nullptr)
return ira->codegen->invalid_instruction;
if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer &&
@@ -20940,102 +20888,6 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
zig_unreachable();
}
-static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) {
- Error err;
- IrInstruction *dest_type_value = instruction->dest_type->child;
- ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
- if (type_is_invalid(dest_type))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *value = instruction->value->child;
- ZigType *src_type = value->value.type;
- if (type_is_invalid(src_type))
- return ira->codegen->invalid_instruction;
-
- if ((err = ensure_complete_type(ira->codegen, dest_type)))
- return ira->codegen->invalid_instruction;
-
- if ((err = ensure_complete_type(ira->codegen, src_type)))
- return ira->codegen->invalid_instruction;
-
- if (get_codegen_ptr_type(src_type) != nullptr) {
- ir_add_error(ira, value,
- buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- switch (src_type->id) {
- case ZigTypeIdInvalid:
- case ZigTypeIdMetaType:
- case ZigTypeIdOpaque:
- case ZigTypeIdBoundFn:
- case ZigTypeIdArgTuple:
- case ZigTypeIdNamespace:
- case ZigTypeIdUnreachable:
- case ZigTypeIdComptimeFloat:
- case ZigTypeIdComptimeInt:
- case ZigTypeIdUndefined:
- case ZigTypeIdNull:
- ir_add_error(ira, dest_type_value,
- buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name)));
- return ira->codegen->invalid_instruction;
- default:
- break;
- }
-
- if (get_codegen_ptr_type(dest_type) != nullptr) {
- ir_add_error(ira, dest_type_value,
- buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- switch (dest_type->id) {
- case ZigTypeIdInvalid:
- case ZigTypeIdMetaType:
- case ZigTypeIdOpaque:
- case ZigTypeIdBoundFn:
- case ZigTypeIdArgTuple:
- case ZigTypeIdNamespace:
- case ZigTypeIdUnreachable:
- case ZigTypeIdComptimeFloat:
- case ZigTypeIdComptimeInt:
- case ZigTypeIdUndefined:
- case ZigTypeIdNull:
- ir_add_error(ira, dest_type_value,
- buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name)));
- return ira->codegen->invalid_instruction;
- default:
- break;
- }
-
- uint64_t dest_size_bytes = type_size(ira->codegen, dest_type);
- uint64_t src_size_bytes = type_size(ira->codegen, src_type);
- if (dest_size_bytes != src_size_bytes) {
- ir_add_error(ira, &instruction->base,
- buf_sprintf("destination type '%s' has size %" ZIG_PRI_u64 " but source type '%s' has size %" ZIG_PRI_u64,
- buf_ptr(&dest_type->name), dest_size_bytes,
- buf_ptr(&src_type->name), src_size_bytes));
- return ira->codegen->invalid_instruction;
- }
-
- if (instr_is_comptime(value)) {
- ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
- if (!val)
- return ira->codegen->invalid_instruction;
-
- IrInstruction *result = ir_const(ira, &instruction->base, dest_type);
- uint8_t *buf = allocate_nonzero(src_size_bytes);
- buf_write_value_bytes(ira->codegen, buf, val);
- buf_read_value_bytes(ira->codegen, buf, &result->value);
- return result;
- }
-
- IrInstruction *result = ir_build_bit_cast(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, nullptr, value);
- result->value.type = dest_type;
- return result;
-}
-
static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) {
Error err;
IrInstruction *dest_type_value = instruction->dest_type->child;
@@ -21875,10 +21727,6 @@ static IrInstruction *ir_analyze_instruction_result_return(IrAnalyze *ira, IrIns
return result;
}
-static IrInstruction *ir_analyze_instruction_result_param(IrAnalyze *ira, IrInstructionResultParam *instruction) {
- zig_panic("TODO");
-}
-
static IrInstruction *ir_analyze_instruction_result_ptr_cast(IrAnalyze *ira,
IrInstructionResultPtrCast *instruction)
{
@@ -22233,8 +22081,6 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction);
case IrInstructionIdPtrCastSrc:
return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction);
- case IrInstructionIdBitCast:
- return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction);
case IrInstructionIdIntToPtr:
return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction);
case IrInstructionIdPtrToInt:
@@ -22329,8 +22175,6 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction);
case IrInstructionIdResultReturn:
return ir_analyze_instruction_result_return(ira, (IrInstructionResultReturn *)instruction);
- case IrInstructionIdResultParam:
- return ir_analyze_instruction_result_param(ira, (IrInstructionResultParam *)instruction);
case IrInstructionIdResultPtrCast:
return ir_analyze_instruction_result_ptr_cast(ira, (IrInstructionResultPtrCast *)instruction);
case IrInstructionIdResultCast:
@@ -22532,7 +22376,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdTestComptime:
case IrInstructionIdPtrCastSrc:
case IrInstructionIdPtrCastGen:
- case IrInstructionIdBitCast:
case IrInstructionIdWidenOrShorten:
case IrInstructionIdPtrToInt:
case IrInstructionIdIntToPtr:
@@ -22575,7 +22418,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdResultErrorUnionPayload:
case IrInstructionIdResultErrorUnionCode:
case IrInstructionIdResultReturn:
- case IrInstructionIdResultParam:
case IrInstructionIdResultPtrCast:
case IrInstructionIdResultCast:
case IrInstructionIdResultSliceToBytes:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 8c208c79c8db..afc3452c0e67 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -872,16 +872,6 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc
fprintf(irp->f, ")");
}
-static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
- fprintf(irp->f, "@bitCast(");
- if (instruction->dest_type) {
- ir_print_other_instruction(irp, instruction->dest_type);
- }
- fprintf(irp->f, ",");
- ir_print_other_instruction(irp, instruction->value);
- fprintf(irp->f, ")");
-}
-
static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
fprintf(irp->f, "WidenOrShorten(");
ir_print_other_instruction(irp, instruction->target);
@@ -1347,10 +1337,6 @@ static void ir_print_result_slice_to_bytes(IrPrint *irp, IrInstructionResultSlic
fprintf(irp->f, "ResultSliceToBytes");
}
-static void ir_print_result_param(IrPrint *irp, IrInstructionResultParam *instruction) {
- fprintf(irp->f, "ResultParam");
-}
-
static void ir_print_result_ptr_cast(IrPrint *irp, IrInstructionResultPtrCast *instruction) {
fprintf(irp->f, "ResultPtrCast(ty=");
ir_print_other_instruction(irp, instruction->elem_type);
@@ -1667,9 +1653,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdPtrCastGen:
ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction);
break;
- case IrInstructionIdBitCast:
- ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
- break;
case IrInstructionIdWidenOrShorten:
ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction);
break;
@@ -1850,9 +1833,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdResultSliceToBytes:
ir_print_result_slice_to_bytes(irp, (IrInstructionResultSliceToBytes *)instruction);
break;
- case IrInstructionIdResultParam:
- ir_print_result_param(irp, (IrInstructionResultParam *)instruction);
- break;
case IrInstructionIdResultPtrCast:
ir_print_result_ptr_cast(irp, (IrInstructionResultPtrCast *)instruction);
break;
From 34f3d74cad873df9ba787bcedcf79e4a86f3d948 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 23 Nov 2018 10:46:56 -0500
Subject: [PATCH 055/190] copy elision: fix simple int cast
```zig
export fn entry() void {
var status: i32 = 12;
var x = isize(status);
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%status = alloca i32, align 4
%x = alloca i64, align 8
store i32 12, i32* %status, align 4, !dbg !51
call void @llvm.dbg.declare(metadata i32* %status, metadata !45, metadata !DIExpression()), !dbg !51
%0 = load i32, i32* %status, align 4, !dbg !52
%1 = sext i32 %0 to i64, !dbg !52
store i64 %1, i64* %x, align 8, !dbg !53
call void @llvm.dbg.declare(metadata i64* %x, metadata !48, metadata !DIExpression()), !dbg !54
ret void, !dbg !55
}
```
---
src/ir.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index b6fc4536224e..55ef5480c6bb 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3861,6 +3861,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
buf_ptr(variable_name)));
return irb->codegen->invalid_instruction;
}
+ assert(err == ErrorPrimitiveTypeNotFound);
} else {
IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type);
return ir_gen_value(irb, scope, node, lval, result_loc, value);
@@ -15952,7 +15953,7 @@ static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruct
return ira->codegen->invalid_instruction;
IrInstruction *deref = ir_get_deref(ira, &instruction->base, ptr);
- if (instruction->result_loc == nullptr)
+ if (instruction->result_loc == nullptr || instruction->result_loc->child == nullptr)
return deref;
IrInstruction *result_loc = instruction->result_loc->child;
From b190b8f407d9285903d8b468fba61d52a5bceb1d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 23 Nov 2018 10:55:12 -0500
Subject: [PATCH 056/190] copy elision: fix @typeName
---
src/all_types.hpp | 1 -
src/ir.cpp | 8 +++-----
2 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index e02161a485b6..d293c7e06675 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -3003,7 +3003,6 @@ struct IrInstructionTypeName {
IrInstruction base;
IrInstruction *type_value;
- IrInstruction *result_loc;
};
enum LVal {
diff --git a/src/ir.cpp b/src/ir.cpp
index 55ef5480c6bb..91a3de0ddebf 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -2292,15 +2292,13 @@ static IrInstruction *ir_build_check_statement_is_void(IrBuilder *irb, Scope *sc
}
static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *type_value, IrInstruction *result_loc)
+ IrInstruction *type_value)
{
IrInstructionTypeName *instruction = ir_build_instruction(
irb, scope, source_node);
instruction->type_value = type_value;
- instruction->result_loc = result_loc;
ir_ref_instruction(type_value, irb->current_basic_block);
- ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -4657,7 +4655,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value, result_loc);
+ IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value);
return ir_gen_value(irb, scope, node, lval, result_loc, type_name);
}
case BuiltinFnIdPanic:
@@ -21824,7 +21822,7 @@ static IrInstruction *ir_analyze_instruction_first_arg_result_loc(IrAnalyze *ira
if (type_is_invalid(dest_type))
return ira->codegen->invalid_instruction;
- if (!handle_is_ptr(dest_type)) {
+ if (!type_has_bits(dest_type) || !handle_is_ptr(dest_type)) {
return nullptr;
}
From 094d3f2df7da25ffeb7ffd17973251bc7eec58ae Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 23 Nov 2018 11:11:56 -0500
Subject: [PATCH 057/190] copy elision: fix slicing
the slice ir instruction now is specified to have side effects.
---
src/ir.cpp | 2 +-
src/ir_print.cpp | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 91a3de0ddebf..354be08c5ba6 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -22326,6 +22326,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdContainerInitFields:
case IrInstructionIdContainerInitList:
case IrInstructionIdInferCompTime:
+ case IrInstructionIdSlice:
return true;
case IrInstructionIdPhi:
@@ -22358,7 +22359,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdTruncate:
case IrInstructionIdIntType:
case IrInstructionIdBoolNot:
- case IrInstructionIdSlice:
case IrInstructionIdMemberCount:
case IrInstructionIdMemberType:
case IrInstructionIdMemberName:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index afc3452c0e67..0b48de20a883 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -718,7 +718,8 @@ static void ir_print_slice(IrPrint *irp, IrInstructionSlice *instruction) {
fprintf(irp->f, "..");
if (instruction->end)
ir_print_other_instruction(irp, instruction->end);
- fprintf(irp->f, "]");
+ fprintf(irp->f, "] result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
}
static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instruction) {
From e15e31094bc4b183e481e4a5b6d4edb69baef490 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 23 Nov 2018 12:48:22 -0500
Subject: [PATCH 058/190] copy elision: better slice codegen
```zig
export fn entry() void {
var envp_optional: [*]?[*]u8 = undefined;
var envp_count: usize = 0;
var envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count];
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%envp_optional = alloca i8**, align 8
%envp_count = alloca i64, align 8
%envp = alloca %"[][*]u8", align 8
call void @llvm.dbg.declare(metadata i8*** %envp_optional, metadata !45, metadata !DIExpression()), !dbg !57
store i64 0, i64* %envp_count, align 8, !dbg !58
call void @llvm.dbg.declare(metadata i64* %envp_count, metadata !48, metadata !DIExpression()), !dbg !58
%0 = load i8**, i8*** %envp_optional, align 8, !dbg !59
%1 = load i64, i64* %envp_count, align 8, !dbg !60
%2 = getelementptr inbounds %"[][*]u8", %"[][*]u8"* %envp, i32 0, i32 0, !dbg !61
%3 = getelementptr inbounds i8*, i8** %0, i64 0, !dbg !61
store i8** %3, i8*** %2, align 8, !dbg !61
%4 = getelementptr inbounds %"[][*]u8", %"[][*]u8"* %envp, i32 0, i32 1, !dbg !61
%5 = sub nsw i64 %1, 0, !dbg !61
store i64 %5, i64* %4, align 8, !dbg !61
ret void, !dbg !62
}
```
---
src/codegen.cpp | 7 ++----
src/ir.cpp | 63 +++++++++++++++++++++++++++++++-----------------
src/ir_print.cpp | 2 ++
3 files changed, 45 insertions(+), 27 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 249d2963b318..0e72daffe439 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -4333,11 +4333,8 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns
}
static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) {
- LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr);
- ZigType *array_ptr_type = instruction->ptr->value.type;
- assert(array_ptr_type->id == ZigTypeIdPointer);
- ZigType *array_type = array_ptr_type->data.pointer.child_type;
- LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
+ LLVMValueRef array_ptr = ir_llvm_value(g, instruction->ptr);
+ ZigType *array_type = instruction->ptr->value.type;
LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
assert(LLVMGetTypeKind(LLVMTypeOf(tmp_struct_ptr)) == LLVMPointerTypeKind);
diff --git a/src/ir.cpp b/src/ir.cpp
index 354be08c5ba6..3687b221b14f 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1722,14 +1722,16 @@ static IrInstruction *ir_build_import(IrBuilder *irb, Scope *scope, AstNode *sou
}
static IrInstruction *ir_build_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value,
- bool is_const, bool is_volatile)
+ bool is_const, bool is_volatile, IrInstruction *result_loc)
{
IrInstructionRef *instruction = ir_build_instruction(irb, scope, source_node);
instruction->value = value;
instruction->is_const = is_const;
instruction->is_volatile = is_volatile;
+ instruction->result_loc = result_loc;
ir_ref_instruction(value, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -3155,6 +3157,12 @@ static IrInstruction *ir_gen_multi(IrBuilder *irb, Scope *scope, AstNode *node,
zig_unreachable();
}
+static IrInstruction *ensure_result_loc(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
+ if (result_loc)
+ return result_loc;
+ return ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
+}
+
static IrInstruction *ir_gen_value(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc, IrInstruction *value)
{
@@ -3171,7 +3179,7 @@ static IrInstruction *ir_gen_value(IrBuilder *irb, Scope *scope, AstNode *node,
case LValPtr:
// We needed a pointer to a value, but we got a value. So we create
// an instruction which just makes a pointer of it.
- return ir_build_ref(irb, scope, value->source_node, value, false, false);
+ return ir_build_ref(irb, scope, value->source_node, value, false, false, result_loc);
case LValNone:
return value;
case LValOptional:
@@ -3406,12 +3414,6 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n
return var;
}
-static IrInstruction *ensure_result_loc(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *result_loc) {
- if (result_loc)
- return result_loc;
- return ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
-}
-
static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node, LVal lval,
IrInstruction *result_loc)
{
@@ -5482,7 +5484,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node,
err_union_ptr, false);
IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ?
- ir_build_ref(irb, payload_scope, symbol_node, payload_ptr, true, false) : payload_ptr;
+ ir_build_ref(irb, payload_scope, symbol_node, payload_ptr, true, false, nullptr) : payload_ptr;
ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_ptr);
}
@@ -5559,7 +5561,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, body_block);
IrInstruction *payload_ptr = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ?
- ir_build_ref(irb, child_scope, symbol_node, payload_ptr, true, false) : payload_ptr;
+ ir_build_ref(irb, child_scope, symbol_node, payload_ptr, true, false, nullptr) : payload_ptr;
ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_ptr);
ZigList incoming_values = {0};
@@ -5747,7 +5749,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_set_cursor_at_end_and_append_block(irb, body_block);
IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false, PtrLenSingle);
IrInstruction *elem_var_ptr = node->data.for_expr.elem_is_ptr ?
- ir_build_ref(irb, child_scope, elem_node, elem_ptr, true, false) : elem_ptr;
+ ir_build_ref(irb, child_scope, elem_node, elem_ptr, true, false, nullptr) : elem_ptr;
ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, elem_var_ptr);
ZigList incoming_values = {0};
@@ -5970,7 +5972,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
IrInstruction *payload_ptr = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
IrInstruction *var_ptr = var_is_ptr ?
- ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr;
+ ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false, nullptr) : payload_ptr;
ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_ptr);
var_scope = var->child_scope;
} else {
@@ -6045,7 +6047,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);
IrInstruction *var_ptr = var_is_ptr ?
- ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr;
+ ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false, nullptr) : payload_ptr;
ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_ptr);
var_scope = var->child_scope;
} else {
@@ -6115,7 +6117,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
IrInstruction *payload_ptr = (prong_value == nullptr) ? target_value_ptr :
ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
IrInstruction *var_ptr = var_is_ptr ?
- ir_build_ref(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr;
+ ir_build_ref(irb, scope, var_symbol_node, payload_ptr, true, false, nullptr) : payload_ptr;
ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_ptr);
child_scope = var->child_scope;
} else {
@@ -7655,7 +7657,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
- IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
+ IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false, nullptr);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr, nullptr);
IrInstruction *mem_slice_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "");
@@ -10344,7 +10346,7 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so
}
static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value,
- bool is_const, bool is_volatile)
+ bool is_const, bool is_volatile, IrInstruction *result_loc)
{
Error err;
@@ -10365,7 +10367,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type,
is_const, is_volatile, PtrLenSingle, 0, 0, 0);
IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, value, is_const, is_volatile);
+ source_instruction->source_node, value, is_const, is_volatile, result_loc);
new_instruction->value.type = ptr_type;
new_instruction->value.data.rh_ptr = RuntimeHintPtrStack;
return new_instruction;
@@ -10402,7 +10404,7 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
IrInstruction *end = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize);
init_const_usize(ira->codegen, &end->value, array_type->data.array.len);
- if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false);
+ if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false, nullptr);
// TODO don't pass nullptr to ir_build_slice
BREAKPOINT;
@@ -11320,7 +11322,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ira->codegen->invalid_instruction;
}
if (!type_has_bits(actual_type)) {
- return ir_get_ref(ira, source_instr, value, false, false);
+ return ir_get_ref(ira, source_instr, value, false, false, nullptr);
}
}
@@ -15251,7 +15253,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, source_instr->scope,
source_instr->source_node, fn_entry, container_ptr);
- return ir_get_ref(ira, source_instr, bound_fn_value, true, false);
+ return ir_get_ref(ira, source_instr, bound_fn_value, true, false, nullptr);
}
}
const char *prefix_name;
@@ -17027,7 +17029,14 @@ static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRe
IrInstruction *value = ref_instruction->value->child;
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- return ir_get_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile);
+ IrInstruction *result_loc = nullptr;
+ if (ref_instruction->result_loc != nullptr) {
+ result_loc = ref_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ }
+ return ir_get_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile,
+ result_loc);
}
static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction,
@@ -19393,6 +19402,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
}
ZigType *return_type;
+ IrInstruction *ptr;
if (array_type->id == ZigTypeIdArray) {
bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic &&
@@ -19403,7 +19413,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
PtrLenUnknown,
ptr_type->data.pointer.explicit_alignment, 0, 0);
return_type = get_slice_type(ira->codegen, slice_ptr_type);
+ ptr = ptr_ptr;
} else if (array_type->id == ZigTypeIdPointer) {
+ assert(ptr_ptr->id == IrInstructionIdRef);
+ IrInstructionRef *ref_inst = reinterpret_cast(ptr_ptr);
+ ptr = ref_inst->value;
+
if (array_type->data.pointer.ptr_len == PtrLenSingle) {
ZigType *main_type = array_type->data.pointer.child_type;
if (main_type->id == ZigTypeIdArray) {
@@ -19425,6 +19440,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
}
}
} else if (is_slice(array_type)) {
+ assert(ptr_ptr->id == IrInstructionIdRef);
+ IrInstructionRef *ref_inst = reinterpret_cast(ptr_ptr);
+ ptr = ref_inst->value;
ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
return_type = get_slice_type(ira->codegen, ptr_type);
} else {
@@ -19440,6 +19458,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
+ // TODO make this use ptr not ptr_ptr
if (instr_is_comptime(ptr_ptr) &&
value_is_comptime(&casted_start->value) &&
(!end || value_is_comptime(&end->value)))
@@ -19658,7 +19677,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
IrInstruction *new_instruction = ir_build_slice(&ira->new_irb,
instruction->base.scope, instruction->base.source_node,
- ptr_ptr, casted_start, end, instruction->safety_check_on,
+ ptr, casted_start, end, instruction->safety_check_on,
result_loc);
new_instruction->value.type = return_type;
return new_instruction;
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 0b48de20a883..121b5b0b1935 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -549,6 +549,8 @@ static void ir_print_ref(IrPrint *irp, IrInstructionRef *instruction) {
const char *volatile_str = instruction->is_volatile ? "volatile " : "";
fprintf(irp->f, "%s%sref ", const_str, volatile_str);
ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, " result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
}
static void ir_print_compile_err(IrPrint *irp, IrInstructionCompileErr *instruction) {
From baedbf5de5692d487c37ff55dc93f338f6a5d8a6 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 23 Nov 2018 12:56:47 -0500
Subject: [PATCH 059/190] copy elision: better slice analysis
when slicing slices and pointers,
don't assume the ptr instruction is a ref,
but handle it optimally if it is
---
src/ir.cpp | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 3687b221b14f..8ea8b4340748 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -11580,7 +11580,11 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
}
}
}
- // TODO if the instruction is a const ref instruction we can skip it
+ // if the instruction is a const ref instruction we can skip it
+ if (ptr->id == IrInstructionIdRef) {
+ IrInstructionRef *ref_inst = reinterpret_cast(ptr);
+ return ref_inst->value;
+ }
IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope,
source_instruction->source_node, ptr, nullptr);
load_ptr_instruction->value.type = child_type;
@@ -19415,9 +19419,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
return_type = get_slice_type(ira->codegen, slice_ptr_type);
ptr = ptr_ptr;
} else if (array_type->id == ZigTypeIdPointer) {
- assert(ptr_ptr->id == IrInstructionIdRef);
- IrInstructionRef *ref_inst = reinterpret_cast(ptr_ptr);
- ptr = ref_inst->value;
+ ptr = ir_get_deref(ira, &instruction->base, ptr_ptr);
+ if (type_is_invalid(ptr->value.type))
+ return ira->codegen->invalid_instruction;
if (array_type->data.pointer.ptr_len == PtrLenSingle) {
ZigType *main_type = array_type->data.pointer.child_type;
@@ -19440,9 +19444,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
}
}
} else if (is_slice(array_type)) {
- assert(ptr_ptr->id == IrInstructionIdRef);
- IrInstructionRef *ref_inst = reinterpret_cast(ptr_ptr);
- ptr = ref_inst->value;
+ ptr = ir_get_deref(ira, &instruction->base, ptr_ptr);
+ if (type_is_invalid(ptr->value.type))
+ return ira->codegen->invalid_instruction;
ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
return_type = get_slice_type(ira->codegen, ptr_type);
} else {
From 2eda967e0a3db4dd41a8d8d294dc7c938c9bf123 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 23 Nov 2018 13:34:21 -0500
Subject: [PATCH 060/190] copy elision: fix `try` when no result location
---
src/ir.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 8ea8b4340748..6b1768a989e3 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3307,7 +3307,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
case ReturnKindError:
{
assert(expr_node);
- IrInstruction *err_val = ir_gen_node(irb, expr_node, scope, LValErrorUnion, result_loc);
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, expr_node, result_loc);
+ IrInstruction *err_val = ir_gen_node(irb, expr_node, scope, LValErrorUnion, ensured_result_loc);
if (err_val == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_val);
@@ -3332,7 +3333,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
}
ir_set_cursor_at_end_and_append_block(irb, continue_block);
- return ir_gen_result(irb, scope, node, lval, result_loc);
+ return ir_gen_result(irb, scope, node, lval, ensured_result_loc);
}
}
zig_unreachable();
From c53a5572deb78ea98b231cdb0c1a8ba935363bd7 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 23 Nov 2018 15:39:29 -0500
Subject: [PATCH 061/190] copy elision: fix for loop
---
src/ir.cpp | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/ir.cpp b/src/ir.cpp
index 0c26e4aada22..8c0b395c13ac 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3175,6 +3175,8 @@ static IrInstruction *ir_gen_value(IrBuilder *irb, Scope *scope, AstNode *node,
{
if (value == irb->codegen->invalid_instruction)
return value;
+ if (instr_is_unreachable(value))
+ return value;
if (result_loc != nullptr) {
ir_build_store_ptr(irb, scope, node, result_loc, value);
if (lval != LValNone) {
@@ -3500,6 +3502,13 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
return ir_gen_result(irb, parent_scope, block_node, lval, scope_block->result_loc);
} else {
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
+ if (parent_scope->id == ScopeIdLoop) {
+ if (reinterpret_cast(parent_scope)->result_loc == result_loc) {
+ // This block is a loop. We do not need to generate a value for the block
+ // returning as it is handled by the loop generation code.
+ return ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
+ }
+ }
return ir_gen_value(irb, parent_scope, block_node, lval, result_loc,
ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)));
}
From 7ab89835dbe994af2283b4870d79a2e8615cd4a7 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 23 Nov 2018 17:21:19 -0500
Subject: [PATCH 062/190] for loops: use i < N rather than i != N
empirically, LLVM handles i < N better. You can even observe it in
clang with this C code:
```c
void entry(void) {
for (unsigned i = 0; i != 10; i += 1) {
if (i == 1) break;
}
}
```
---
src/ir.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 8c0b395c13ac..cdaab42d7e35 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5760,7 +5760,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_set_cursor_at_end_and_append_block(irb, cond_block);
IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca, nullptr);
- IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpNotEq, index_val, len_val, false);
+ IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);
ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime, result_loc));
ir_set_cursor_at_end_and_append_block(irb, body_block);
From 8236c5ae172b4d087449caa1bca351dca288656d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 24 Nov 2018 11:04:40 -0500
Subject: [PATCH 063/190] copy elision: fix result optional payload for pointer
types
---
src/codegen.cpp | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 4a1fd5daf379..6ede465e57ac 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5107,9 +5107,14 @@ static LLVMValueRef ir_render_result_optional_payload(CodeGen *g, IrExecutable *
IrInstructionResultOptionalPayload *instruction)
{
LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
- LLVMValueRef nonnull_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_null_index, "");
- gen_store_untyped(g, LLVMConstInt(LLVMInt1Type(), 1, false), nonnull_ptr, 0, false);
- return LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_child_index, "");
+ ZigType *child_type = instruction->base.value.type;
+ if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
+ return prev_result_loc;
+ } else {
+ LLVMValueRef nonnull_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_null_index, "");
+ gen_store_untyped(g, LLVMConstInt(LLVMInt1Type(), 1, false), nonnull_ptr, 0, false);
+ return LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_child_index, "");
+ }
}
static LLVMValueRef ir_render_result_slice_ptr(CodeGen *g, IrExecutable *executable,
From 82c8617ca62e2f86bdc6d363ea1785e05f43b12f Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 24 Nov 2018 13:39:13 -0500
Subject: [PATCH 064/190] copy elision: fix generic functions
---
src/ir.cpp | 110 ++++++++++++++++++++++++++---------------------------
1 file changed, 55 insertions(+), 55 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index cdaab42d7e35..568becdb5317 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -13921,6 +13921,57 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
return result;
}
+static IrInstruction *analyze_runtime_call(IrAnalyze *ira, ZigType *return_type,
+ IrInstructionCall *call_instruction, ZigFn *fn_entry, IrInstruction *fn_ref, size_t call_param_count,
+ IrInstruction **casted_args, FnInline fn_inline, IrInstruction *casted_new_stack)
+{
+ IrInstruction *casted_result_loc = nullptr;
+
+ ZigType *scalar_result_type;
+ ZigType *payload_result_type;
+ if (return_type->id == ZigTypeIdErrorUnion) {
+ scalar_result_type = get_optional_type(ira->codegen, return_type->data.error_union.err_set_type);
+ payload_result_type = return_type->data.error_union.payload_type;
+ } else {
+ payload_result_type = return_type;
+ scalar_result_type = return_type;
+ }
+
+ bool need_store_ptr = (return_type == payload_result_type) && !handle_is_ptr(return_type) &&
+ call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr;
+
+ if (call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr) {
+ IrInstruction *prev_result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if (instr_is_comptime(prev_result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, prev_result_loc, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr_val->special = ConstValSpecialRuntime;
+ }
+ }
+
+ casted_result_loc = ir_implicit_cast_result(ira, prev_result_loc, payload_result_type, need_store_ptr);
+ if (casted_result_loc == nullptr)
+ casted_result_loc = prev_result_loc;
+ if (type_is_invalid(casted_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ }
+
+ IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
+ call_instruction->base.scope, call_instruction->base.source_node,
+ fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
+ casted_new_stack, casted_result_loc, nullptr);
+ new_call_instruction->value.type = scalar_result_type;
+
+ if (need_store_ptr) {
+ ir_analyze_store_ptr(ira, &call_instruction->base, casted_result_loc, new_call_instruction);
+ }
+
+ return ir_finish_anal(ira, new_call_instruction);
+}
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref,
@@ -14401,15 +14452,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
return ir_finish_anal(ira, result);
}
- assert(async_allocator_inst == nullptr);
- IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
- call_instruction->base.scope, call_instruction->base.source_node,
- impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
- call_instruction->is_async, nullptr, casted_new_stack, nullptr, nullptr);
- new_call_instruction->value.type = return_type;
-
-
- return ir_finish_anal(ira, new_call_instruction);
+ return analyze_runtime_call(ira, return_type, call_instruction, impl_fn, nullptr,
+ impl_param_count, casted_args, fn_inline, casted_new_stack);
}
ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
@@ -14501,52 +14545,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
return ira->codegen->invalid_instruction;
}
- IrInstruction *casted_result_loc = nullptr;
-
- ZigType *scalar_result_type;
- ZigType *payload_result_type;
- if (return_type->id == ZigTypeIdErrorUnion) {
- scalar_result_type = get_optional_type(ira->codegen, return_type->data.error_union.err_set_type);
- payload_result_type = return_type->data.error_union.payload_type;
- } else {
- payload_result_type = return_type;
- scalar_result_type = return_type;
- }
-
- bool need_store_ptr = (return_type == payload_result_type) && !handle_is_ptr(return_type) &&
- call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr;
-
- if (call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr) {
- IrInstruction *prev_result_loc = call_instruction->result_loc->child;
- if (type_is_invalid(prev_result_loc->value.type))
- return ira->codegen->invalid_instruction;
- if (instr_is_comptime(prev_result_loc)) {
- ConstExprValue *ptr_val = ir_resolve_const(ira, prev_result_loc, UndefBad);
- if (!ptr_val)
- return ira->codegen->invalid_instruction;
- if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
- ptr_val->special = ConstValSpecialRuntime;
- }
- }
-
- casted_result_loc = ir_implicit_cast_result(ira, prev_result_loc, payload_result_type, need_store_ptr);
- if (casted_result_loc == nullptr)
- casted_result_loc = prev_result_loc;
- if (type_is_invalid(casted_result_loc->value.type))
- return ira->codegen->invalid_instruction;
- }
-
- IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
- call_instruction->base.scope, call_instruction->base.source_node,
- fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
- casted_new_stack, casted_result_loc, nullptr);
- new_call_instruction->value.type = scalar_result_type;
-
- if (need_store_ptr) {
- ir_analyze_store_ptr(ira, &call_instruction->base, casted_result_loc, new_call_instruction);
- }
-
- return ir_finish_anal(ira, new_call_instruction);
+ return analyze_runtime_call(ira, return_type, call_instruction, fn_entry, fn_ref,
+ call_param_count, casted_args, fn_inline, casted_new_stack);
}
static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) {
From 05a325e81bbe5d8a1951f86406aa0c4800bd2256 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 25 Nov 2018 11:05:38 -0500
Subject: [PATCH 065/190] copy elision: fix switch when no result location for
target
---
src/ir.cpp | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 568becdb5317..c7eeb5ddc34d 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3133,6 +3133,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_gen_result(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
IrInstruction *result_loc)
{
+ assert(result_loc != nullptr);
switch (lval) {
case LValNone:
return ir_build_load_ptr(irb, scope, node, result_loc, nullptr);
@@ -3151,8 +3152,13 @@ static IrInstruction *ir_gen_multi(IrBuilder *irb, Scope *scope, AstNode *node,
switch (lval) {
case LValNone:
return value;
- case LValPtr:
- return result_loc;
+ case LValPtr: {
+ if (result_loc != nullptr)
+ return result_loc;
+ // We needed a pointer to a value, but we got a value. So we create
+ // an instruction which just makes a pointer of it.
+ return ir_build_ref(irb, scope, value->source_node, value, false, false, nullptr);
+ }
case LValErrorUnion:
case LValOptional: {
IrInstruction *err_alloca = ir_build_alloca_src(irb, scope, value->source_node,
@@ -17008,9 +17014,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
- IrInstruction *result = ir_build_load_ptr(&ira->new_irb,
- switch_target_instruction->base.scope, switch_target_instruction->base.source_node,
- target_value_ptr, nullptr);
+ IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
result->value.type = target_type;
return result;
}
@@ -17040,8 +17044,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
- IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr, nullptr);
+ IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
union_value->value.type = target_type;
IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope,
@@ -17065,8 +17068,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
- IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr, nullptr);
+ IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
enum_value->value.type = target_type;
return enum_value;
}
From 252938c8b223970ae06814ed60b7f128b6bc6d70 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 25 Nov 2018 11:36:10 -0500
Subject: [PATCH 066/190] copy elision: comptime slice
```zig
export fn entry() void {
var slice = "aoeu"[0..1];
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%slice = alloca %"[]u8", align 8
%0 = bitcast %"[]u8"* %slice to i8*, !dbg !47
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 bitcast (%"[]u8"* @2 to i8*), i64 16, i1 false), !dbg !47
call void @llvm.dbg.declare(metadata %"[]u8"* %slice, metadata !45, metadata !DIExpression()), !dbg !47
ret void, !dbg !48
}
```
---
src/ir.cpp | 35 ++++++++++++++++-------------------
1 file changed, 16 insertions(+), 19 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index c7eeb5ddc34d..84b45c938e31 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -19566,9 +19566,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
if (type_is_invalid(ptr_ptr->value.type))
return ira->codegen->invalid_instruction;
- ZigType *ptr_type = ptr_ptr->value.type;
- assert(ptr_type->id == ZigTypeIdPointer);
- ZigType *array_type = ptr_type->data.pointer.child_type;
+ ZigType *ptr_ptr_type = ptr_ptr->value.type;
+ assert(ptr_ptr_type->id == ZigTypeIdPointer);
+ ZigType *array_type = ptr_ptr_type->data.pointer.child_type;
IrInstruction *start = instruction->start->child;
if (type_is_invalid(start->value.type))
@@ -19591,18 +19591,17 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
end = nullptr;
}
- ZigType *return_type;
+ ZigType *slice_ptr_type;
IrInstruction *ptr;
if (array_type->id == ZigTypeIdArray) {
bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic &&
ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst;
- ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
- ptr_type->data.pointer.is_const || is_comptime_const,
- ptr_type->data.pointer.is_volatile,
+ slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
+ ptr_ptr_type->data.pointer.is_const || is_comptime_const,
+ ptr_ptr_type->data.pointer.is_volatile,
PtrLenUnknown,
- ptr_type->data.pointer.explicit_alignment, 0, 0);
- return_type = get_slice_type(ira->codegen, slice_ptr_type);
+ ptr_ptr_type->data.pointer.explicit_alignment, 0, 0);
ptr = ptr_ptr;
} else if (array_type->id == ZigTypeIdPointer) {
ptr = ir_get_deref(ira, &instruction->base, ptr_ptr);
@@ -19612,18 +19611,17 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
if (array_type->data.pointer.ptr_len == PtrLenSingle) {
ZigType *main_type = array_type->data.pointer.child_type;
if (main_type->id == ZigTypeIdArray) {
- ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen,
+ slice_ptr_type = get_pointer_to_type_extra(ira->codegen,
main_type->data.pointer.child_type,
array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
PtrLenUnknown,
array_type->data.pointer.explicit_alignment, 0, 0);
- return_type = get_slice_type(ira->codegen, slice_ptr_type);
} else {
ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer"));
return ira->codegen->invalid_instruction;
}
} else {
- return_type = get_slice_type(ira->codegen, array_type);
+ slice_ptr_type = array_type;
if (!end) {
ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
return ira->codegen->invalid_instruction;
@@ -19633,13 +19631,13 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
ptr = ir_get_deref(ira, &instruction->base, ptr_ptr);
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
- ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
- return_type = get_slice_type(ira->codegen, ptr_type);
+ slice_ptr_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
} else {
ir_add_error(ira, &instruction->base,
buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name)));
return ira->codegen->invalid_instruction;
}
+ ZigType *return_type = get_slice_type(ira->codegen, slice_ptr_type);
IrInstruction *result_loc = instruction->result_loc->child;
if (type_is_invalid(result_loc->value.type))
@@ -19648,7 +19646,6 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
- // TODO make this use ptr not ptr_ptr
if (instr_is_comptime(ptr_ptr) &&
value_is_comptime(&casted_start->value) &&
(!end || value_is_comptime(&end->value)))
@@ -19799,10 +19796,6 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
return ira->codegen->invalid_instruction;
}
- if (result_loc->value.special != ConstValSpecialRuntime) {
- zig_panic("TODO slice with comptime ptr and values");
- }
-
IrInstruction *result = ir_const(ira, &instruction->base, return_type);
ConstExprValue *out_val = &result->value;
out_val->data.x_struct.fields = create_const_vals(2);
@@ -19853,6 +19846,10 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];
init_const_usize(ira->codegen, len_val, end_scalar - start_scalar);
+ if (result_loc->value.special != ConstValSpecialRuntime) {
+ return ir_analyze_store_ptr(ira, &instruction->base, result_loc, result);
+ }
+
return result;
}
From be17a1e3eafb2580ad59439b69b7d4f75dda0098 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 25 Nov 2018 19:48:55 -0500
Subject: [PATCH 067/190] copy elision: orelse
```zig
export fn entry() void {
var y: ?Bar = null;
var x = y orelse return;
}
```
```llvm
define void @entry() #2 !dbg !41 {
Entry:
%y = alloca { %Bar, i1 }, align 4
%x = alloca %Bar, align 4
%0 = bitcast { %Bar, i1 }* %y to i8*, !dbg !59
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast ({ %Bar, i1 }* @0 to i8*), i64 12, i1 false), !dbg !59
call void @llvm.dbg.declare(metadata { %Bar, i1 }* %y, metadata !45, metadata !DIExpression()), !dbg !59
%1 = getelementptr inbounds { %Bar, i1 }, { %Bar, i1 }* %y, i32 0, i32 0, !dbg !60
%2 = bitcast %Bar* %1 to i8*, !dbg !60
%3 = bitcast %Bar* %x to i8*, !dbg !60
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %3, i8* align 4 %2, i64 8, i1 false), !dbg !60
%4 = getelementptr inbounds { %Bar, i1 }, { %Bar, i1 }* %y, i32 0, i32 1, !dbg !60
%5 = load i1, i1* %4, align 1, !dbg !60
br i1 %5, label %OrElseEnd, label %OrElseNull, !dbg !61
OrElseNull: ; preds = %Entry
ret void, !dbg !62
OrElseEnd: ; preds = %Entry
call void @llvm.dbg.declare(metadata %Bar* %x, metadata !57, metadata !DIExpression()), !dbg !63
ret void, !dbg !64
}
```
---
src/all_types.hpp | 8 +++++
src/codegen.cpp | 20 +++++++++++++
src/ir.cpp | 76 +++++++++++++++++++++++++++++++++++++++--------
src/ir_print.cpp | 9 ++++++
4 files changed, 100 insertions(+), 13 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index d293c7e06675..d7ff32f8924f 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2197,6 +2197,7 @@ enum IrInstructionId {
IrInstructionIdAllocaSrc,
IrInstructionIdAllocaGen,
IrInstructionIdAssertNonError,
+ IrInstructionIdAssertNonNull,
IrInstructionIdErrorUnionFieldErrorSet,
IrInstructionIdFirstArgResultLoc,
IrInstructionIdInferArrayType,
@@ -3362,6 +3363,13 @@ struct IrInstructionAssertNonError {
IrInstruction *err_code;
};
+// This is the safety check when using `.?`.
+struct IrInstructionAssertNonNull {
+ IrInstruction base;
+
+ IrInstruction *is_non_null;
+};
+
struct IrInstructionFirstArgResultLoc {
IrInstruction base;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index afbf5d79be60..02bd2a55a38d 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5170,6 +5170,24 @@ static LLVMValueRef ir_render_assert_non_error(CodeGen *g, IrExecutable *executa
return nullptr;
}
+static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executable,
+ IrInstructionAssertNonNull *instruction)
+{
+ if (!ir_want_runtime_safety(g, &instruction->base)) {
+ return nullptr;
+ }
+ LLVMValueRef is_non_null = ir_llvm_value(g, instruction->is_non_null);
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
+ LLVMBuildCondBr(g->builder, is_non_null, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_safety_crash(g, PanicMsgIdUnwrapOptionalFail);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ return nullptr;
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -5421,6 +5439,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_result_error_union_code(g, executable, (IrInstructionResultErrorUnionCode *)instruction);
case IrInstructionIdAssertNonError:
return ir_render_assert_non_error(g, executable, (IrInstructionAssertNonError *)instruction);
+ case IrInstructionIdAssertNonNull:
+ return ir_render_assert_non_null(g, executable, (IrInstructionAssertNonNull *)instruction);
case IrInstructionIdResultSliceToBytes:
zig_panic("TODO");
case IrInstructionIdResultBytesToSlice:
diff --git a/src/ir.cpp b/src/ir.cpp
index 84b45c938e31..411d2ea526a5 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -908,6 +908,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonError *
return IrInstructionIdAssertNonError;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonNull *) {
+ return IrInstructionIdAssertNonNull;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnionFieldErrorSet *) {
return IrInstructionIdErrorUnionFieldErrorSet;
}
@@ -2892,6 +2896,17 @@ static IrInstruction *ir_build_assert_non_error(IrBuilder *irb, Scope *scope, As
return &instruction->base;
}
+static IrInstruction *ir_build_assert_non_null(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *is_non_null)
+{
+ IrInstructionAssertNonNull *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->is_non_null = is_non_null;
+
+ ir_ref_instruction(is_non_null, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_error_union_field_error_set(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *ptr)
{
@@ -3223,8 +3238,15 @@ static IrInstruction *ir_gen_ptr(IrBuilder *irb, Scope *scope, AstNode *node, LV
ir_build_load_ptr(irb, scope, node, payload_ptr, result_loc);
return ir_build_error_union_field_error_set(irb, scope, node, ptr);
}
- case LValOptional:
- zig_panic("TODO");
+ case LValOptional: {
+ // ptr points to an optional;
+ // result_loc points to the result payload
+ // must return is_non_null bool
+ IrInstruction *payload_ptr = ir_build_unwrap_maybe(irb, scope, node, ptr, false);
+ ir_build_load_ptr(irb, scope, node, payload_ptr, result_loc);
+ IrInstruction *loaded_ptr = ir_build_load_ptr(irb, scope, node, ptr, nullptr);
+ return ir_build_test_nonnull(irb, scope, node, loaded_ptr);
+ }
}
zig_unreachable();
}
@@ -3323,10 +3345,12 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
{
assert(expr_node);
IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, expr_node, result_loc);
- IrInstruction *err_val = ir_gen_node(irb, expr_node, scope, LValErrorUnion, ensured_result_loc);
- if (err_val == irb->codegen->invalid_instruction)
+ IrInstruction *ptr_opt_err_code = ir_gen_node(irb, expr_node, scope, LValErrorUnion, ensured_result_loc);
+ if (ptr_opt_err_code == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_val);
+
+ IrInstruction *opt_err_code = ir_build_load_ptr(irb, scope, node, ptr_opt_err_code, nullptr);
+ IrInstruction *is_err_val = ir_build_test_nonnull(irb, scope, node, opt_err_code);
IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
@@ -3340,6 +3364,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime, nullptr));
ir_set_cursor_at_end_and_append_block(irb, return_block);
+ IrInstruction *ptr_err_code = ir_build_unwrap_maybe(irb, scope, node, ptr_opt_err_code, false);
+ IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, ptr_err_code, nullptr);
if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
if (irb->codegen->have_err_ret_tracing && !should_inline) {
ir_build_save_err_ret_addr(irb, scope, node);
@@ -7373,17 +7399,14 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_gen_ptr(irb, scope, node, lval, result_loc, ptr_inst);
}
case NodeTypeUnwrapOptional: {
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, result_loc);
AstNode *expr_node = node->data.unwrap_optional.expr;
-
- IrInstruction *maybe_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, nullptr);
- if (maybe_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *is_non_null = ir_gen_node(irb, expr_node, scope, LValOptional, ensured_result_loc);
+ if (is_non_null == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
- if (lval == LValPtr)
- return unwrapped_ptr;
-
- return ir_build_load_ptr(irb, scope, node, unwrapped_ptr, nullptr);
+ ir_build_assert_non_null(irb, scope, expr_node, is_non_null);
+ return ir_gen_result(irb, scope, node, lval, ensured_result_loc);
}
case NodeTypeBoolLiteral:
return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_bool_literal(irb, scope, node));
@@ -20469,6 +20492,30 @@ static IrInstruction *ir_analyze_instruction_assert_non_error(IrAnalyze *ira,
return ir_const_void(ira, &instruction->base);
}
+static IrInstruction *ir_analyze_instruction_assert_non_null(IrAnalyze *ira,
+ IrInstructionAssertNonNull *instruction)
+{
+ IrInstruction *is_non_null = instruction->is_non_null->child;
+ if (type_is_invalid(is_non_null->value.type))
+ return ira->codegen->invalid_instruction;
+
+ assert(is_non_null->value.type->id == ZigTypeIdBool);
+
+ if (instr_is_comptime(is_non_null)) {
+ bool is_non_null_bool;
+ if (!ir_resolve_bool(ira, is_non_null, &is_non_null_bool))
+ return ira->codegen->invalid_instruction;
+ if (is_non_null_bool)
+ return ir_const_void(ira, &instruction->base);
+ ir_add_error(ira, &instruction->base, buf_sprintf("unable to unwrap null"));
+ return ira->codegen->invalid_instruction;
+ }
+
+ ir_build_assert_non_null(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, is_non_null);
+ return ir_const_void(ira, &instruction->base);
+}
+
static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) {
Error err;
AstNode *proto_node = instruction->base.source_node;
@@ -22272,6 +22319,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_unwrap_err_payload(ira, (IrInstructionUnwrapErrPayload *)instruction);
case IrInstructionIdAssertNonError:
return ir_analyze_instruction_assert_non_error(ira, (IrInstructionAssertNonError *)instruction);
+ case IrInstructionIdAssertNonNull:
+ return ir_analyze_instruction_assert_non_null(ira, (IrInstructionAssertNonNull *)instruction);
case IrInstructionIdFnProto:
return ir_analyze_instruction_fn_proto(ira, (IrInstructionFnProto *)instruction);
case IrInstructionIdTestComptime:
@@ -22530,6 +22579,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdMarkErrRetTracePtr:
case IrInstructionIdAtomicRmw:
case IrInstructionIdAssertNonError:
+ case IrInstructionIdAssertNonNull:
case IrInstructionIdContainerInitFields:
case IrInstructionIdContainerInitList:
case IrInstructionIdInferCompTime:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 121b5b0b1935..b0a6b7bf82bf 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1374,6 +1374,12 @@ static void ir_print_assert_non_error(IrPrint *irp, IrInstructionAssertNonError
fprintf(irp->f, ")");
}
+static void ir_print_assert_non_null(IrPrint *irp, IrInstructionAssertNonNull *instruction) {
+ fprintf(irp->f, "AssertNonNull(");
+ ir_print_other_instruction(irp, instruction->is_non_null);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_error_union_field_error_set(IrPrint *irp, IrInstructionErrorUnionFieldErrorSet *instruction) {
fprintf(irp->f, "ErrorUnionFieldErrorSet(");
ir_print_other_instruction(irp, instruction->ptr);
@@ -1851,6 +1857,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdAssertNonError:
ir_print_assert_non_error(irp, (IrInstructionAssertNonError *)instruction);
break;
+ case IrInstructionIdAssertNonNull:
+ ir_print_assert_non_null(irp, (IrInstructionAssertNonNull *)instruction);
+ break;
case IrInstructionIdErrorUnionFieldErrorSet:
ir_print_error_union_field_error_set(irp, (IrInstructionErrorUnionFieldErrorSet *)instruction);
break;
From ca440b3c16d00cdef3c7cefc777bfd0b354314e2 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 27 Nov 2018 20:31:55 -0500
Subject: [PATCH 068/190] copy elision: @cmpxchg
```zig
export fn entry() void {
var linux_lock: i32 = undefined;
var c = @cmpxchgWeak(i32, &linux_lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse return;
}
```
```llvm
define void @entry() #2 !dbg !50 {
Entry:
%linux_lock = alloca i32, align 4
%c = alloca i32, align 4
%0 = bitcast i32* %linux_lock to i8*, !dbg !59
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 -86, i64 4, i1 false), !dbg !59
call void @llvm.dbg.declare(metadata i32* %linux_lock, metadata !54, metadata !DIExpression()), !dbg !59
%1 = cmpxchg weak i32* %linux_lock, i32 0, i32 1 acquire monotonic, !dbg !60
%2 = extractvalue { i32, i1 } %1, 1, !dbg !60
br i1 %2, label %CmpXchgPhi, label %CmpXchgNonNull, !dbg !60
OrElseNull: ; preds = %CmpXchgPhi
ret void, !dbg !61
OrElseEnd: ; preds = %CmpXchgPhi
call void @llvm.dbg.declare(metadata i32* %c, metadata !57, metadata !DIExpression()), !dbg !62
ret void, !dbg !63
CmpXchgNonNull: ; preds = %Entry
%3 = extractvalue { i32, i1 } %1, 0, !dbg !60
store i32 %3, i32* %c, align 4, !dbg !60
br label %CmpXchgPhi, !dbg !60
CmpXchgPhi: ; preds = %CmpXchgNonNull, %Entry
%4 = phi i1 [ true, %CmpXchgNonNull ], [ false, %Entry ], !dbg !60
br i1 %4, label %OrElseEnd, label %OrElseNull, !dbg !64
}
```
---
src/all_types.hpp | 28 +++++-
src/codegen.cpp | 71 ++++++++------
src/ir.cpp | 244 +++++++++++++++++++++++++++++++++++++---------
src/ir_print.cpp | 42 ++++++--
4 files changed, 300 insertions(+), 85 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index d7ff32f8924f..ca43b9424e92 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2101,7 +2101,8 @@ enum IrInstructionId {
IrInstructionIdCompileLog,
IrInstructionIdErrName,
IrInstructionIdEmbedFile,
- IrInstructionIdCmpxchg,
+ IrInstructionIdCmpxchgSrc,
+ IrInstructionIdCmpxchgGen,
IrInstructionIdFence,
IrInstructionIdTruncate,
IrInstructionIdIntCast,
@@ -2202,6 +2203,7 @@ enum IrInstructionId {
IrInstructionIdFirstArgResultLoc,
IrInstructionIdInferArrayType,
IrInstructionIdInferCompTime,
+ IrInstructionIdSetNonNullBit,
};
struct IrInstruction {
@@ -2676,7 +2678,7 @@ struct IrInstructionEmbedFile {
IrInstruction *name;
};
-struct IrInstructionCmpxchg {
+struct IrInstructionCmpxchgSrc {
IrInstruction base;
IrInstruction *type_value;
@@ -2687,8 +2689,18 @@ struct IrInstructionCmpxchg {
IrInstruction *failure_order_value;
IrInstruction *result_loc;
- // if this instruction gets to runtime then we know these values:
+ bool is_weak;
+};
+
+struct IrInstructionCmpxchgGen {
+ IrInstruction base;
+
ZigType *type;
+ IrInstruction *ptr;
+ IrInstruction *cmp_value;
+ IrInstruction *new_value;
+ IrInstruction *result_loc;
+
AtomicOrder success_order;
AtomicOrder failure_order;
@@ -3302,6 +3314,8 @@ struct IrInstructionResultOptionalPayload {
IrInstruction base;
IrInstruction *prev_result_loc;
+ IrInstruction *payload_type;
+ bool make_non_null;
};
struct IrInstructionResultBytesToSlice {
@@ -3391,6 +3405,14 @@ struct IrInstructionInferCompTime {
IrInstruction *new_result_loc;
};
+struct IrInstructionSetNonNullBit {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ IrInstruction *non_null_bit;
+ IrInstruction *new_result_loc;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 02bd2a55a38d..90171985d318 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3827,7 +3827,7 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable
return gen_non_null_bit(g, instruction->value->value.type, ir_llvm_value(g, instruction->value));
}
-static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
+static LLVMValueRef ir_render_unwrap_optional(CodeGen *g, IrExecutable *executable,
IrInstructionUnwrapOptional *instruction)
{
ZigType *ptr_type = instruction->value->value.type;
@@ -4260,7 +4260,7 @@ static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed)
zig_unreachable();
}
-static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) {
+static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchgGen *instruction) {
LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr);
LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value);
LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value);
@@ -4268,32 +4268,29 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order);
LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order);
- LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
+ LLVMValueRef cmpxchg_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
success_order, failure_order, instruction->is_weak);
- ZigType *maybe_type = instruction->base.value.type;
- assert(maybe_type->id == ZigTypeIdOptional);
- ZigType *child_type = maybe_type->data.maybe.child_type;
-
- if (type_is_codegen_pointer(child_type)) {
- LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
- LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
- return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, "");
- }
-
assert(type_has_bits(instruction->type));
- LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
+ LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, cmpxchg_val, 1, "");
+ LLVMBasicBlockRef null_block = LLVMGetInsertBlock(g->builder);
+ LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn_val, "CmpXchgNonNull");
+ LLVMBasicBlockRef phi_block = LLVMAppendBasicBlock(g->cur_fn_val, "CmpXchgPhi");
+ LLVMBuildCondBr(g->builder, success_bit, phi_block, non_null_block);
- LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
- LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_ptr, maybe_child_index, "");
- gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val);
+ LLVMPositionBuilderAtEnd(g->builder, non_null_block);
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
+ LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, cmpxchg_val, 0, "");
+ gen_assign_raw(g, result_ptr, instruction->result_loc->value.type, payload_val);
+ LLVMBuildBr(g->builder, phi_block);
- LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
- LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, "");
- LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, result_ptr, maybe_null_index, "");
- gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false);
- return result_ptr;
+ LLVMPositionBuilderAtEnd(g->builder, phi_block);
+ LLVMValueRef non_null_bit = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
+ LLVMValueRef incoming_values[] = {LLVMConstAllOnes(LLVMInt1Type()), LLVMConstNull(LLVMInt1Type())};
+ LLVMBasicBlockRef incoming_blocks[] = {non_null_block, null_block};
+ LLVMAddIncoming(non_null_bit, incoming_values, incoming_blocks, 2);
+ return non_null_bit;
}
static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) {
@@ -5107,12 +5104,16 @@ static LLVMValueRef ir_render_result_optional_payload(CodeGen *g, IrExecutable *
IrInstructionResultOptionalPayload *instruction)
{
LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
- ZigType *child_type = instruction->base.value.type;
+ ZigType *ptr_type = instruction->base.value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+ ZigType *child_type = ptr_type->data.pointer.child_type;
if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
return prev_result_loc;
} else {
- LLVMValueRef nonnull_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_null_index, "");
- gen_store_untyped(g, LLVMConstInt(LLVMInt1Type(), 1, false), nonnull_ptr, 0, false);
+ if (instruction->make_non_null) {
+ LLVMValueRef nonnull_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_null_index, "");
+ gen_store_untyped(g, LLVMConstInt(LLVMInt1Type(), 1, false), nonnull_ptr, 0, false);
+ }
return LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_child_index, "");
}
}
@@ -5188,6 +5189,17 @@ static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executab
return nullptr;
}
+static LLVMValueRef ir_render_set_non_null_bit(CodeGen *g, IrExecutable *executable,
+ IrInstructionSetNonNullBit *instruction)
+{
+ LLVMValueRef ptr_to_optional = ir_llvm_value(g, instruction->prev_result_loc);
+ LLVMValueRef non_null_bit = ir_llvm_value(g, instruction->non_null_bit);
+
+ LLVMValueRef nonnull_ptr = LLVMBuildStructGEP(g->builder, ptr_to_optional, maybe_null_index, "");
+ gen_store_untyped(g, non_null_bit, nonnull_ptr, 0, false);
+ return nullptr;
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -5271,6 +5283,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdPtrCastSrc:
case IrInstructionIdInferCompTime:
case IrInstructionIdResultPtrCast:
+ case IrInstructionIdCmpxchgSrc:
zig_unreachable();
case IrInstructionIdDeclVarGen:
@@ -5308,7 +5321,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdTestNonNull:
return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
case IrInstructionIdUnwrapOptional:
- return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction);
+ return ir_render_unwrap_optional(g, executable, (IrInstructionUnwrapOptional *)instruction);
case IrInstructionIdClz:
return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
case IrInstructionIdCtz:
@@ -5323,8 +5336,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_ref(g, executable, (IrInstructionRef *)instruction);
case IrInstructionIdErrName:
return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction);
- case IrInstructionIdCmpxchg:
- return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction);
+ case IrInstructionIdCmpxchgGen:
+ return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchgGen *)instruction);
case IrInstructionIdFence:
return ir_render_fence(g, executable, (IrInstructionFence *)instruction);
case IrInstructionIdTruncate:
@@ -5441,6 +5454,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_assert_non_error(g, executable, (IrInstructionAssertNonError *)instruction);
case IrInstructionIdAssertNonNull:
return ir_render_assert_non_null(g, executable, (IrInstructionAssertNonNull *)instruction);
+ case IrInstructionIdSetNonNullBit:
+ return ir_render_set_non_null_bit(g, executable, (IrInstructionSetNonNullBit *)instruction);
case IrInstructionIdResultSliceToBytes:
zig_panic("TODO");
case IrInstructionIdResultBytesToSlice:
diff --git a/src/ir.cpp b/src/ir.cpp
index 411d2ea526a5..942026960080 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -165,6 +165,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *uncasted_ptr, IrInstruction *uncasted_value);
static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed);
+static IrInstruction *resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type);
static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
assert(get_src_ptr_type(const_val->type) != nullptr);
@@ -524,8 +525,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) {
return IrInstructionIdEmbedFile;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchg *) {
- return IrInstructionIdCmpxchg;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgSrc *) {
+ return IrInstructionIdCmpxchgSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgGen *) {
+ return IrInstructionIdCmpxchgGen;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) {
@@ -928,6 +933,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionInferCompTime *)
return IrInstructionIdInferCompTime;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionSetNonNullBit *) {
+ return IrInstructionIdSetNonNullBit;
+}
+
template
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate(1);
@@ -1822,31 +1831,49 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base;
}
-static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
- IrInstruction *success_order_value, IrInstruction *failure_order_value, bool is_weak,
- ZigType *type, AtomicOrder success_order, AtomicOrder failure_order, IrInstruction *result_loc)
+ IrInstruction *success_order_value, IrInstruction *failure_order_value, IrInstruction *result_loc, bool is_weak)
{
- IrInstructionCmpxchg *instruction = ir_build_instruction(irb, scope, source_node);
+ IrInstructionCmpxchgSrc *instruction = ir_build_instruction(irb, scope, source_node);
instruction->type_value = type_value;
instruction->ptr = ptr;
instruction->cmp_value = cmp_value;
instruction->new_value = new_value;
instruction->success_order_value = success_order_value;
instruction->failure_order_value = failure_order_value;
+ instruction->result_loc = result_loc;
instruction->is_weak = is_weak;
+
+ ir_ref_instruction(type_value, irb->current_basic_block);
+ ir_ref_instruction(ptr, irb->current_basic_block);
+ ir_ref_instruction(cmp_value, irb->current_basic_block);
+ ir_ref_instruction(new_value, irb->current_basic_block);
+ ir_ref_instruction(success_order_value, irb->current_basic_block);
+ ir_ref_instruction(failure_order_value, irb->current_basic_block);
+ ir_ref_instruction(result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_cmpxchg_gen(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ ZigType *type, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
+ AtomicOrder success_order, AtomicOrder failure_order, IrInstruction *result_loc, bool is_weak)
+{
+ IrInstructionCmpxchgGen *instruction = ir_build_instruction(irb, scope, source_node);
instruction->type = type;
+ instruction->ptr = ptr;
+ instruction->cmp_value = cmp_value;
+ instruction->new_value = new_value;
instruction->success_order = success_order;
instruction->failure_order = failure_order;
instruction->result_loc = result_loc;
+ instruction->is_weak = is_weak;
- if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block);
ir_ref_instruction(ptr, irb->current_basic_block);
ir_ref_instruction(cmp_value, irb->current_basic_block);
ir_ref_instruction(new_value, irb->current_basic_block);
- if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block);
- if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block);
- ir_ref_instruction(result_loc, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -2762,12 +2789,15 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope,
}
static IrInstruction *ir_build_result_optional_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *prev_result_loc)
+ IrInstruction *prev_result_loc, IrInstruction *payload_type, bool make_non_null)
{
IrInstructionResultOptionalPayload *instruction = ir_build_instruction(irb, scope, source_node);
instruction->prev_result_loc = prev_result_loc;
+ instruction->payload_type = payload_type;
+ instruction->make_non_null = make_non_null;
ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block);
return &instruction->base;
}
@@ -2956,6 +2986,21 @@ static IrInstruction *ir_build_infer_comptime(IrBuilder *irb, Scope *scope, AstN
return &instruction->base;
}
+static IrInstruction *ir_build_set_nonnull_bit(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, IrInstruction *non_null_bit, IrInstruction *new_result_loc)
+{
+ IrInstructionSetNonNullBit *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->non_null_bit = non_null_bit;
+ instruction->new_result_loc = new_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ ir_ref_instruction(non_null_bit, irb->current_basic_block);
+ if (new_result_loc != nullptr) ir_ref_instruction(new_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -3174,13 +3219,14 @@ static IrInstruction *ir_gen_multi(IrBuilder *irb, Scope *scope, AstNode *node,
// an instruction which just makes a pointer of it.
return ir_build_ref(irb, scope, value->source_node, value, false, false, nullptr);
}
- case LValErrorUnion:
- case LValOptional: {
+ case LValErrorUnion: {
IrInstruction *err_alloca = ir_build_alloca_src(irb, scope, value->source_node,
nullptr, nullptr, "err");
ir_build_store_ptr(irb, scope, value->source_node, err_alloca, value);
return err_alloca;
}
+ case LValOptional:
+ return value;
}
zig_unreachable();
}
@@ -3199,10 +3245,26 @@ static IrInstruction *ir_gen_value(IrBuilder *irb, Scope *scope, AstNode *node,
if (instr_is_unreachable(value))
return value;
if (result_loc != nullptr) {
- ir_build_store_ptr(irb, scope, node, result_loc, value);
- if (lval != LValNone) {
- assert(lval != LValPtr);
- return ir_gen_result(irb, scope, node, lval, result_loc);
+ switch (lval) {
+ case LValNone:
+ ir_build_store_ptr(irb, scope, node, result_loc, value);
+ break;
+ case LValPtr:
+ zig_unreachable();
+ case LValErrorUnion:
+ zig_panic("TODO");
+ //ir_build_store_ptr(irb, scope, node, result_loc, value);
+ //return ir_gen_result(irb, scope, node, lval, result_loc);
+ case LValOptional: {
+ zig_panic("TODO");
+ //// result_loc is a pointer to child type
+ //// value is an optional value
+ //// need to return non-null bit
+ //IrInstruction *opt_ptr = ir_build_ref(irb, scope, node, value, false, false, nullptr);
+ //IrInstruction *payload_ptr = ir_build_unwrap_maybe(irb, scope, node, opt_ptr, false);
+ //ir_build_load_ptr(irb, scope, node, payload_ptr, result_loc);
+ //return ir_build_test_nonnull(irb, scope, node, value);
+ }
}
}
switch (lval) {
@@ -4284,10 +4346,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg5_value == irb->codegen->invalid_instruction)
return arg5_value;
- IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
- arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak),
- nullptr, AtomicOrderUnordered, AtomicOrderUnordered, result_loc);
- return ir_gen_multi(irb, scope, node, lval, result_loc, cmpxchg);
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, result_loc);
+ IrInstruction *payload_ptr = (lval == LValOptional) ? ensured_result_loc :
+ ir_build_result_optional_payload(irb, scope, node, ensured_result_loc, arg0_value, false);
+
+ IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value,
+ arg2_value, arg3_value, arg4_value, arg5_value, payload_ptr,
+ (builtin_fn->id == BuiltinFnIdCmpxchgWeak));
+
+ if (lval == LValOptional)
+ return cmpxchg;
+
+ ir_build_set_nonnull_bit(irb, scope, node, ensured_result_loc, cmpxchg, payload_ptr);
+ return ir_gen_result(irb, scope, node, lval, ensured_result_loc);
}
case BuiltinFnIdFence:
{
@@ -5342,11 +5413,14 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional));
case PrefixOpAddrOf: {
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
- IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, expr_node, result_loc);
- IrInstruction *inst = ir_gen_node(irb, expr_node, scope, LValPtr, ensured_result_loc);
+ IrInstruction *inst = ir_gen_node(irb, expr_node, scope, LValPtr, result_loc);
if (inst == irb->codegen->invalid_instruction)
return inst;
- return ir_gen_result(irb, scope, expr_node, lval, ensured_result_loc);
+ if (result_loc == nullptr) {
+ return ir_gen_value(irb, scope, expr_node, lval, nullptr, inst);
+ } else {
+ return ir_gen_result(irb, scope, expr_node, lval, result_loc);
+ }
}
}
zig_unreachable();
@@ -10131,8 +10205,13 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
}
static IrInstruction *ir_analyze_result_optional_payload(IrAnalyze *ira, IrInstruction *result_loc,
- ZigType *needed_child_type)
+ ZigType *needed_child_type, bool make_non_null)
{
+ ZigType *opt_type = get_optional_type(ira->codegen, needed_child_type);
+ result_loc = resolve_possible_alloca_inference(ira, result_loc, opt_type);
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
ZigType *old_ptr_type = result_loc->value.type;
assert(old_ptr_type->id == ZigTypeIdPointer);
ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
@@ -10157,26 +10236,42 @@ static IrInstruction *ir_analyze_result_optional_payload(IrAnalyze *ira, IrInstr
}
assert(optional_val->data.x_optional != nullptr);
- IrInstruction *result = ir_const(ira, result_loc, new_ptr_type);
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_result_optional_payload(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc, nullptr, make_non_null);
+ result->value.type = new_ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, result_loc, new_ptr_type);
+ }
ConstExprValue *result_val = &result->value;
result_val->data.x_ptr.special = ConstPtrSpecialRef;
result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
result_val->data.x_ptr.data.ref.pointee = optional_val->data.x_optional;
- if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
- ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
- }
-
return result;
}
}
IrInstruction *result = ir_build_result_optional_payload(&ira->new_irb, result_loc->scope,
- result_loc->source_node, result_loc);
+ result_loc->source_node, result_loc, nullptr, make_non_null);
result->value.type = new_ptr_type;
return result;
}
+static IrInstruction *ir_analyze_instruction_result_optional_payload(IrAnalyze *ira,
+ IrInstructionResultOptionalPayload *instruction)
+{
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child);
+ if (type_is_invalid(payload_type))
+ return ira->codegen->invalid_instruction;
+ return ir_analyze_result_optional_payload(ira, prev_result_loc, payload_type, instruction->make_non_null);
+}
+
static IrInstruction *ir_analyze_result_slice_ptr(IrAnalyze *ira, IrInstruction *result_loc,
ZigType *ptr_to_array_type, uint64_t len)
{
@@ -10359,10 +10454,6 @@ static IrInstruction *ir_analyze_result_error_union_code(IrAnalyze *ira, IrInstr
result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
result_val->data.x_ptr.data.ref.pointee = error_union_val->data.x_err_union.error_set;
- if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
- ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
- }
-
return result;
}
}
@@ -11682,7 +11773,7 @@ static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, IrInstruction *unr
if (types_match_const_cast_only(ira, have_child_type->data.maybe.child_type, needed_child_type, source_node,
false).id == ConstCastResultIdOk)
{
- return ir_analyze_result_optional_payload(ira, result_loc, needed_child_type);
+ return ir_analyze_result_optional_payload(ira, result_loc, needed_child_type, true);
}
}
@@ -16665,7 +16756,7 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns
}
}
-static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
+static IrInstruction *ir_analyze_instruction_unwrap_optional(IrAnalyze *ira,
IrInstructionUnwrapOptional *unwrap_maybe_instruction)
{
IrInstruction *value = unwrap_maybe_instruction->value->child;
@@ -18936,7 +19027,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru
return result;
}
-static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
+static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchgSrc *instruction) {
ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_instruction;
@@ -18946,6 +19037,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
return ira->codegen->invalid_instruction;
IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ result_loc = resolve_possible_alloca_inference(ira, result_loc, operand_type);
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
@@ -19012,10 +19106,15 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
zig_panic("TODO compile-time execution of cmpxchg");
}
- IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
- nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,
- operand_type, success_order, failure_order, result_loc);
- result->value.type = get_optional_type(ira->codegen, operand_type);
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ result_loc->value.special = ConstValSpecialRuntime;
+ }
+
+ IrInstruction *result = ir_build_cmpxchg_gen(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node,
+ operand_type, casted_ptr, casted_cmp_value, casted_new_value,
+ success_order, failure_order, result_loc, instruction->is_weak);
+ result->value.type = ira->codegen->builtin_types.entry_bool;
return result;
}
@@ -22150,6 +22249,51 @@ static IrInstruction *ir_analyze_instruction_infer_comptime(IrAnalyze *ira,
return ir_const_void(ira, &instruction->base);
}
+static IrInstruction *ir_analyze_instruction_set_non_null_bit(IrAnalyze *ira,
+ IrInstructionSetNonNullBit *instruction)
+{
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *non_null_bit = instruction->non_null_bit->child;
+ if (type_is_invalid(non_null_bit->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = instruction->new_result_loc->child;
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ assert(prev_result_loc->value.type->id == ZigTypeIdPointer);
+ ZigType *opt_type = prev_result_loc->value.type->data.pointer.child_type;
+ assert(opt_type->id == ZigTypeIdOptional);
+
+ if (!handle_is_ptr(opt_type)) {
+ if (prev_result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(new_result_loc) &&
+ new_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ prev_result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ prev_result_loc->value.special = ConstValSpecialRuntime;
+ }
+ }
+ return ir_const_void(ira, &instruction->base);
+ }
+
+ if (instr_is_comptime(prev_result_loc) && instr_is_comptime(new_result_loc) &&
+ instr_is_comptime(non_null_bit))
+ {
+ zig_panic("TODO comptime cmpxchg");
+ }
+
+ prev_result_loc->value.special = ConstValSpecialRuntime;
+ IrInstruction *result = ir_build_set_nonnull_bit(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, prev_result_loc, non_null_bit, nullptr);
+ result->value.type = ira->codegen->builtin_types.entry_void;
+ return result;
+}
+
static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -22162,11 +22306,11 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdCast:
case IrInstructionIdDeclVarGen:
case IrInstructionIdAllocaGen:
- case IrInstructionIdResultOptionalPayload:
case IrInstructionIdResultSlicePtr:
case IrInstructionIdResultErrorUnionPayload:
case IrInstructionIdResultErrorUnionCode:
case IrInstructionIdPtrCastGen:
+ case IrInstructionIdCmpxchgGen:
zig_unreachable();
case IrInstructionIdReturn:
@@ -22224,7 +22368,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdTestNonNull:
return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction);
case IrInstructionIdUnwrapOptional:
- return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction);
+ return ir_analyze_instruction_unwrap_optional(ira, (IrInstructionUnwrapOptional *)instruction);
case IrInstructionIdClz:
return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction);
case IrInstructionIdCtz:
@@ -22265,8 +22409,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction);
case IrInstructionIdEmbedFile:
return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction);
- case IrInstructionIdCmpxchg:
- return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction);
+ case IrInstructionIdCmpxchgSrc:
+ return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchgSrc *)instruction);
case IrInstructionIdFence:
return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);
case IrInstructionIdTruncate:
@@ -22443,6 +22587,10 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_infer_array_type(ira, (IrInstructionInferArrayType *)instruction);
case IrInstructionIdInferCompTime:
return ir_analyze_instruction_infer_comptime(ira, (IrInstructionInferCompTime *)instruction);
+ case IrInstructionIdResultOptionalPayload:
+ return ir_analyze_instruction_result_optional_payload(ira, (IrInstructionResultOptionalPayload *)instruction);
+ case IrInstructionIdSetNonNullBit:
+ return ir_analyze_instruction_set_non_null_bit(ira, (IrInstructionSetNonNullBit *)instruction);
case IrInstructionIdResultBytesToSlice:
zig_panic("TODO");
case IrInstructionIdResultSliceToBytes:
@@ -22550,7 +22698,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdCInclude:
case IrInstructionIdCDefine:
case IrInstructionIdCUndef:
- case IrInstructionIdCmpxchg:
case IrInstructionIdFence:
case IrInstructionIdMemset:
case IrInstructionIdMemcpy:
@@ -22583,7 +22730,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdContainerInitFields:
case IrInstructionIdContainerInitList:
case IrInstructionIdInferCompTime:
+ case IrInstructionIdSetNonNullBit:
case IrInstructionIdSlice:
+ case IrInstructionIdCmpxchgGen:
+ case IrInstructionIdCmpxchgSrc:
return true;
case IrInstructionIdPhi:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index b0a6b7bf82bf..0966fe13eb49 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -469,8 +469,7 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
fprintf(irp->f, ")");
}
-static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
- fprintf(irp->f, "*");
+static void ir_print_test_non_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
ir_print_other_instruction(irp, instruction->value);
fprintf(irp->f, " != null");
}
@@ -606,7 +605,7 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio
fprintf(irp->f, ")");
}
-static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
+static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruction) {
fprintf(irp->f, "@cmpxchg(");
ir_print_other_instruction(irp, instruction->ptr);
fprintf(irp->f, ", ");
@@ -620,6 +619,17 @@ static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) {
+ fprintf(irp->f, "@cmpxchg(%s,", buf_ptr(&instruction->type->name));
+ ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ", ");
+ ir_print_other_instruction(irp, instruction->cmp_value);
+ fprintf(irp->f, ", ");
+ ir_print_other_instruction(irp, instruction->new_value);
+ fprintf(irp->f, ") result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
+}
+
static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {
fprintf(irp->f, "@fence(");
ir_print_other_instruction(irp, instruction->order_value);
@@ -1307,7 +1317,9 @@ static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *instruc
static void ir_print_result_optional_payload(IrPrint *irp, IrInstructionResultOptionalPayload *instruction) {
fprintf(irp->f, "ResultOptionalPayload(");
ir_print_other_instruction(irp, instruction->prev_result_loc);
- fprintf(irp->f, ")");
+ fprintf(irp->f, ",");
+ ir_print_other_instruction(irp, instruction->payload_type);
+ fprintf(irp->f, "make_non_null=%s)", instruction->make_non_null ? "yes" : "no");
}
static void ir_print_result_slice_ptr(IrPrint *irp, IrInstructionResultSlicePtr *instruction) {
@@ -1408,6 +1420,16 @@ static void ir_print_infer_comptime(IrPrint *irp, IrInstructionInferCompTime *in
fprintf(irp->f, ")");
}
+static void ir_print_set_non_null_bit(IrPrint *irp, IrInstructionSetNonNullBit *instruction) {
+ fprintf(irp->f, "SetNonNullBit(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",new_result=");
+ ir_print_other_instruction(irp, instruction->new_result_loc);
+ fprintf(irp->f, ",non_null_bit=");
+ ir_print_other_instruction(irp, instruction->non_null_bit);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1507,7 +1529,7 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
break;
case IrInstructionIdTestNonNull:
- ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction);
+ ir_print_test_non_null(irp, (IrInstructionTestNonNull *)instruction);
break;
case IrInstructionIdUnwrapOptional:
ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction);
@@ -1563,8 +1585,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdEmbedFile:
ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction);
break;
- case IrInstructionIdCmpxchg:
- ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction);
+ case IrInstructionIdCmpxchgSrc:
+ ir_print_cmpxchg_src(irp, (IrInstructionCmpxchgSrc *)instruction);
+ break;
+ case IrInstructionIdCmpxchgGen:
+ ir_print_cmpxchg_gen(irp, (IrInstructionCmpxchgGen *)instruction);
break;
case IrInstructionIdFence:
ir_print_fence(irp, (IrInstructionFence *)instruction);
@@ -1872,6 +1897,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdInferCompTime:
ir_print_infer_comptime(irp, (IrInstructionInferCompTime *)instruction);
break;
+ case IrInstructionIdSetNonNullBit:
+ ir_print_set_non_null_bit(irp, (IrInstructionSetNonNullBit *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
From f4b27a34e7176c5be2daa45b4a5f9e576ad78bf5 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 28 Nov 2018 16:48:24 -0500
Subject: [PATCH 069/190] copy elision: function call with error union return
```zig
export fn entry() void {
var x = ebar();
}
```
```llvm
define void @entry() #2 !dbg !42 {
Entry:
%error_return_trace_addresses = alloca [30 x i64], align 8
%error_return_trace = alloca %StackTrace, align 8
%x = alloca { i16, %Bar }, align 4
%0 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 0
store i64 0, i64* %0, align 8
%1 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 1
%2 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 0
%3 = getelementptr inbounds [30 x i64], [30 x i64]* %error_return_trace_addresses, i64 0, i64 0
store i64* %3, i64** %2, align 8
%4 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 1
store i64 30, i64* %4, align 8
%5 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 1, !dbg !57
%6 = call fastcc i16 @ebar(%Bar* %5, %StackTrace* %error_return_trace), !dbg !57
%7 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 0, !dbg !57
store i16 %6, i16* %7, align 2, !dbg !57
call void @llvm.dbg.declare(metadata { i16, %Bar }* %x, metadata !46, metadata !DIExpression()), !dbg !58
ret void, !dbg !59
}
```
---
src/all_types.hpp | 15 +-
src/codegen.cpp | 2 +
src/ir.cpp | 351 +++++++++++++++++++++++++++++++---------------
3 files changed, 245 insertions(+), 123 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index ca43b9424e92..8f1334e4f5e8 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2047,6 +2047,13 @@ struct IrBasicBlock {
IrInstruction *must_be_comptime_source_instr;
};
+enum LVal {
+ LValNone,
+ LValPtr,
+ LValErrorUnion,
+ LValOptional,
+};
+
enum IrInstructionId {
IrInstructionIdInvalid,
IrInstructionIdDeclVarSrc,
@@ -2432,6 +2439,7 @@ struct IrInstructionCall {
IrInstruction *result_loc;
IrInstruction *first_arg_result_loc;
FnInline fn_inline;
+ LVal lval;
bool is_async;
bool is_comptime;
};
@@ -3018,13 +3026,6 @@ struct IrInstructionTypeName {
IrInstruction *type_value;
};
-enum LVal {
- LValNone,
- LValPtr,
- LValErrorUnion,
- LValOptional,
-};
-
struct IrInstructionDeclRef {
IrInstruction base;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 90171985d318..ee17ba72f7c1 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -2270,6 +2270,8 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
if (val->special == ConstValSpecialStatic) {
LLVMValueRef const_error_val = gen_const_val(g, val->data.x_err_union.error_set, "");
LLVMBuildRet(g->builder, const_error_val);
+ } else if (!type_has_bits(fn_type_id->return_type->data.error_union.payload_type)) {
+ LLVMBuildRet(g->builder, value);
} else {
zig_panic("TODO");
}
diff --git a/src/ir.cpp b/src/ir.cpp
index 942026960080..e0fdf9a629b0 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -166,6 +166,12 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
IrInstruction *uncasted_ptr, IrInstruction *uncasted_value);
static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed);
static IrInstruction *resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type);
+static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *base_ptr, bool safety_check_on);
+static IrInstruction *ir_analyze_unwrap_err_payload(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *base_ptr, bool safety_check_on);
+static IrInstruction *ir_analyze_error_union_field_error_set(IrAnalyze *ira,
+ IrInstruction *source_instr, IrInstruction *base_ptr);
static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
assert(get_src_ptr_type(const_val->type) != nullptr);
@@ -1238,7 +1244,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast
static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
- IrInstruction *new_stack, IrInstruction *result_loc, IrInstruction *first_arg_result_loc)
+ IrInstruction *new_stack, IrInstruction *result_loc, IrInstruction *first_arg_result_loc, LVal lval)
{
IrInstructionCall *call_instruction = ir_build_instruction(irb, scope, source_node);
call_instruction->fn_entry = fn_entry;
@@ -1252,6 +1258,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
call_instruction->new_stack = new_stack;
call_instruction->result_loc = result_loc;
call_instruction->first_arg_result_loc = first_arg_result_loc;
+ call_instruction->lval = lval;
if (fn_ref) ir_ref_instruction(fn_ref, irb->current_basic_block);
for (size_t i = 0; i < arg_count; i += 1)
@@ -4947,7 +4954,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
- fn_inline, false, nullptr, nullptr, result_loc, nullptr);
+ fn_inline, false, nullptr, nullptr, result_loc, nullptr, lval);
return ir_gen_multi(irb, scope, node, lval, result_loc, call);
}
case BuiltinFnIdNewStackCall:
@@ -4978,7 +4985,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args,
- false, FnInlineAuto, false, nullptr, new_stack, result_loc, nullptr);
+ false, FnInlineAuto, false, nullptr, new_stack, result_loc, nullptr, lval);
return ir_gen_multi(irb, scope, node, lval, result_loc, call);
}
case BuiltinFnIdTypeId:
@@ -5220,7 +5227,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
// In the analysis, this call instruction will be a simple LoadPtr instruction if
// it turns out to be an implicit cast.
IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
- FnInlineAuto, false, nullptr, nullptr, result_loc, arg_result_loc);
+ FnInlineAuto, false, nullptr, nullptr, result_loc, arg_result_loc, lval);
return ir_gen_multi(irb, scope, node, lval, result_loc, fn_call);
}
@@ -5241,7 +5248,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
}
IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto,
- is_async, async_allocator, nullptr, result_loc, nullptr);
+ is_async, async_allocator, nullptr, result_loc, nullptr, lval);
return ir_gen_multi(irb, scope, node, lval, result_loc, fn_call);
}
@@ -7797,7 +7804,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
args[0] = implicit_allocator_ptr; // self
args[1] = mem_slice; // old_mem
ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false,
- nullptr, nullptr, nullptr, nullptr);
+ nullptr, nullptr, nullptr, nullptr, LValNone);
IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false, nullptr);
@@ -13762,7 +13769,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c
IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope,
call_instruction->base.source_node, fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true,
- async_allocator_inst, nullptr, nullptr, nullptr);
+ async_allocator_inst, nullptr, nullptr, nullptr, LValNone);
result->value.type = async_return_type;
return result;
}
@@ -14041,23 +14048,61 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
return result;
}
+// Note this is semantically different from what gets run with ir_build_set_nonnull_bit
+static IrInstruction *ir_analyze_set_non_null_bit(IrAnalyze *ira,
+ IrInstruction *source_instr, IrInstruction *base_ptr, IrInstruction *non_null_bit)
+{
+ ZigType *ptr_type = base_ptr->value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+
+ ZigType *opt_type = ptr_type->data.pointer.child_type;
+ if (type_is_invalid(opt_type))
+ return ira->codegen->invalid_instruction;
+
+ if (opt_type->id != ZigTypeIdErrorUnion) {
+ ir_add_error(ira, base_ptr,
+ buf_sprintf("expected optional type, found '%s'", buf_ptr(&opt_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if (instr_is_comptime(base_ptr)) {
+ zig_panic("TODO comptime set non null bit");
+ }
+
+ return ir_build_set_nonnull_bit(&ira->new_irb,
+ source_instr->scope, source_instr->source_node, base_ptr, non_null_bit, nullptr);
+}
+
static IrInstruction *analyze_runtime_call(IrAnalyze *ira, ZigType *return_type,
IrInstructionCall *call_instruction, ZigFn *fn_entry, IrInstruction *fn_ref, size_t call_param_count,
IrInstruction **casted_args, FnInline fn_inline, IrInstruction *casted_new_stack)
{
- IrInstruction *casted_result_loc = nullptr;
-
+ // For an optional or error union, this result location is a pointer to the payload field.
+ // For other types this is a base pointer to the value.
+ IrInstruction *payload_result_loc = nullptr;
+ // For an optional or error union, this is a base pointer.
+ // For other types this is the same as payload_result_loc.
+ IrInstruction *base_result_loc = nullptr;
+
+ bool convert_to_value;
ZigType *scalar_result_type;
ZigType *payload_result_type;
- if (return_type->id == ZigTypeIdErrorUnion) {
+ if (return_type->id == ZigTypeIdErrorUnion && handle_is_ptr(return_type)) {
scalar_result_type = get_optional_type(ira->codegen, return_type->data.error_union.err_set_type);
payload_result_type = return_type->data.error_union.payload_type;
+ convert_to_value = call_instruction->lval != LValErrorUnion;
+ } else if (return_type->id == ZigTypeIdOptional && handle_is_ptr(return_type)) {
+ scalar_result_type = ira->codegen->builtin_types.entry_bool;
+ payload_result_type = return_type->data.maybe.child_type;
+ convert_to_value = call_instruction->lval != LValOptional;
} else {
payload_result_type = return_type;
scalar_result_type = return_type;
+ convert_to_value = false;
}
- bool need_store_ptr = (return_type == payload_result_type) && !handle_is_ptr(return_type) &&
+ bool need_store_ptr = !convert_to_value &&
+ (return_type == payload_result_type) && !handle_is_ptr(return_type) &&
call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr;
if (call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr) {
@@ -14073,24 +14118,80 @@ static IrInstruction *analyze_runtime_call(IrAnalyze *ira, ZigType *return_type,
}
}
- casted_result_loc = ir_implicit_cast_result(ira, prev_result_loc, payload_result_type, need_store_ptr);
- if (casted_result_loc == nullptr)
- casted_result_loc = prev_result_loc;
- if (type_is_invalid(casted_result_loc->value.type))
+ if (convert_to_value) {
+ base_result_loc = ir_implicit_cast_result(ira, prev_result_loc, return_type, false);
+ if (type_is_invalid(base_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if (return_type->id == ZigTypeIdErrorUnion) {
+ payload_result_loc = ir_analyze_unwrap_err_payload(ira, &call_instruction->base,
+ base_result_loc, false);
+ } else if (return_type->id == ZigTypeIdOptional) {
+ payload_result_loc = ir_analyze_unwrap_optional_payload(ira, &call_instruction->base,
+ base_result_loc, false);
+ } else {
+ zig_unreachable();
+ }
+ } else {
+ payload_result_loc = ir_implicit_cast_result(ira, prev_result_loc, payload_result_type, need_store_ptr);
+ if (payload_result_loc == nullptr)
+ payload_result_loc = prev_result_loc;
+ base_result_loc = payload_result_loc;
+ }
+ if (type_is_invalid(payload_result_loc->value.type))
return ira->codegen->invalid_instruction;
}
+ // This instruction, in the case of optional and error union, is always the error code / bool value.
+ // So if the LVal does not match this, we have to emit more instructions to adhere to the expected
+ // types.
IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
call_instruction->base.scope, call_instruction->base.source_node,
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
- casted_new_stack, casted_result_loc, nullptr);
+ casted_new_stack, payload_result_loc, nullptr, LValNone);
new_call_instruction->value.type = scalar_result_type;
+ if (scalar_result_type->id == ZigTypeIdUnreachable)
+ return ir_finish_anal(ira, new_call_instruction);
if (need_store_ptr) {
- ir_analyze_store_ptr(ira, &call_instruction->base, casted_result_loc, new_call_instruction);
+ ir_analyze_store_ptr(ira, &call_instruction->base, payload_result_loc, new_call_instruction);
+ return new_call_instruction;
}
+ if (!convert_to_value)
+ return new_call_instruction;
- return ir_finish_anal(ira, new_call_instruction);
+ if (return_type->id == ZigTypeIdErrorUnion) {
+ IrInstruction *err_code_ptr = ir_analyze_error_union_field_error_set(ira,
+ &call_instruction->base, base_result_loc);
+ ir_analyze_store_ptr(ira, &call_instruction->base, err_code_ptr, new_call_instruction);
+ switch (call_instruction->lval) {
+ case LValNone:
+ return ir_get_deref(ira, &call_instruction->base, base_result_loc);
+ case LValPtr:
+ return base_result_loc;
+ case LValErrorUnion:
+ zig_unreachable();
+ case LValOptional:
+ // This means incorrectly used optional syntax for error union.
+ zig_panic("TODO");
+ }
+ zig_unreachable();
+ } else if (return_type->id == ZigTypeIdOptional) {
+ ir_analyze_set_non_null_bit(ira, &call_instruction->base, base_result_loc, new_call_instruction);
+ switch (call_instruction->lval) {
+ case LValNone:
+ return ir_get_deref(ira, &call_instruction->base, base_result_loc);
+ case LValPtr:
+ return base_result_loc;
+ case LValOptional:
+ zig_unreachable();
+ case LValErrorUnion:
+ // This means incorrectly used error union for optional.
+ zig_panic("TODO");
+ }
+ zig_unreachable();
+ } else {
+ zig_unreachable();
+ }
}
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
@@ -16756,30 +16857,28 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns
}
}
-static IrInstruction *ir_analyze_instruction_unwrap_optional(IrAnalyze *ira,
- IrInstructionUnwrapOptional *unwrap_maybe_instruction)
+static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *base_ptr, bool safety_check_on)
{
- IrInstruction *value = unwrap_maybe_instruction->value->child;
- if (type_is_invalid(value->value.type))
- return ira->codegen->invalid_instruction;
-
- ZigType *ptr_type = value->value.type;
+ ZigType *ptr_type = base_ptr->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *type_entry = ptr_type->data.pointer.child_type;
- if (type_is_invalid(type_entry)) {
+ if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
- } else if (type_entry->id != ZigTypeIdOptional) {
- ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node,
+
+ if (type_entry->id != ZigTypeIdOptional) {
+ ir_add_error_node(ira, base_ptr->source_node,
buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
}
+
ZigType *child_type = type_entry->data.maybe.child_type;
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
- if (instr_is_comptime(value)) {
- ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
+ if (instr_is_comptime(base_ptr)) {
+ ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
ConstExprValue *maybe_val = const_ptr_pointee(ira->codegen, val);
@@ -16788,10 +16887,10 @@ static IrInstruction *ir_analyze_instruction_unwrap_optional(IrAnalyze *ira,
if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) {
if (optional_value_is_null(maybe_val)) {
- ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null"));
+ ir_add_error(ira, source_instr, buf_sprintf("unable to unwrap null"));
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_const(ira, &unwrap_maybe_instruction->base, result_type);
+ IrInstruction *result = ir_const(ira, source_instr, result_type);
ConstExprValue *out_val = &result->value;
out_val->data.x_ptr.special = ConstPtrSpecialRef;
out_val->data.x_ptr.mut = val->data.x_ptr.mut;
@@ -16804,13 +16903,22 @@ static IrInstruction *ir_analyze_instruction_unwrap_optional(IrAnalyze *ira,
}
}
- IrInstruction *result = ir_build_unwrap_maybe(&ira->new_irb,
- unwrap_maybe_instruction->base.scope, unwrap_maybe_instruction->base.source_node,
- value, unwrap_maybe_instruction->safety_check_on);
+ IrInstruction *result = ir_build_unwrap_maybe(&ira->new_irb, source_instr->scope, source_instr->source_node,
+ base_ptr, safety_check_on);
result->value.type = result_type;
return result;
}
+static IrInstruction *ir_analyze_instruction_unwrap_optional(IrAnalyze *ira,
+ IrInstructionUnwrapOptional *instruction)
+{
+ IrInstruction *base_ptr = instruction->value->child;
+ if (type_is_invalid(base_ptr->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on);
+}
+
static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *ctz_instruction) {
IrInstruction *value = ctz_instruction->value->child;
if (type_is_invalid(value->value.type)) {
@@ -20358,14 +20466,10 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
}
}
-static IrInstruction *ir_analyze_instruction_error_union_field_error_set(IrAnalyze *ira,
- IrInstructionErrorUnionFieldErrorSet *instruction)
+static IrInstruction *ir_analyze_error_union_field_error_set(IrAnalyze *ira,
+ IrInstruction *source_instr, IrInstruction *base_ptr)
{
- IrInstruction *ptr = instruction->ptr->child;
- if (type_is_invalid(ptr->value.type))
- return ira->codegen->invalid_instruction;
- ZigType *ptr_type = ptr->value.type;
-
+ ZigType *ptr_type = base_ptr->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *type_entry = ptr_type->data.pointer.child_type;
@@ -20373,17 +20477,18 @@ static IrInstruction *ir_analyze_instruction_error_union_field_error_set(IrAnaly
return ira->codegen->invalid_instruction;
if (type_entry->id != ZigTypeIdErrorUnion) {
- ir_add_error(ira, ptr,
+ ir_add_error(ira, base_ptr,
buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
}
ZigType *opt_err_set = get_optional_type(ira->codegen, type_entry->data.error_union.err_set_type);
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, opt_err_set,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle,
+ ptr_type->data.pointer.explicit_alignment, 0, 0);
- if (instr_is_comptime(ptr)) {
- ConstExprValue *ptr_val = ir_resolve_const(ira, ptr, UndefBad);
+ if (instr_is_comptime(base_ptr)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad);
if (!ptr_val)
return ira->codegen->invalid_instruction;
if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
@@ -20408,12 +20513,12 @@ static IrInstruction *ir_analyze_instruction_error_union_field_error_set(IrAnaly
IrInstruction *result;
if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
- result = ir_build_error_union_field_error_set(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, ptr);
+ result = ir_build_error_union_field_error_set(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, base_ptr);
result->value.type = result_type;
result->value.special = ConstValSpecialStatic;
} else {
- result = ir_const(ira, &instruction->base, result_type);
+ result = ir_const(ira, source_instr, result_type);
}
ConstExprValue *const_val = &result->value;
const_val->data.x_ptr.special = ConstPtrSpecialBaseErrorUnionCode;
@@ -20424,11 +20529,21 @@ static IrInstruction *ir_analyze_instruction_error_union_field_error_set(IrAnaly
}
IrInstruction *result = ir_build_error_union_field_error_set(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node, ptr);
+ source_instr->scope, source_instr->source_node, base_ptr);
result->value.type = result_type;
return result;
}
+static IrInstruction *ir_analyze_instruction_error_union_field_error_set(IrAnalyze *ira,
+ IrInstructionErrorUnionFieldErrorSet *instruction)
+{
+ IrInstruction *base_ptr = instruction->ptr->child;
+ if (type_is_invalid(base_ptr->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return ir_analyze_error_union_field_error_set(ira, &instruction->base, base_ptr);
+}
+
static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
IrInstructionUnwrapErrCode *instruction)
{
@@ -20473,91 +20588,95 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
}
}
-static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
- IrInstructionUnwrapErrPayload *instruction)
+static IrInstruction *ir_analyze_unwrap_err_payload(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *base_ptr, bool safety_check_on)
{
- assert(instruction->value->child);
- IrInstruction *value = instruction->value->child;
- if (type_is_invalid(value->value.type))
- return ira->codegen->invalid_instruction;
- ZigType *ptr_type = value->value.type;
-
+ ZigType *ptr_type = base_ptr->value.type;
// This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *type_entry = ptr_type->data.pointer.child_type;
- if (type_is_invalid(type_entry)) {
+ if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
- } else if (type_entry->id == ZigTypeIdErrorUnion) {
- ZigType *payload_type = type_entry->data.error_union.payload_type;
- if (type_is_invalid(payload_type)) {
+ if (type_entry->id != ZigTypeIdErrorUnion) {
+ ir_add_error(ira, base_ptr,
+ buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ ZigType *payload_type = type_entry->data.error_union.payload_type;
+ if (type_is_invalid(payload_type))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ PtrLenSingle, 0, 0, 0);
+ if (instr_is_comptime(base_ptr)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad);
+ if (!ptr_val)
return ira->codegen->invalid_instruction;
- }
- ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
- PtrLenSingle, 0, 0, 0);
- if (instr_is_comptime(value)) {
- ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
- if (!ptr_val)
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
+ ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val);
+ if (err_union_val == nullptr)
return ira->codegen->invalid_instruction;
- if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
- ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val);
- if (err_union_val == nullptr)
- return ira->codegen->invalid_instruction;
- if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer &&
- err_union_val->special == ConstValSpecialUndef)
- {
- ConstExprValue *vals = create_const_vals(2);
- ConstExprValue *err_set_val = &vals[0];
- ConstExprValue *payload_val = &vals[1];
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer &&
+ err_union_val->special == ConstValSpecialUndef)
+ {
+ ConstExprValue *vals = create_const_vals(2);
+ ConstExprValue *err_set_val = &vals[0];
+ ConstExprValue *payload_val = &vals[1];
- ZigType *opt_err_set = get_optional_type(ira->codegen, type_entry->data.error_union.err_set_type);
- err_set_val->special = ConstValSpecialStatic;
- err_set_val->type = opt_err_set;
- err_set_val->data.x_err_set = nullptr;
+ ZigType *opt_err_set = get_optional_type(ira->codegen, type_entry->data.error_union.err_set_type);
+ err_set_val->special = ConstValSpecialStatic;
+ err_set_val->type = opt_err_set;
+ err_set_val->data.x_err_set = nullptr;
- payload_val->special = ConstValSpecialUndef;
- payload_val->type = payload_type;
+ payload_val->special = ConstValSpecialUndef;
+ payload_val->type = payload_type;
- err_union_val->special = ConstValSpecialStatic;
- err_union_val->data.x_err_union.error_set = err_set_val;
- err_union_val->data.x_err_union.payload = payload_val;
+ err_union_val->special = ConstValSpecialStatic;
+ err_union_val->data.x_err_union.error_set = err_set_val;
+ err_union_val->data.x_err_union.payload = payload_val;
+ }
+ if (err_union_val->special != ConstValSpecialRuntime) {
+ ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
+ if (err != nullptr) {
+ ir_add_error(ira, source_instr,
+ buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
+ return ira->codegen->invalid_instruction;
}
- if (err_union_val->special != ConstValSpecialRuntime) {
- ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
- if (err != nullptr) {
- ir_add_error(ira, &instruction->base,
- buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
- return ira->codegen->invalid_instruction;
- }
- IrInstruction *result;
- if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
- result = ir_build_unwrap_err_payload(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, value, instruction->safety_check_on);
- result->value.type = result_type;
- result->value.special = ConstValSpecialStatic;
- } else {
- result = ir_const(ira, &instruction->base, result_type);
- }
- result->value.data.x_ptr.special = ConstPtrSpecialRef;
- result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload;
- result->value.data.x_ptr.mut = ptr_val->data.x_ptr.mut;
- return result;
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_unwrap_err_payload(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, base_ptr, safety_check_on);
+ result->value.type = result_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, source_instr, result_type);
}
+ result->value.data.x_ptr.special = ConstPtrSpecialRef;
+ result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload;
+ result->value.data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ return result;
}
}
+ }
- IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on);
- result->value.type = result_type;
- return result;
- } else {
- ir_add_error(ira, value,
- buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
+ IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, base_ptr, safety_check_on);
+ result->value.type = result_type;
+ return result;
+}
+
+static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
+ IrInstructionUnwrapErrPayload *instruction)
+{
+ IrInstruction *base_ptr = instruction->value->child;
+ if (type_is_invalid(base_ptr->value.type))
return ira->codegen->invalid_instruction;
- }
+ return ir_analyze_unwrap_err_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on);
}
static IrInstruction *ir_analyze_instruction_assert_non_error(IrAnalyze *ira,
From eebfb2eaf3758138f6a55195fa4b985e1c0e3c24 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 28 Nov 2018 18:15:33 -0500
Subject: [PATCH 070/190] copy elision: handle direct assignment of
anyerror!void
```zig
export fn entry() void {
var x = evoid();
}
```
```llvm
define void @entry() #2 !dbg !42 {
Entry:
%error_return_trace_addresses = alloca [30 x i64], align 8
%error_return_trace = alloca %StackTrace, align 8
%x = alloca i16, align 2
%0 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 0
store i64 0, i64* %0, align 8
%1 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 1
%2 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 0
%3 = getelementptr inbounds [30 x i64], [30 x i64]* %error_return_trace_addresses, i64 0, i64 0
store i64* %3, i64** %2, align 8
%4 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 1
store i64 30, i64* %4, align 8
%5 = call fastcc i16 @evoid(%StackTrace* %error_return_trace), !dbg !48
store i16 %5, i16* %x, align 2, !dbg !48
call void @llvm.dbg.declare(metadata i16* %x, metadata !46, metadata !DIExpression()), !dbg !49
ret void, !dbg !50
}
```
---
src/codegen.cpp | 10 ++++++++--
src/ir.cpp | 5 +++--
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index ee17ba72f7c1..74a2e15e79ff 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -4657,7 +4657,13 @@ static LLVMValueRef ir_render_error_union_field_error_set(CodeGen *g, IrExecutab
}
}
-static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) {
+static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable,
+ IrInstructionUnwrapErrPayload *instruction)
+{
+ bool want_safety = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on &&
+ g->errors_by_index.length > 1;
+ if (!want_safety && !type_has_bits(instruction->base.value.type))
+ return nullptr;
ZigType *ptr_type = instruction->value->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *err_union_type = ptr_type->data.pointer.child_type;
@@ -4669,7 +4675,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
return err_union_handle;
}
- if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) {
+ if (want_safety) {
LLVMValueRef err_val;
if (type_has_bits(payload_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
diff --git a/src/ir.cpp b/src/ir.cpp
index e0fdf9a629b0..31029b1c444a 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -14087,11 +14087,11 @@ static IrInstruction *analyze_runtime_call(IrAnalyze *ira, ZigType *return_type,
bool convert_to_value;
ZigType *scalar_result_type;
ZigType *payload_result_type;
- if (return_type->id == ZigTypeIdErrorUnion && handle_is_ptr(return_type)) {
+ if (return_type->id == ZigTypeIdErrorUnion) {
scalar_result_type = get_optional_type(ira->codegen, return_type->data.error_union.err_set_type);
payload_result_type = return_type->data.error_union.payload_type;
convert_to_value = call_instruction->lval != LValErrorUnion;
- } else if (return_type->id == ZigTypeIdOptional && handle_is_ptr(return_type)) {
+ } else if (return_type->id == ZigTypeIdOptional) {
scalar_result_type = ira->codegen->builtin_types.entry_bool;
payload_result_type = return_type->data.maybe.child_type;
convert_to_value = call_instruction->lval != LValOptional;
@@ -20611,6 +20611,7 @@ static IrInstruction *ir_analyze_unwrap_err_payload(IrAnalyze *ira, IrInstructio
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
PtrLenSingle, 0, 0, 0);
+
if (instr_is_comptime(base_ptr)) {
ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad);
if (!ptr_val)
From edd48a58db17f33733d61986e3a3e758fd0b50e7 Mon Sep 17 00:00:00 2001
From: Andrew Kelley