authorgravatar for keyboard.operator@gmail.comRobert Scott <keyboard.operator@gmail.com> 2019-05-09 02:28:14-07:00
committergravatar for keyboard.operator@gmail.comRobert Scott <keyboard.operator@gmail.com> 2019-05-24 01:48:45-07:00
log9b7ad124810e4a3df964927ace449502daa167f9
tree62a6674b3a255fcc76f464029f5b5d2a6cb4d9f3
parent163a8e98bc04ea955ee54d5905436ffac34c93a2

Implement @unionInit


5 files changed, 148 insertions(+), 8 deletions(-)

src/all_types.hpp+13
...@@ -1471,6 +1471,7 @@ enum BuiltinFnId {...@@ -1471,6 +1471,7 @@ enum BuiltinFnId {
1471 BuiltinFnIdErrorReturnTrace,1471 BuiltinFnIdErrorReturnTrace,
1472 BuiltinFnIdAtomicRmw,1472 BuiltinFnIdAtomicRmw,
1473 BuiltinFnIdAtomicLoad,1473 BuiltinFnIdAtomicLoad,
1474 BuiltinFnIdUnionInit,
1474};1475};
14751476
1476struct BuiltinFnEntry {1477struct BuiltinFnEntry {
...@@ -2297,6 +2298,7 @@ enum IrInstructionId {...@@ -2297,6 +2298,7 @@ enum IrInstructionId {
2297 IrInstructionIdArrayToVector,2298 IrInstructionIdArrayToVector,
2298 IrInstructionIdAssertZero,2299 IrInstructionIdAssertZero,
2299 IrInstructionIdAssertNonNull,2300 IrInstructionIdAssertNonNull,
2301 IrInstructionIdUnionInit2,
2300};2302};
23012303
2302struct IrInstruction {2304struct IrInstruction {
...@@ -3503,6 +3505,17 @@ struct IrInstructionAssertNonNull {...@@ -3503,6 +3505,17 @@ struct IrInstructionAssertNonNull {
3503 IrInstruction *target;3505 IrInstruction *target;
3504};3506};
35053507
3508// TODO, need a better name. Using 2 because there is currently a IrInstructionUnionInit
3509// It seems like the first one should only be used during the analyze phase, but still
3510// don't understand it all.
3511struct IrInstructionUnionInit2 {
3512 IrInstruction base;
3513
3514 IrInstruction *union_type_value;
3515 IrInstruction *field_name_expr;
3516 IrInstruction *value;
3517};
3518
3506static const size_t slice_ptr_index = 0;3519static const size_t slice_ptr_index = 0;
3507static const size_t slice_len_index = 1;3520static const size_t slice_len_index = 1;
35083521
src/codegen.cpp+2
...@@ -5616,6 +5616,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5616,6 +5616,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5616 case IrInstructionIdLoadPtr:5616 case IrInstructionIdLoadPtr:
5617 case IrInstructionIdBitCast:5617 case IrInstructionIdBitCast:
5618 case IrInstructionIdGlobalAsm:5618 case IrInstructionIdGlobalAsm:
5619 case IrInstructionIdUnionInit2:
5619 zig_unreachable();5620 zig_unreachable();
56205621
5621 case IrInstructionIdDeclVarGen:5622 case IrInstructionIdDeclVarGen:
...@@ -7409,6 +7410,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -7409,6 +7410,7 @@ static void define_builtin_fns(CodeGen *g) {
7409 create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);7410 create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
7410 create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);7411 create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
7411 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);7412 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
7413 create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3);
7412}7414}
74137415
7414static const char *bool_to_str(bool b) {7416static const char *bool_to_str(bool b) {
src/ir.cpp+83-7
...@@ -188,7 +188,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c...@@ -188,7 +188,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
188 assert(get_src_ptr_type(const_val->type) != nullptr);188 assert(get_src_ptr_type(const_val->type) != nullptr);
189 assert(const_val->special == ConstValSpecialStatic);189 assert(const_val->special == ConstValSpecialStatic);
190 ConstExprValue *result;190 ConstExprValue *result;
191 191
192 switch (type_has_one_possible_value(g, const_val->type->data.pointer.child_type)) {192 switch (type_has_one_possible_value(g, const_val->type->data.pointer.child_type)) {
193 case OnePossibleValueInvalid:193 case OnePossibleValueInvalid:
194 zig_unreachable();194 zig_unreachable();
...@@ -200,7 +200,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c...@@ -200,7 +200,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
200 case OnePossibleValueNo:200 case OnePossibleValueNo:
201 break;201 break;
202 }202 }
203 203
204 switch (const_val->data.x_ptr.special) {204 switch (const_val->data.x_ptr.special) {
205 case ConstPtrSpecialInvalid:205 case ConstPtrSpecialInvalid:
206 zig_unreachable();206 zig_unreachable();
...@@ -1011,6 +1011,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonNull *)...@@ -1011,6 +1011,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonNull *)
1011 return IrInstructionIdAssertNonNull;1011 return IrInstructionIdAssertNonNull;
1012}1012}
10131013
1014static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit2 *) {
1015 return IrInstructionIdUnionInit2;
1016}
1017
1014template<typename T>1018template<typename T>
1015static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {1019static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
1016 T *special_instruction = allocate<T>(1);1020 T *special_instruction = allocate<T>(1);
...@@ -1312,6 +1316,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast...@@ -1312,6 +1316,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast
1312 return &instruction->base;1316 return &instruction->base;
1313}1317}
13141318
1319
1315static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,1320static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
1316 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,1321 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1317 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,1322 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
...@@ -3025,6 +3030,21 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope,...@@ -3025,6 +3030,21 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope,
3025 return &instruction->base;3030 return &instruction->base;
3026}3031}
30273032
3033static IrInstruction *ir_build_union_init_2(IrBuilder *irb, Scope *scope, AstNode *source_node,
3034 IrInstruction *union_type_value, IrInstruction *field_name_expr, IrInstruction *value) {
3035 IrInstructionUnionInit2 *instruction = ir_build_instruction<IrInstructionUnionInit2>(irb, scope, source_node);
3036 instruction->union_type_value = union_type_value;
3037 instruction->field_name_expr = field_name_expr;
3038 instruction->value = value;
3039
3040 ir_ref_instruction(union_type_value, irb->current_basic_block);
3041 ir_ref_instruction(field_name_expr, irb->current_basic_block);
3042 ir_ref_instruction(value, irb->current_basic_block);
3043
3044 return &instruction->base;
3045}
3046
3047
3028static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *source_instruction,3048static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *source_instruction,
3029 IrInstruction *vector, ZigType *result_type)3049 IrInstruction *vector, ZigType *result_type)
3030{3050{
...@@ -3868,7 +3888,7 @@ static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode...@@ -3868,7 +3888,7 @@ static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode
3868 TldVar *tld_var = allocate<TldVar>(1);3888 TldVar *tld_var = allocate<TldVar>(1);
3869 init_tld(&tld_var->base, TldIdVar, var_name, VisibModPub, node, &scope_decls->base);3889 init_tld(&tld_var->base, TldIdVar, var_name, VisibModPub, node, &scope_decls->base);
3870 tld_var->base.resolution = TldResolutionInvalid;3890 tld_var->base.resolution = TldResolutionInvalid;
3871 tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false, 3891 tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false,
3872 &g->invalid_instruction->value, &tld_var->base, g->builtin_types.entry_invalid);3892 &g->invalid_instruction->value, &tld_var->base, g->builtin_types.entry_invalid);
3873 scope_decls->decl_table.put(var_name, &tld_var->base);3893 scope_decls->decl_table.put(var_name, &tld_var->base);
3874}3894}
...@@ -5098,6 +5118,29 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -5098,6 +5118,29 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
5098 }5118 }
5099 return ir_lval_wrap(irb, scope, result, lval);5119 return ir_lval_wrap(irb, scope, result, lval);
5100 }5120 }
5121 case BuiltinFnIdUnionInit:
5122 {
5123
5124 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
5125 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
5126 if (arg0_value == irb->codegen->invalid_instruction)
5127 return arg0_value;
5128
5129 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
5130 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
5131 if (arg1_value == irb->codegen->invalid_instruction)
5132 return arg1_value;
5133
5134 AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
5135 IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
5136 if (arg2_value == irb->codegen->invalid_instruction)
5137 return arg2_value;
5138
5139 IrInstruction *result = ir_build_union_init_2(irb, scope, node, arg0_value, arg1_value, arg2_value);
5140
5141 // TODO: Not sure if we need ir_lval_wrap or not.
5142 return result;
5143 }
5101 }5144 }
5102 zig_unreachable();5145 zig_unreachable();
5103}5146}
...@@ -6328,7 +6371,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit...@@ -6328,7 +6371,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
6328 prong_values, prong_values_len);6371 prong_values, prong_values_len);
6329 var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value);6372 var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value);
6330 } else {6373 } else {
6331 var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, 6374 var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node,
6332target_value_ptr);6375target_value_ptr);
6333 }6376 }
6334 IrInstruction *var_type = nullptr; // infer the type6377 IrInstruction *var_type = nullptr; // infer the type
...@@ -12372,7 +12415,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -12372,7 +12415,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
12372 } else {12415 } else {
12373 return is_non_null;12416 return is_non_null;
12374 }12417 }
12375 } else if (is_equality_cmp && 12418 } else if (is_equality_cmp &&
12376 ((op1->value.type->id == ZigTypeIdNull && op2->value.type->id == ZigTypeIdPointer &&12419 ((op1->value.type->id == ZigTypeIdNull && op2->value.type->id == ZigTypeIdPointer &&
12377 op2->value.type->data.pointer.ptr_len == PtrLenC) ||12420 op2->value.type->data.pointer.ptr_len == PtrLenC) ||
12378 (op2->value.type->id == ZigTypeIdNull && op1->value.type->id == ZigTypeIdPointer &&12421 (op2->value.type->id == ZigTypeIdNull && op1->value.type->id == ZigTypeIdPointer &&
...@@ -19383,7 +19426,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct...@@ -19383,7 +19426,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
19383 ir_add_error_node(ira, node, buf_sprintf("C import failed: unable to make dir: %s", err_str(err)));19426 ir_add_error_node(ira, node, buf_sprintf("C import failed: unable to make dir: %s", err_str(err)));
19384 return ira->codegen->invalid_instruction;19427 return ira->codegen->invalid_instruction;
19385 }19428 }
19386 19429
19387 if ((err = os_write_file(&tmp_c_file_path, &cimport_scope->buf))) {19430 if ((err = os_write_file(&tmp_c_file_path, &cimport_scope->buf))) {
19388 ir_add_error_node(ira, node, buf_sprintf("C import failed: unable to write .h file: %s", err_str(err)));19431 ir_add_error_node(ira, node, buf_sprintf("C import failed: unable to write .h file: %s", err_str(err)));
19389 return ira->codegen->invalid_instruction;19432 return ira->codegen->invalid_instruction;
...@@ -20333,7 +20376,7 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio...@@ -20333,7 +20376,7 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
20333 return ira->codegen->invalid_instruction;20376 return ira->codegen->invalid_instruction;
2033420377
20335 // TODO test this at comptime with u8 and non-u8 types20378 // TODO test this at comptime with u8 and non-u8 types
20336 // TODO test with dest ptr being a global runtime variable 20379 // TODO test with dest ptr being a global runtime variable
20337 if (casted_dest_ptr->value.special == ConstValSpecialStatic &&20380 if (casted_dest_ptr->value.special == ConstValSpecialStatic &&
20338 casted_src_ptr->value.special == ConstValSpecialStatic &&20381 casted_src_ptr->value.special == ConstValSpecialStatic &&
20339 casted_count->value.special == ConstValSpecialStatic &&20382 casted_count->value.special == ConstValSpecialStatic &&
...@@ -23151,6 +23194,35 @@ static IrInstruction *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira,...@@ -23151,6 +23194,35 @@ static IrInstruction *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira,
23151 return ir_const_void(ira, &instruction->base);23194 return ir_const_void(ira, &instruction->base);
23152}23195}
2315323196
23197static IrInstruction *ir_analyze_instruction_union_init_2(IrAnalyze *ira, IrInstructionUnionInit2 *union_init_instruction)
23198{
23199 Error err;
23200 IrInstruction *union_type_value = union_init_instruction->union_type_value->child;
23201 ZigType *union_type = ir_resolve_type(ira, union_type_value);
23202 if (type_is_invalid(union_type)) {
23203 return ira->codegen->invalid_instruction;
23204 }
23205
23206 if (union_type->id != ZigTypeIdUnion)
23207 return ira->codegen->invalid_instruction;
23208
23209 if ((err = ensure_complete_type(ira->codegen, union_type)))
23210 return ira->codegen->invalid_instruction;
23211
23212 IrInstruction *field_name_expr = union_init_instruction->field_name_expr->child;
23213 Buf *field_name = ir_resolve_str(ira, field_name_expr);
23214 if (!field_name)
23215 return ira->codegen->invalid_instruction;
23216
23217 IrInstructionContainerInitFieldsField *fields = allocate<IrInstructionContainerInitFieldsField>(1);
23218
23219 fields[0].name = field_name;
23220 fields[0].value = union_init_instruction->value;
23221 fields[0].source_node = union_init_instruction->base.source_node;
23222
23223 return ir_analyze_container_init_fields_union(ira, &union_init_instruction->base, union_type, 1, fields);
23224}
23225
23154static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {23226static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
23155 switch (instruction->id) {23227 switch (instruction->id) {
23156 case IrInstructionIdInvalid:23228 case IrInstructionIdInvalid:
...@@ -23445,6 +23517,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio...@@ -23445,6 +23517,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
23445 return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);23517 return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);
23446 case IrInstructionIdCheckRuntimeScope:23518 case IrInstructionIdCheckRuntimeScope:
23447 return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction);23519 return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction);
23520 case IrInstructionIdUnionInit2:
23521 return ir_analyze_instruction_union_init_2(ira, (IrInstructionUnionInit2 *)instruction);
23448 }23522 }
23449 zig_unreachable();23523 zig_unreachable();
23450}23524}
...@@ -23681,6 +23755,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -23681,6 +23755,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
23681 case IrInstructionIdEnumToInt:23755 case IrInstructionIdEnumToInt:
23682 case IrInstructionIdVectorToArray:23756 case IrInstructionIdVectorToArray:
23683 case IrInstructionIdArrayToVector:23757 case IrInstructionIdArrayToVector:
23758 case IrInstructionIdUnionInit2:
23759
23684 return false;23760 return false;
2368523761
23686 case IrInstructionIdAsm:23762 case IrInstructionIdAsm:
src/ir_print.cpp+14
...@@ -1453,6 +1453,17 @@ static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_va...@@ -1453,6 +1453,17 @@ static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_va
1453 }1453 }
1454}1454}
14551455
1456
1457static void ir_print_uniont_init_2(IrPrint *irp, IrInstructionUnionInit2 *instruction) {
1458 fprintf(irp->f, "@unionInit(");
1459 ir_print_other_instruction(irp, instruction->union_type_value);
1460 fprintf(irp->f, ", ");
1461 ir_print_other_instruction(irp, instruction->field_name_expr);
1462 fprintf(irp->f, ", ");
1463 ir_print_other_instruction(irp, instruction->value);
1464 fprintf(irp->f, ")");
1465}
1466
1456static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1467static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1457 ir_print_prefix(irp, instruction);1468 ir_print_prefix(irp, instruction);
1458 switch (instruction->id) {1469 switch (instruction->id) {
...@@ -1920,6 +1931,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1920,6 +1931,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1920 case IrInstructionIdResizeSlice:1931 case IrInstructionIdResizeSlice:
1921 ir_print_resize_slice(irp, (IrInstructionResizeSlice *)instruction);1932 ir_print_resize_slice(irp, (IrInstructionResizeSlice *)instruction);
1922 break;1933 break;
1934 case IrInstructionIdUnionInit2:
1935 ir_print_uniont_init_2(irp, (IrInstructionUnionInit2 *)instruction);
1936 break;
1923 }1937 }
1924 fprintf(irp->f, "\n");1938 fprintf(irp->f, "\n");
1925}1939}
test/stage1/behavior/union.zig+36-1
...@@ -374,7 +374,7 @@ const Attribute = union(enum) {...@@ -374,7 +374,7 @@ const Attribute = union(enum) {
374fn setAttribute(attr: Attribute) void {}374fn setAttribute(attr: Attribute) void {}
375375
376fn Setter(attr: Attribute) type {376fn Setter(attr: Attribute) type {
377 return struct{377 return struct {
378 fn set() void {378 fn set() void {
379 setAttribute(attr);379 setAttribute(attr);
380 }380 }
...@@ -402,3 +402,38 @@ test "comptime union field value equality" {...@@ -402,3 +402,38 @@ test "comptime union field value equality" {
402 expect(a0 != a1);402 expect(a0 != a1);
403 expect(b0 != b1);403 expect(b0 != b1);
404}404}
405
406test "unionInit can modify a union type" {
407 const UnionInitEnum = union(enum) {
408 Boolean: bool,
409 Byte: u8,
410 };
411
412 var value: UnionInitEnum = undefined;
413
414 value = @unionInit(UnionInitEnum, "Boolean", true);
415 expect(value.Boolean == true);
416 value.Boolean = false;
417 expect(value.Boolean == false);
418
419 value = @unionInit(UnionInitEnum, "Byte", 2);
420 expect(value.Byte == 2);
421 value.Byte = 3;
422 expect(value.Byte == 3);
423}
424
425test "unionInit can modify a pointer value" {
426 const UnionInitEnum = union(enum) {
427 Boolean: bool,
428 Byte: u8,
429 };
430
431 var value: UnionInitEnum = undefined;
432 var value_ptr = &value;
433
434 value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true);
435 expect(value.Boolean == true);
436
437 value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2);
438 expect(value.Byte == 2);
439}