| author | |
| committer | |
| log | 09a1162af57858a9579ef112b75472f82581e1d3 |
| tree | 7d955ccaf912924421807ff84ea24e0e90020da6 |
| parent | b18af37c578b118a245c911508d73ed23c303ee0 |
7 files changed, 176 insertions(+), 56 deletions(-)
doc/langref.html.in+8-2| ... | @@ -5838,8 +5838,14 @@ fn add(a: i32, b: i32) i32 { | ... | @@ -5838,8 +5838,14 @@ fn add(a: i32, b: i32) i32 { |
| 5838 | </p> | 5838 | </p> |
| 5839 | {#see_also|@inlineCall#} | 5839 | {#see_also|@inlineCall#} |
| 5840 | {#header_close#} | 5840 | {#header_close#} |
| 5841 | {#header_open|@offsetOf#} | 5841 | {#header_open|@byteOffsetOf#} |
| 5842 | <pre><code class="zig">@offsetOf(comptime T: type, comptime field_name: [] const u8) (number literal)</code></pre> | 5842 | <pre><code class="zig">@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) (number literal)</code></pre> |
| 5843 | <p> | ||
| 5844 | This function returns the byte offset of a field relative to its containing struct. | ||
| 5845 | </p> | ||
| 5846 | {#header_close#} | ||
| 5847 | {#header_open|@bitOffsetOf#} | ||
| 5848 | <pre><code class="zig">@bitOffsetOf(comptime T: type, comptime field_name: [] const u8) (number literal)</code></pre> | ||
| 5843 | <p> | 5849 | <p> |
| 5844 | This function returns the byte offset of a field relative to its containing struct. | 5850 | This function returns the byte offset of a field relative to its containing struct. |
| 5845 | </p> | 5851 | </p> |
src/all_types.hpp+12-3| ... | @@ -1395,7 +1395,8 @@ enum BuiltinFnId { | ... | @@ -1395,7 +1395,8 @@ enum BuiltinFnId { |
| 1395 | BuiltinFnIdTagName, | 1395 | BuiltinFnIdTagName, |
| 1396 | BuiltinFnIdTagType, | 1396 | BuiltinFnIdTagType, |
| 1397 | BuiltinFnIdFieldParentPtr, | 1397 | BuiltinFnIdFieldParentPtr, |
| 1398 | BuiltinFnIdOffsetOf, | 1398 | BuiltinFnIdByteOffsetOf, |
| 1399 | BuiltinFnIdBitOffsetOf, | ||
| 1399 | BuiltinFnIdInlineCall, | 1400 | BuiltinFnIdInlineCall, |
| 1400 | BuiltinFnIdNoInlineCall, | 1401 | BuiltinFnIdNoInlineCall, |
| 1401 | BuiltinFnIdNewStackCall, | 1402 | BuiltinFnIdNewStackCall, |
| ... | @@ -2119,7 +2120,8 @@ enum IrInstructionId { | ... | @@ -2119,7 +2120,8 @@ enum IrInstructionId { |
| 2119 | IrInstructionIdTagName, | 2120 | IrInstructionIdTagName, |
| 2120 | IrInstructionIdTagType, | 2121 | IrInstructionIdTagType, |
| 2121 | IrInstructionIdFieldParentPtr, | 2122 | IrInstructionIdFieldParentPtr, |
| 2122 | IrInstructionIdOffsetOf, | 2123 | IrInstructionIdByteOffsetOf, |
| 2124 | IrInstructionIdBitOffsetOf, | ||
| 2123 | IrInstructionIdTypeInfo, | 2125 | IrInstructionIdTypeInfo, |
| 2124 | IrInstructionIdTypeId, | 2126 | IrInstructionIdTypeId, |
| 2125 | IrInstructionIdSetEvalBranchQuota, | 2127 | IrInstructionIdSetEvalBranchQuota, |
| ... | @@ -3022,7 +3024,14 @@ struct IrInstructionFieldParentPtr { | ... | @@ -3022,7 +3024,14 @@ struct IrInstructionFieldParentPtr { |
| 3022 | TypeStructField *field; | 3024 | TypeStructField *field; |
| 3023 | }; | 3025 | }; |
| 3024 | 3026 | ||
| 3025 | struct IrInstructionOffsetOf { | 3027 | struct IrInstructionByteOffsetOf { |
| 3028 | IrInstruction base; | ||
| 3029 | |||
| 3030 | IrInstruction *type_value; | ||
| 3031 | IrInstruction *field_name; | ||
| 3032 | }; | ||
| 3033 | |||
| 3034 | struct IrInstructionBitOffsetOf { | ||
| 3026 | IrInstruction base; | 3035 | IrInstruction base; |
| 3027 | 3036 | ||
| 3028 | IrInstruction *type_value; | 3037 | IrInstruction *type_value; |
src/codegen.cpp+4-2| ... | @@ -5194,7 +5194,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5194,7 +5194,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5194 | case IrInstructionIdTypeName: | 5194 | case IrInstructionIdTypeName: |
| 5195 | case IrInstructionIdDeclRef: | 5195 | case IrInstructionIdDeclRef: |
| 5196 | case IrInstructionIdSwitchVar: | 5196 | case IrInstructionIdSwitchVar: |
| 5197 | case IrInstructionIdOffsetOf: | 5197 | case IrInstructionIdByteOffsetOf: |
| 5198 | case IrInstructionIdBitOffsetOf: | ||
| 5198 | case IrInstructionIdTypeInfo: | 5199 | case IrInstructionIdTypeInfo: |
| 5199 | case IrInstructionIdTypeId: | 5200 | case IrInstructionIdTypeId: |
| 5200 | case IrInstructionIdSetEvalBranchQuota: | 5201 | case IrInstructionIdSetEvalBranchQuota: |
| ... | @@ -6766,7 +6767,8 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -6766,7 +6767,8 @@ static void define_builtin_fns(CodeGen *g) { |
| 6766 | create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1); | 6767 | create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1); |
| 6767 | create_builtin_fn(g, BuiltinFnIdTagType, "TagType", 1); | 6768 | create_builtin_fn(g, BuiltinFnIdTagType, "TagType", 1); |
| 6768 | create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3); | 6769 | create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3); |
| 6769 | create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2); | 6770 | create_builtin_fn(g, BuiltinFnIdByteOffsetOf, "byteOffsetOf", 2); |
| 6771 | create_builtin_fn(g, BuiltinFnIdBitOffsetOf, "bitOffsetOf", 2); | ||
| 6770 | create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2); | 6772 | create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2); |
| 6771 | create_builtin_fn(g, BuiltinFnIdDivTrunc, "divTrunc", 2); | 6773 | create_builtin_fn(g, BuiltinFnIdDivTrunc, "divTrunc", 2); |
| 6772 | create_builtin_fn(g, BuiltinFnIdDivFloor, "divFloor", 2); | 6774 | create_builtin_fn(g, BuiltinFnIdDivFloor, "divFloor", 2); |
src/ir.cpp+91-27| ... | @@ -719,8 +719,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr * | ... | @@ -719,8 +719,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr * |
| 719 | return IrInstructionIdFieldParentPtr; | 719 | return IrInstructionIdFieldParentPtr; |
| 720 | } | 720 | } |
| 721 | 721 | ||
| 722 | static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) { | 722 | static constexpr IrInstructionId ir_instruction_id(IrInstructionByteOffsetOf *) { |
| 723 | return IrInstructionIdOffsetOf; | 723 | return IrInstructionIdByteOffsetOf; |
| 724 | } | ||
| 725 | |||
| 726 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBitOffsetOf *) { | ||
| 727 | return IrInstructionIdBitOffsetOf; | ||
| 724 | } | 728 | } |
| 725 | 729 | ||
| 726 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) { | 730 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) { |
| ... | @@ -2645,10 +2649,23 @@ static IrInstruction *ir_build_field_parent_ptr(IrBuilder *irb, Scope *scope, As | ... | @@ -2645,10 +2649,23 @@ static IrInstruction *ir_build_field_parent_ptr(IrBuilder *irb, Scope *scope, As |
| 2645 | return &instruction->base; | 2649 | return &instruction->base; |
| 2646 | } | 2650 | } |
| 2647 | 2651 | ||
| 2648 | static IrInstruction *ir_build_offset_of(IrBuilder *irb, Scope *scope, AstNode *source_node, | 2652 | static IrInstruction *ir_build_byte_offset_of(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2653 | IrInstruction *type_value, IrInstruction *field_name) | ||
| 2654 | { | ||
| 2655 | IrInstructionByteOffsetOf *instruction = ir_build_instruction<IrInstructionByteOffsetOf>(irb, scope, source_node); | ||
| 2656 | instruction->type_value = type_value; | ||
| 2657 | instruction->field_name = field_name; | ||
| 2658 | |||
| 2659 | ir_ref_instruction(type_value, irb->current_basic_block); | ||
| 2660 | ir_ref_instruction(field_name, irb->current_basic_block); | ||
| 2661 | |||
| 2662 | return &instruction->base; | ||
| 2663 | } | ||
| 2664 | |||
| 2665 | static IrInstruction *ir_build_bit_offset_of(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 2649 | IrInstruction *type_value, IrInstruction *field_name) | 2666 | IrInstruction *type_value, IrInstruction *field_name) |
| 2650 | { | 2667 | { |
| 2651 | IrInstructionOffsetOf *instruction = ir_build_instruction<IrInstructionOffsetOf>(irb, scope, source_node); | 2668 | IrInstructionBitOffsetOf *instruction = ir_build_instruction<IrInstructionBitOffsetOf>(irb, scope, source_node); |
| 2652 | instruction->type_value = type_value; | 2669 | instruction->type_value = type_value; |
| 2653 | instruction->field_name = field_name; | 2670 | instruction->field_name = field_name; |
| 2654 | 2671 | ||
| ... | @@ -4695,7 +4712,22 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4695,7 +4712,22 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4695 | IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr); | 4712 | IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr); |
| 4696 | return ir_lval_wrap(irb, scope, field_parent_ptr, lval); | 4713 | return ir_lval_wrap(irb, scope, field_parent_ptr, lval); |
| 4697 | } | 4714 | } |
| 4698 | case BuiltinFnIdOffsetOf: | 4715 | case BuiltinFnIdByteOffsetOf: |
| 4716 | { | ||
| 4717 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4718 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 4719 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 4720 | return arg0_value; | ||
| 4721 | |||
| 4722 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 4723 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 4724 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 4725 | return arg1_value; | ||
| 4726 | |||
| 4727 | IrInstruction *offset_of = ir_build_byte_offset_of(irb, scope, node, arg0_value, arg1_value); | ||
| 4728 | return ir_lval_wrap(irb, scope, offset_of, lval); | ||
| 4729 | } | ||
| 4730 | case BuiltinFnIdBitOffsetOf: | ||
| 4699 | { | 4731 | { |
| 4700 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 4732 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 4701 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | 4733 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| ... | @@ -4707,7 +4739,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4707,7 +4739,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4707 | if (arg1_value == irb->codegen->invalid_instruction) | 4739 | if (arg1_value == irb->codegen->invalid_instruction) |
| 4708 | return arg1_value; | 4740 | return arg1_value; |
| 4709 | 4741 | ||
| 4710 | IrInstruction *offset_of = ir_build_offset_of(irb, scope, node, arg0_value, arg1_value); | 4742 | IrInstruction *offset_of = ir_build_bit_offset_of(irb, scope, node, arg0_value, arg1_value); |
| 4711 | return ir_lval_wrap(irb, scope, offset_of, lval); | 4743 | return ir_lval_wrap(irb, scope, offset_of, lval); |
| 4712 | } | 4744 | } |
| 4713 | case BuiltinFnIdInlineCall: | 4745 | case BuiltinFnIdInlineCall: |
| ... | @@ -16909,47 +16941,76 @@ static ZigType *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, | ... | @@ -16909,47 +16941,76 @@ static ZigType *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, |
| 16909 | return result_type; | 16941 | return result_type; |
| 16910 | } | 16942 | } |
| 16911 | 16943 | ||
| 16912 | static ZigType *ir_analyze_instruction_offset_of(IrAnalyze *ira, | 16944 | static TypeStructField *validate_byte_offset(IrAnalyze *ira, |
| 16913 | IrInstructionOffsetOf *instruction) | 16945 | IrInstruction *type_value, |
| 16946 | IrInstruction *field_name_value, | ||
| 16947 | size_t *byte_offset) | ||
| 16914 | { | 16948 | { |
| 16915 | Error err; | ||
| 16916 | IrInstruction *type_value = instruction->type_value->other; | ||
| 16917 | ZigType *container_type = ir_resolve_type(ira, type_value); | 16949 | ZigType *container_type = ir_resolve_type(ira, type_value); |
| 16918 | if (type_is_invalid(container_type)) | 16950 | if (type_is_invalid(container_type)) |
| 16919 | return ira->codegen->builtin_types.entry_invalid; | 16951 | return nullptr; |
| 16920 | 16952 | ||
| 16953 | Error err; | ||
| 16921 | if ((err = ensure_complete_type(ira->codegen, container_type))) | 16954 | if ((err = ensure_complete_type(ira->codegen, container_type))) |
| 16922 | return ira->codegen->builtin_types.entry_invalid; | 16955 | return nullptr; |
| 16923 | 16956 | ||
| 16924 | IrInstruction *field_name_value = instruction->field_name->other; | ||
| 16925 | Buf *field_name = ir_resolve_str(ira, field_name_value); | 16957 | Buf *field_name = ir_resolve_str(ira, field_name_value); |
| 16926 | if (!field_name) | 16958 | if (!field_name) |
| 16927 | return ira->codegen->builtin_types.entry_invalid; | 16959 | return nullptr; |
| 16928 | 16960 | ||
| 16929 | if (container_type->id != ZigTypeIdStruct) { | 16961 | if (container_type->id != ZigTypeIdStruct) { |
| 16930 | ir_add_error(ira, type_value, | 16962 | ir_add_error(ira, type_value, |
| 16931 | buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); | 16963 | buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); |
| 16932 | return ira->codegen->builtin_types.entry_invalid; | 16964 | return nullptr; |
| 16933 | } | 16965 | } |
| 16934 | 16966 | ||
| 16935 | TypeStructField *field = find_struct_type_field(container_type, field_name); | 16967 | TypeStructField *field = find_struct_type_field(container_type, field_name); |
| 16936 | if (field == nullptr) { | 16968 | if (field == nullptr) { |
| 16937 | ir_add_error(ira, field_name_value, | 16969 | ir_add_error(ira, field_name_value, |
| 16938 | buf_sprintf("struct '%s' has no field '%s'", | 16970 | buf_sprintf("struct '%s' has no field '%s'", |
| 16939 | buf_ptr(&container_type->name), buf_ptr(field_name))); | 16971 | buf_ptr(&container_type->name), buf_ptr(field_name))); |
| 16940 | return ira->codegen->builtin_types.entry_invalid; | 16972 | return nullptr; |
| 16941 | } | 16973 | } |
| 16942 | 16974 | ||
| 16943 | if (!type_has_bits(field->type_entry)) { | 16975 | if (!type_has_bits(field->type_entry)) { |
| 16944 | ir_add_error(ira, field_name_value, | 16976 | ir_add_error(ira, field_name_value, |
| 16945 | buf_sprintf("zero-bit field '%s' in struct '%s' has no offset", | 16977 | buf_sprintf("zero-bit field '%s' in struct '%s' has no offset", |
| 16946 | buf_ptr(field_name), buf_ptr(&container_type->name))); | 16978 | buf_ptr(field_name), buf_ptr(&container_type->name))); |
| 16947 | return ira->codegen->builtin_types.entry_invalid; | 16979 | return nullptr; |
| 16948 | } | 16980 | } |
| 16949 | size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, container_type->type_ref, field->gen_index); | 16981 | |
| 16950 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | 16982 | *byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, container_type->type_ref, field->gen_index); |
| 16951 | bigint_init_unsigned(&out_val->data.x_bigint, byte_offset); | 16983 | return field; |
| 16952 | return ira->codegen->builtin_types.entry_num_lit_int; | 16984 | } |
| 16985 | |||
| 16986 | static ZigType *ir_analyze_instruction_byte_offset_of(IrAnalyze *ira, | ||
| 16987 | IrInstructionByteOffsetOf *instruction) | ||
| 16988 | { | ||
| 16989 | IrInstruction *type_value = instruction->type_value->other; | ||
| 16990 | IrInstruction *field_name_value = instruction->field_name->other; | ||
| 16991 | size_t byte_offset = 0; | ||
| 16992 | if (validate_byte_offset(ira, type_value, field_name_value, &byte_offset)) { | ||
| 16993 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | ||
| 16994 | bigint_init_unsigned(&out_val->data.x_bigint, byte_offset); | ||
| 16995 | return ira->codegen->builtin_types.entry_num_lit_int; | ||
| 16996 | } | ||
| 16997 | return ira->codegen->builtin_types.entry_invalid; | ||
| 16998 | } | ||
| 16999 | |||
| 17000 | static ZigType *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira, | ||
| 17001 | IrInstructionBitOffsetOf *instruction) | ||
| 17002 | { | ||
| 17003 | IrInstruction *type_value = instruction->type_value->other; | ||
| 17004 | IrInstruction *field_name_value = instruction->field_name->other; | ||
| 17005 | size_t byte_offset = 0; | ||
| 17006 | TypeStructField *field = nullptr; | ||
| 17007 | if ((field = validate_byte_offset(ira, type_value, field_name_value, &byte_offset))) { | ||
| 17008 | size_t bit_offset = byte_offset * 8 + field->packed_bits_offset; | ||
| 17009 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | ||
| 17010 | bigint_init_unsigned(&out_val->data.x_bigint, bit_offset); | ||
| 17011 | return ira->codegen->builtin_types.entry_num_lit_int; | ||
| 17012 | } | ||
| 17013 | return ira->codegen->builtin_types.entry_invalid; | ||
| 16953 | } | 17014 | } |
| 16954 | 17015 | ||
| 16955 | static void ensure_field_index(ZigType *type, const char *field_name, size_t index) | 17016 | static void ensure_field_index(ZigType *type, const char *field_name, size_t index) |
| ... | @@ -21362,8 +21423,10 @@ static ZigType *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *ins | ... | @@ -21362,8 +21423,10 @@ static ZigType *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *ins |
| 21362 | return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionTagName *)instruction); | 21423 | return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionTagName *)instruction); |
| 21363 | case IrInstructionIdFieldParentPtr: | 21424 | case IrInstructionIdFieldParentPtr: |
| 21364 | return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction); | 21425 | return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction); |
| 21365 | case IrInstructionIdOffsetOf: | 21426 | case IrInstructionIdByteOffsetOf: |
| 21366 | return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction); | 21427 | return ir_analyze_instruction_byte_offset_of(ira, (IrInstructionByteOffsetOf *)instruction); |
| 21428 | case IrInstructionIdBitOffsetOf: | ||
| 21429 | return ir_analyze_instruction_bit_offset_of(ira, (IrInstructionBitOffsetOf *)instruction); | ||
| 21367 | case IrInstructionIdTypeInfo: | 21430 | case IrInstructionIdTypeInfo: |
| 21368 | return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction); | 21431 | return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction); |
| 21369 | case IrInstructionIdTypeId: | 21432 | case IrInstructionIdTypeId: |
| ... | @@ -21647,7 +21710,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -21647,7 +21710,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21647 | case IrInstructionIdTypeName: | 21710 | case IrInstructionIdTypeName: |
| 21648 | case IrInstructionIdTagName: | 21711 | case IrInstructionIdTagName: |
| 21649 | case IrInstructionIdFieldParentPtr: | 21712 | case IrInstructionIdFieldParentPtr: |
| 21650 | case IrInstructionIdOffsetOf: | 21713 | case IrInstructionIdByteOffsetOf: |
| 21714 | case IrInstructionIdBitOffsetOf: | ||
| 21651 | case IrInstructionIdTypeInfo: | 21715 | case IrInstructionIdTypeInfo: |
| 21652 | case IrInstructionIdTypeId: | 21716 | case IrInstructionIdTypeId: |
| 21653 | case IrInstructionIdAlignCast: | 21717 | case IrInstructionIdAlignCast: |
src/ir_print.cpp+15-4| ... | @@ -1041,8 +1041,16 @@ static void ir_print_field_parent_ptr(IrPrint *irp, IrInstructionFieldParentPtr | ... | @@ -1041,8 +1041,16 @@ static void ir_print_field_parent_ptr(IrPrint *irp, IrInstructionFieldParentPtr |
| 1041 | fprintf(irp->f, ")"); | 1041 | fprintf(irp->f, ")"); |
| 1042 | } | 1042 | } |
| 1043 | 1043 | ||
| 1044 | static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction) { | 1044 | static void ir_print_byte_offset_of(IrPrint *irp, IrInstructionByteOffsetOf *instruction) { |
| 1045 | fprintf(irp->f, "@offset_of("); | 1045 | fprintf(irp->f, "@byte_offset_of("); |
| 1046 | ir_print_other_instruction(irp, instruction->type_value); | ||
| 1047 | fprintf(irp->f, ","); | ||
| 1048 | ir_print_other_instruction(irp, instruction->field_name); | ||
| 1049 | fprintf(irp->f, ")"); | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | static void ir_print_bit_offset_of(IrPrint *irp, IrInstructionBitOffsetOf *instruction) { | ||
| 1053 | fprintf(irp->f, "@bit_offset_of("); | ||
| 1046 | ir_print_other_instruction(irp, instruction->type_value); | 1054 | ir_print_other_instruction(irp, instruction->type_value); |
| 1047 | fprintf(irp->f, ","); | 1055 | fprintf(irp->f, ","); |
| 1048 | ir_print_other_instruction(irp, instruction->field_name); | 1056 | ir_print_other_instruction(irp, instruction->field_name); |
| ... | @@ -1649,8 +1657,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1649,8 +1657,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1649 | case IrInstructionIdFieldParentPtr: | 1657 | case IrInstructionIdFieldParentPtr: |
| 1650 | ir_print_field_parent_ptr(irp, (IrInstructionFieldParentPtr *)instruction); | 1658 | ir_print_field_parent_ptr(irp, (IrInstructionFieldParentPtr *)instruction); |
| 1651 | break; | 1659 | break; |
| 1652 | case IrInstructionIdOffsetOf: | 1660 | case IrInstructionIdByteOffsetOf: |
| 1653 | ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction); | 1661 | ir_print_byte_offset_of(irp, (IrInstructionByteOffsetOf *)instruction); |
| 1662 | break; | ||
| 1663 | case IrInstructionIdBitOffsetOf: | ||
| 1664 | ir_print_bit_offset_of(irp, (IrInstructionBitOffsetOf *)instruction); | ||
| 1654 | break; | 1665 | break; |
| 1655 | case IrInstructionIdTypeInfo: | 1666 | case IrInstructionIdTypeInfo: |
| 1656 | ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction); | 1667 | ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction); |
test/cases/sizeof_and_typeof.zig+28-12| ... | @@ -7,28 +7,44 @@ test "sizeofAndTypeOf" { | ... | @@ -7,28 +7,44 @@ test "sizeofAndTypeOf" { |
| 7 | const x: u16 = 13; | 7 | const x: u16 = 13; |
| 8 | const z: @typeOf(x) = 19; | 8 | const z: @typeOf(x) = 19; |
| 9 | 9 | ||
| 10 | const A = struct { | 10 | const S = struct { |
| 11 | a: u8, | 11 | a: u8, |
| 12 | b: u32, | 12 | b: u32, |
| 13 | c: u8, | 13 | c: u8, |
| 14 | d: u3, | ||
| 15 | e: u5, | ||
| 16 | f: u16, | ||
| 17 | g: u16, | ||
| 14 | }; | 18 | }; |
| 15 | 19 | ||
| 16 | const P = packed struct { | 20 | const P = packed struct { |
| 17 | a: u8, | 21 | a: u8, |
| 18 | b: u32, | 22 | b: u32, |
| 19 | c: u8, | 23 | c: u8, |
| 24 | d: u3, | ||
| 25 | e: u5, | ||
| 26 | f: u16, | ||
| 27 | g: u16, | ||
| 20 | }; | 28 | }; |
| 21 | 29 | ||
| 22 | test "offsetOf" { | 30 | test "byteOffsetOf" { |
| 23 | // Packed structs have fixed memory layout | ||
| 24 | const p: P = undefined; | 31 | const p: P = undefined; |
| 25 | assert(@offsetOf(P, "a") == 0); | 32 | std.debug.assert(@byteOffsetOf(P, "a") == 0 and @byteOffsetOf(S, "a") == 0); |
| 26 | assert(@offsetOf(@typeOf(p), "b") == 1); | 33 | std.debug.assert(@byteOffsetOf(P, "b") == 1 and @byteOffsetOf(S, "b") == 4); |
| 27 | assert(@offsetOf(@typeOf(p), "c") == 5); | 34 | std.debug.assert(@byteOffsetOf(P, "c") == 5 and @byteOffsetOf(S, "c") == 8); |
| 28 | 35 | std.debug.assert(@byteOffsetOf(P, "d") == 6 and @byteOffsetOf(S, "d") == 9); | |
| 29 | // Non-packed struct fields can be moved/padded | 36 | std.debug.assert(@byteOffsetOf(P, "e") == 6 and @byteOffsetOf(S, "e") == 10); |
| 30 | const a: A = undefined; | 37 | std.debug.assert(@byteOffsetOf(P, "f") == 7 and @byteOffsetOf(S, "f") == 12); |
| 31 | assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @offsetOf(A, "a")); | 38 | std.debug.assert(@byteOffsetOf(P, "g") == 9 and @byteOffsetOf(S, "g") == 14); |
| 32 | assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @offsetOf(@typeOf(a), "b")); | ||
| 33 | assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @offsetOf(@typeOf(a), "c")); | ||
| 34 | } | 39 | } |
| 40 | |||
| 41 | test "bitOffsetOf" { | ||
| 42 | const p: P = undefined; | ||
| 43 | std.debug.assert(@bitOffsetOf(P, "a") == 0 and @bitOffsetOf(S, "a") == 0); | ||
| 44 | std.debug.assert(@bitOffsetOf(P, "b") == 8 and @bitOffsetOf(S, "b") == 32); | ||
| 45 | std.debug.assert(@bitOffsetOf(P, "c") == 40 and @bitOffsetOf(S, "c") == 64); | ||
| 46 | std.debug.assert(@bitOffsetOf(P, "d") == 48 and @bitOffsetOf(S, "d") == 72); | ||
| 47 | std.debug.assert(@bitOffsetOf(P, "e") == 51 and @bitOffsetOf(S, "e") == 80); | ||
| 48 | std.debug.assert(@bitOffsetOf(P, "f") == 56 and @bitOffsetOf(S, "f") == 96); | ||
| 49 | std.debug.assert(@bitOffsetOf(P, "g") == 72 and @bitOffsetOf(S, "g") == 112); | ||
| 50 | } | ||
| \ No newline at end of file | |||
test/compile_errors.zig+18-6| ... | @@ -3706,22 +3706,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -3706,22 +3706,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3706 | ); | 3706 | ); |
| 3707 | 3707 | ||
| 3708 | cases.add( | 3708 | cases.add( |
| 3709 | "@offsetOf - non struct", | 3709 | "@byteOffsetOf - non struct", |
| 3710 | \\const Foo = i32; | 3710 | \\const Foo = i32; |
| 3711 | \\export fn foo() usize { | 3711 | \\export fn foo() usize { |
| 3712 | \\ return @offsetOf(Foo, "a",); | 3712 | \\ return @byteOffsetOf(Foo, "a",); |
| 3713 | \\} | 3713 | \\} |
| 3714 | , | 3714 | , |
| 3715 | ".tmp_source.zig:3:22: error: expected struct type, found 'i32'", | 3715 | ".tmp_source.zig:3:22: error: expected struct type, found 'i32'", |
| 3716 | ); | 3716 | ); |
| 3717 | 3717 | ||
| 3718 | cases.add( | 3718 | cases.add( |
| 3719 | "@offsetOf - bad field name", | 3719 | "@byteOffsetOf - bad field name", |
| 3720 | \\const Foo = struct { | 3720 | \\const Foo = struct { |
| 3721 | \\ derp: i32, | 3721 | \\ derp: i32, |
| 3722 | \\}; | 3722 | \\}; |
| 3723 | \\export fn foo() usize { | 3723 | \\export fn foo() usize { |
| 3724 | \\ return @offsetOf(Foo, "a",); | 3724 | \\ return @byteOffsetOf(Foo, "a",); |
| 3725 | \\} | 3725 | \\} |
| 3726 | , | 3726 | , |
| 3727 | ".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'", | 3727 | ".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'", |
| ... | @@ -5029,12 +5029,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -5029,12 +5029,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5029 | ); | 5029 | ); |
| 5030 | 5030 | ||
| 5031 | cases.add( | 5031 | cases.add( |
| 5032 | "taking offset of void field in struct", | 5032 | "taking byte offset of void field in struct", |
| 5033 | \\const Empty = struct { | 5033 | \\const Empty = struct { |
| 5034 | \\ val: void, | 5034 | \\ val: void, |
| 5035 | \\}; | 5035 | \\}; |
| 5036 | \\export fn foo() void { | 5036 | \\export fn foo() void { |
| 5037 | \\ const fieldOffset = @offsetOf(Empty, "val",); | 5037 | \\ const fieldOffset = @byteOffsetOf(Empty, "val",); |
| 5038 | \\} | ||
| 5039 | , | ||
| 5040 | ".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset", | ||
| 5041 | ); | ||
| 5042 | |||
| 5043 | cases.add( | ||
| 5044 | "taking bit offset of void field in struct", | ||
| 5045 | \\const Empty = struct { | ||
| 5046 | \\ val: void, | ||
| 5047 | \\}; | ||
| 5048 | \\export fn foo() void { | ||
| 5049 | \\ const fieldOffset = @bitOffsetOf(Empty, "val",); | ||
| 5038 | \\} | 5050 | \\} |
| 5039 | , | 5051 | , |
| 5040 | ".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset", | 5052 | ".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset", |