Skip to content

Commit 79c1db5

Browse files
committed
duplicate function
1 parent a95a992 commit 79c1db5

File tree

7 files changed

+157
-36
lines changed

7 files changed

+157
-36
lines changed

doc/langref.html.in

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5780,8 +5780,14 @@ fn add(a: i32, b: i32) i32 {
57805780
</p>
57815781
{#see_also|@inlineCall#}
57825782
{#header_close#}
5783-
{#header_open|@offsetOf#}
5784-
<pre><code class="zig">@offsetOf(comptime T: type, comptime field_name: [] const u8) (number literal)</code></pre>
5783+
{#header_open|@byteOffsetOf#}
5784+
<pre><code class="zig">@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) (number literal)</code></pre>
5785+
<p>
5786+
This function returns the byte offset of a field relative to its containing struct.
5787+
</p>
5788+
{#header_close#}
5789+
{#header_open|@bitOffsetOf#}
5790+
<pre><code class="zig">@bitOffsetOf(comptime T: type, comptime field_name: [] const u8) (number literal)</code></pre>
57855791
<p>
57865792
This function returns the byte offset of a field relative to its containing struct.
57875793
</p>

src/all_types.hpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,7 +1394,8 @@ enum BuiltinFnId {
13941394
BuiltinFnIdTagName,
13951395
BuiltinFnIdTagType,
13961396
BuiltinFnIdFieldParentPtr,
1397-
BuiltinFnIdOffsetOf,
1397+
BuiltinFnIdByteOffsetOf,
1398+
BuiltinFnIdBitOffsetOf,
13981399
BuiltinFnIdInlineCall,
13991400
BuiltinFnIdNoInlineCall,
14001401
BuiltinFnIdNewStackCall,
@@ -2104,7 +2105,8 @@ enum IrInstructionId {
21042105
IrInstructionIdTagName,
21052106
IrInstructionIdTagType,
21062107
IrInstructionIdFieldParentPtr,
2107-
IrInstructionIdOffsetOf,
2108+
IrInstructionIdByteOffsetOf,
2109+
IrInstructionIdBitOffsetOf,
21082110
IrInstructionIdTypeInfo,
21092111
IrInstructionIdTypeId,
21102112
IrInstructionIdSetEvalBranchQuota,
@@ -3005,7 +3007,14 @@ struct IrInstructionFieldParentPtr {
30053007
TypeStructField *field;
30063008
};
30073009

3008-
struct IrInstructionOffsetOf {
3010+
struct IrInstructionByteOffsetOf {
3011+
IrInstruction base;
3012+
3013+
IrInstruction *type_value;
3014+
IrInstruction *field_name;
3015+
};
3016+
3017+
struct IrInstructionBitOffsetOf {
30093018
IrInstruction base;
30103019

30113020
IrInstruction *type_value;

src/codegen.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4835,7 +4835,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
48354835
case IrInstructionIdTypeName:
48364836
case IrInstructionIdDeclRef:
48374837
case IrInstructionIdSwitchVar:
4838-
case IrInstructionIdOffsetOf:
4838+
case IrInstructionIdByteOffsetOf:
4839+
case IrInstructionIdBitOffsetOf:
48394840
case IrInstructionIdTypeInfo:
48404841
case IrInstructionIdTypeId:
48414842
case IrInstructionIdSetEvalBranchQuota:
@@ -6425,7 +6426,8 @@ static void define_builtin_fns(CodeGen *g) {
64256426
create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1);
64266427
create_builtin_fn(g, BuiltinFnIdTagType, "TagType", 1);
64276428
create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);
6428-
create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);
6429+
create_builtin_fn(g, BuiltinFnIdByteOffsetOf, "byteOffsetOf", 2);
6430+
create_builtin_fn(g, BuiltinFnIdBitOffsetOf, "bitOffsetOf", 2);
64296431
create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2);
64306432
create_builtin_fn(g, BuiltinFnIdDivTrunc, "divTrunc", 2);
64316433
create_builtin_fn(g, BuiltinFnIdDivFloor, "divFloor", 2);

src/ir.cpp

Lines changed: 92 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -692,8 +692,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr *
692692
return IrInstructionIdFieldParentPtr;
693693
}
694694

695-
static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) {
696-
return IrInstructionIdOffsetOf;
695+
static constexpr IrInstructionId ir_instruction_id(IrInstructionByteOffsetOf *) {
696+
return IrInstructionIdByteOffsetOf;
697+
}
698+
699+
static constexpr IrInstructionId ir_instruction_id(IrInstructionBitOffsetOf *) {
700+
return IrInstructionIdBitOffsetOf;
697701
}
698702

699703
static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) {
@@ -2609,10 +2613,23 @@ static IrInstruction *ir_build_field_parent_ptr(IrBuilder *irb, Scope *scope, As
26092613
return &instruction->base;
26102614
}
26112615

2612-
static IrInstruction *ir_build_offset_of(IrBuilder *irb, Scope *scope, AstNode *source_node,
2616+
static IrInstruction *ir_build_byte_offset_of(IrBuilder *irb, Scope *scope, AstNode *source_node,
2617+
IrInstruction *type_value, IrInstruction *field_name)
2618+
{
2619+
IrInstructionByteOffsetOf *instruction = ir_build_instruction<IrInstructionByteOffsetOf>(irb, scope, source_node);
2620+
instruction->type_value = type_value;
2621+
instruction->field_name = field_name;
2622+
2623+
ir_ref_instruction(type_value, irb->current_basic_block);
2624+
ir_ref_instruction(field_name, irb->current_basic_block);
2625+
2626+
return &instruction->base;
2627+
}
2628+
2629+
static IrInstruction *ir_build_bit_offset_of(IrBuilder *irb, Scope *scope, AstNode *source_node,
26132630
IrInstruction *type_value, IrInstruction *field_name)
26142631
{
2615-
IrInstructionOffsetOf *instruction = ir_build_instruction<IrInstructionOffsetOf>(irb, scope, source_node);
2632+
IrInstructionBitOffsetOf *instruction = ir_build_instruction<IrInstructionBitOffsetOf>(irb, scope, source_node);
26162633
instruction->type_value = type_value;
26172634
instruction->field_name = field_name;
26182635

@@ -4644,7 +4661,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
46444661
IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr);
46454662
return ir_lval_wrap(irb, scope, field_parent_ptr, lval);
46464663
}
4647-
case BuiltinFnIdOffsetOf:
4664+
case BuiltinFnIdByteOffsetOf:
46484665
{
46494666
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
46504667
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
@@ -4656,7 +4673,22 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
46564673
if (arg1_value == irb->codegen->invalid_instruction)
46574674
return arg1_value;
46584675

4659-
IrInstruction *offset_of = ir_build_offset_of(irb, scope, node, arg0_value, arg1_value);
4676+
IrInstruction *offset_of = ir_build_byte_offset_of(irb, scope, node, arg0_value, arg1_value);
4677+
return ir_lval_wrap(irb, scope, offset_of, lval);
4678+
}
4679+
case BuiltinFnIdBitOffsetOf:
4680+
{
4681+
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4682+
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4683+
if (arg0_value == irb->codegen->invalid_instruction)
4684+
return arg0_value;
4685+
4686+
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4687+
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4688+
if (arg1_value == irb->codegen->invalid_instruction)
4689+
return arg1_value;
4690+
4691+
IrInstruction *offset_of = ir_build_bit_offset_of(irb, scope, node, arg0_value, arg1_value);
46604692
return ir_lval_wrap(irb, scope, offset_of, lval);
46614693
}
46624694
case BuiltinFnIdInlineCall:
@@ -16705,10 +16737,55 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
1670516737
return result_type;
1670616738
}
1670716739

16708-
static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira,
16709-
IrInstructionOffsetOf *instruction)
16740+
static TypeTableEntry *ir_analyze_instruction_byte_offset_of(IrAnalyze *ira,
16741+
IrInstructionByteOffsetOf *instruction)
16742+
{
16743+
IrInstruction *type_value = instruction->type_value->other;
16744+
TypeTableEntry *container_type = ir_resolve_type(ira, type_value);
16745+
if (type_is_invalid(container_type))
16746+
return ira->codegen->builtin_types.entry_invalid;
16747+
16748+
ensure_complete_type(ira->codegen, container_type);
16749+
if (type_is_invalid(container_type))
16750+
return ira->codegen->builtin_types.entry_invalid;
16751+
16752+
IrInstruction *field_name_value = instruction->field_name->other;
16753+
Buf *field_name = ir_resolve_str(ira, field_name_value);
16754+
if (!field_name)
16755+
return ira->codegen->builtin_types.entry_invalid;
16756+
16757+
if (container_type->id != TypeTableEntryIdStruct) {
16758+
ir_add_error(ira, type_value,
16759+
buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name)));
16760+
return ira->codegen->builtin_types.entry_invalid;
16761+
}
16762+
16763+
TypeStructField *field = find_struct_type_field(container_type, field_name);
16764+
if (field == nullptr) {
16765+
ir_add_error(ira, field_name_value,
16766+
buf_sprintf("struct '%s' has no field '%s'",
16767+
buf_ptr(&container_type->name), buf_ptr(field_name)));
16768+
return ira->codegen->builtin_types.entry_invalid;
16769+
}
16770+
16771+
if (!type_has_bits(field->type_entry)) {
16772+
ir_add_error(ira, field_name_value,
16773+
buf_sprintf("zero-bit field '%s' in struct '%s' has no offset",
16774+
buf_ptr(field_name), buf_ptr(&container_type->name)));
16775+
return ira->codegen->builtin_types.entry_invalid;
16776+
}
16777+
16778+
size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, container_type->type_ref, field->gen_index);
16779+
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
16780+
bigint_init_unsigned(&out_val->data.x_bigint, byte_offset);
16781+
return ira->codegen->builtin_types.entry_num_lit_int;
16782+
}
16783+
16784+
static TypeTableEntry *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira,
16785+
IrInstructionBitOffsetOf *instruction)
1671016786
{
1671116787
IrInstruction *type_value = instruction->type_value->other;
16788+
1671216789
TypeTableEntry *container_type = ir_resolve_type(ira, type_value);
1671316790
if (type_is_invalid(container_type))
1671416791
return ira->codegen->builtin_types.entry_invalid;
@@ -16742,6 +16819,7 @@ static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira,
1674216819
buf_ptr(field_name), buf_ptr(&container_type->name)));
1674316820
return ira->codegen->builtin_types.entry_invalid;
1674416821
}
16822+
1674516823
size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, container_type->type_ref, field->gen_index);
1674616824
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1674716825
bigint_init_unsigned(&out_val->data.x_bigint, byte_offset);
@@ -21089,8 +21167,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
2108921167
return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionTagName *)instruction);
2109021168
case IrInstructionIdFieldParentPtr:
2109121169
return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction);
21092-
case IrInstructionIdOffsetOf:
21093-
return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction);
21170+
case IrInstructionIdByteOffsetOf:
21171+
return ir_analyze_instruction_byte_offset_of(ira, (IrInstructionByteOffsetOf *)instruction);
21172+
case IrInstructionIdBitOffsetOf:
21173+
return ir_analyze_instruction_bit_offset_of(ira, (IrInstructionBitOffsetOf *)instruction);
2109421174
case IrInstructionIdTypeInfo:
2109521175
return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction);
2109621176
case IrInstructionIdTypeId:
@@ -21368,7 +21448,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2136821448
case IrInstructionIdTypeName:
2136921449
case IrInstructionIdTagName:
2137021450
case IrInstructionIdFieldParentPtr:
21371-
case IrInstructionIdOffsetOf:
21451+
case IrInstructionIdByteOffsetOf:
21452+
case IrInstructionIdBitOffsetOf:
2137221453
case IrInstructionIdTypeInfo:
2137321454
case IrInstructionIdTypeId:
2137421455
case IrInstructionIdAlignCast:

