| ... | ... | @@ -553,6 +553,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr * |
| 553 | 553 | return IrInstructionIdFieldParentPtr; |
| 554 | 554 | } |
| 555 | 555 | |
| 556 | static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) { |
| 557 | return IrInstructionIdOffsetOf; |
| 558 | } |
| 559 | |
| 556 | 560 | template<typename T> |
| 557 | 561 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 558 | 562 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -2183,6 +2187,19 @@ static IrInstruction *ir_build_field_parent_ptr(IrBuilder *irb, Scope *scope, As |
| 2183 | 2187 | return &instruction->base; |
| 2184 | 2188 | } |
| 2185 | 2189 | |
| 2190 | static IrInstruction *ir_build_offset_of(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2191 | IrInstruction *type_value, IrInstruction *field_name) |
| 2192 | { |
| 2193 | IrInstructionOffsetOf *instruction = ir_build_instruction<IrInstructionOffsetOf>(irb, scope, source_node); |
| 2194 | instruction->type_value = type_value; |
| 2195 | instruction->field_name = field_name; |
| 2196 | |
| 2197 | ir_ref_instruction(type_value, irb->current_basic_block); |
| 2198 | ir_ref_instruction(field_name, irb->current_basic_block); |
| 2199 | |
| 2200 | return &instruction->base; |
| 2201 | } |
| 2202 | |
| 2186 | 2203 | static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { |
| 2187 | 2204 | return nullptr; |
| 2188 | 2205 | } |
| ... | ... | @@ -2863,6 +2880,13 @@ static IrInstruction *ir_instruction_fieldparentptr_get_dep(IrInstructionFieldPa |
| 2863 | 2880 | } |
| 2864 | 2881 | } |
| 2865 | 2882 | |
| 2883 | static IrInstruction *ir_instruction_offsetof_get_dep(IrInstructionOffsetOf *instruction, size_t index) { |
| 2884 | switch (index) { |
| 2885 | case 0: return instruction->type_value; |
| 2886 | case 1: return instruction->field_name; |
| 2887 | default: return nullptr; |
| 2888 | } |
| 2889 | } |
| 2866 | 2890 | |
| 2867 | 2891 | static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { |
| 2868 | 2892 | switch (instruction->id) { |
| ... | ... | @@ -3058,6 +3082,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3058 | 3082 | return ir_instruction_setfnrefinline_get_dep((IrInstructionSetFnRefInline *) instruction, index); |
| 3059 | 3083 | case IrInstructionIdFieldParentPtr: |
| 3060 | 3084 | return ir_instruction_fieldparentptr_get_dep((IrInstructionFieldParentPtr *) instruction, index); |
| 3085 | case IrInstructionIdOffsetOf: |
| 3086 | return ir_instruction_offsetof_get_dep((IrInstructionOffsetOf *) instruction, index); |
| 3061 | 3087 | } |
| 3062 | 3088 | zig_unreachable(); |
| 3063 | 3089 | } |
| ... | ... | @@ -4384,6 +4410,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4384 | 4410 | |
| 4385 | 4411 | return ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr); |
| 4386 | 4412 | } |
| 4413 | case BuiltinFnIdOffsetOf: |
| 4414 | { |
| 4415 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 4416 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| 4417 | if (arg0_value == irb->codegen->invalid_instruction) |
| 4418 | return arg0_value; |
| 4419 | |
| 4420 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); |
| 4421 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); |
| 4422 | if (arg1_value == irb->codegen->invalid_instruction) |
| 4423 | return arg1_value; |
| 4424 | |
| 4425 | return ir_build_offset_of(irb, scope, node, arg0_value, arg1_value); |
| 4426 | } |
| 4387 | 4427 | } |
| 4388 | 4428 | zig_unreachable(); |
| 4389 | 4429 | } |
| ... | ... | @@ -11401,6 +11441,41 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, |
| 11401 | 11441 | return result_type; |
| 11402 | 11442 | } |
| 11403 | 11443 | |
| 11444 | static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira, |
| 11445 | IrInstructionOffsetOf *instruction) |
| 11446 | { |
| 11447 | IrInstruction *type_value = instruction->type_value->other; |
| 11448 | TypeTableEntry *container_type = ir_resolve_type(ira, type_value); |
| 11449 | if (type_is_invalid(container_type)) |
| 11450 | return ira->codegen->builtin_types.entry_invalid; |
| 11451 | |
| 11452 | ensure_complete_type(ira->codegen, container_type); |
| 11453 | |
| 11454 | IrInstruction *field_name_value = instruction->field_name->other; |
| 11455 | Buf *field_name = ir_resolve_str(ira, field_name_value); |
| 11456 | if (!field_name) |
| 11457 | return ira->codegen->builtin_types.entry_invalid; |
| 11458 | |
| 11459 | if (container_type->id != TypeTableEntryIdStruct) { |
| 11460 | ir_add_error(ira, type_value, |
| 11461 | buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); |
| 11462 | return ira->codegen->builtin_types.entry_invalid; |
| 11463 | } |
| 11464 | |
| 11465 | TypeStructField *field = find_struct_type_field(container_type, field_name); |
| 11466 | if (field == nullptr) { |
| 11467 | ir_add_error(ira, field_name_value, |
| 11468 | buf_sprintf("struct '%s' has no field '%s'", |
| 11469 | buf_ptr(&container_type->name), buf_ptr(field_name))); |
| 11470 | return ira->codegen->builtin_types.entry_invalid; |
| 11471 | } |
| 11472 | |
| 11473 | size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, container_type->type_ref, field->gen_index); |
| 11474 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 11475 | bignum_init_unsigned(&out_val->data.x_bignum, byte_offset); |
| 11476 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 11477 | } |
| 11478 | |
| 11404 | 11479 | static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { |
| 11405 | 11480 | IrInstruction *type_value = instruction->type_value->other; |
| 11406 | 11481 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); |
| ... | ... | @@ -12921,6 +12996,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 12921 | 12996 | return ir_analyze_instruction_set_fn_ref_inline(ira, (IrInstructionSetFnRefInline *)instruction); |
| 12922 | 12997 | case IrInstructionIdFieldParentPtr: |
| 12923 | 12998 | return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction); |
| 12999 | case IrInstructionIdOffsetOf: |
| 13000 | return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction); |
| 12924 | 13001 | case IrInstructionIdMaybeWrap: |
| 12925 | 13002 | case IrInstructionIdErrWrapCode: |
| 12926 | 13003 | case IrInstructionIdErrWrapPayload: |
| ... | ... | @@ -13108,6 +13185,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 13108 | 13185 | case IrInstructionIdEnumTagName: |
| 13109 | 13186 | case IrInstructionIdSetFnRefInline: |
| 13110 | 13187 | case IrInstructionIdFieldParentPtr: |
| 13188 | case IrInstructionIdOffsetOf: |
| 13111 | 13189 | return false; |
| 13112 | 13190 | case IrInstructionIdAsm: |
| 13113 | 13191 | { |