src/ir_print.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,8 +1033,16 @@ static void ir_print_field_parent_ptr(IrPrint *irp, IrInstructionFieldParentPtr
10331033
fprintf(irp->f, ")");
10341034
}
10351035

1036-
static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction) {
1037-
fprintf(irp->f, "@offset_of(");
1036+
static void ir_print_byte_offset_of(IrPrint *irp, IrInstructionByteOffsetOf *instruction) {
1037+
fprintf(irp->f, "@byte_offset_of(");
1038+
ir_print_other_instruction(irp, instruction->type_value);
1039+
fprintf(irp->f, ",");
1040+
ir_print_other_instruction(irp, instruction->field_name);
1041+
fprintf(irp->f, ")");
1042+
}
1043+
1044+
static void ir_print_bit_offset_of(IrPrint *irp, IrInstructionBitOffsetOf *instruction) {
1045+
fprintf(irp->f, "@bit_offset_of(");
10381046
ir_print_other_instruction(irp, instruction->type_value);
10391047
fprintf(irp->f, ",");
10401048
ir_print_other_instruction(irp, instruction->field_name);
@@ -1641,8 +1649,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
16411649
case IrInstructionIdFieldParentPtr:
16421650
ir_print_field_parent_ptr(irp, (IrInstructionFieldParentPtr *)instruction);
16431651
break;
1644-
case IrInstructionIdOffsetOf:
1645-
ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction);
1652+
case IrInstructionIdByteOffsetOf:
1653+
ir_print_byte_offset_of(irp, (IrInstructionByteOffsetOf *)instruction);
1654+
break;
1655+
case IrInstructionIdBitOffsetOf:
1656+
ir_print_bit_offset_of(irp, (IrInstructionBitOffsetOf *)instruction);
16461657
break;
16471658
case IrInstructionIdTypeInfo:
16481659
ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction);

test/cases/sizeof_and_typeof.zig

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ const P = packed struct {
1919
c: u8,
2020
};
2121

22-
test "offsetOf" {
22+
test "byteOffsetOf" {
2323
// Packed structs have fixed memory layout
2424
const p: P = undefined;
25-
assert(@offsetOf(P, "a") == 0);
26-
assert(@offsetOf(@typeOf(p), "b") == 1);
27-
assert(@offsetOf(@typeOf(p), "c") == 5);
25+
assert(@byteOffsetOf(P, "a") == 0);
26+
assert(@byteOffsetOf(@typeOf(p), "b") == 1);
27+
assert(@byteOffsetOf(@typeOf(p), "c") == 5);
2828

2929
// Non-packed struct fields can be moved/padded
3030
const a: A = undefined;
31-
assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @offsetOf(A, "a"));
32-
assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @offsetOf(@typeOf(a), "b"));
33-
assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @offsetOf(@typeOf(a), "c"));
34-
}
31+
assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a"));
32+
assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(@typeOf(a), "b"));
33+
assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(@typeOf(a), "c"));
34+
}

test/compile_errors.zig

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3450,22 +3450,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
34503450
);
34513451

34523452
cases.add(
3453-
"@offsetOf - non struct",
3453+
"@byteOffsetOf - non struct",
34543454
\\const Foo = i32;
34553455
\\export fn foo() usize {
3456-
\\ return @offsetOf(Foo, "a",);
3456+
\\ return @byteOffsetOf(Foo, "a",);
34573457
\\}
34583458
,
34593459
".tmp_source.zig:3:22: error: expected struct type, found 'i32'",
34603460
);
34613461

34623462
cases.add(
3463-
"@offsetOf - bad field name",
3463+
"@byteOffsetOf - bad field name",
34643464
\\const Foo = struct {
34653465
\\ derp: i32,
34663466
\\};
34673467
\\export fn foo() usize {
3468-
\\ return @offsetOf(Foo, "a",);
3468+
\\ return @byteOffsetOf(Foo, "a",);
34693469
\\}
34703470
,
34713471
".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'",
@@ -4773,12 +4773,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47734773
);
47744774

47754775
cases.add(
4776-
"taking offset of void field in struct",
4776+
"taking byte offset of void field in struct",
47774777
\\const Empty = struct {
47784778
\\ val: void,
47794779
\\};
47804780
\\export fn foo() void {
4781-
\\ const fieldOffset = @offsetOf(Empty, "val",);
4781+
\\ const fieldOffset = @byteOffsetOf(Empty, "val",);
4782+
\\}
4783+
,
4784+
".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset",
4785+
);
4786+
4787+
cases.add(
4788+
"taking bit offset of void field in struct",
4789+
\\const Empty = struct {
4790+
\\ val: void,
4791+
\\};
4792+
\\export fn foo() void {
4793+
\\ const fieldOffset = @bitOffsetOf(Empty, "val",);
47824794
\\}
47834795
,
47844796
".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset",

0 commit comments

Comments
 (0)