authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-20 10:45:23-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2017-04-20 10:45:23-04:00
log68f75a3130d09e1cd86caa1252ff3c4f517a452b
treea04b9bb3fca7fcc650bf7928e7ea5413225d20e7
parent037a9d937d41552a44f8fd597e14a2d3491cb499
parent5234016561ab4a771e908fdff78b2871850626c6

Merge pull request #338 from raulgrell/master

Add `@offsetOf` builtin function

7 files changed, 138 insertions(+), 3 deletions(-)

doc/langref.md+4
...@@ -314,6 +314,10 @@ for the current target....@@ -314,6 +314,10 @@ for the current target.
314314
315The result is a target-specific compile time constant.315The result is a target-specific compile time constant.
316316
317### @offsetOf(comptime T: type, comptime field_name: [] const u8) -> (number literal)
318
319This function returns the byte offset of a field relative to its containing struct.
320
317### Overflow Arithmetic321### Overflow Arithmetic
318322
319These functions take an integer type, two variables of the specified type,323These functions take an integer type, two variables of the specified type,
src/all_types.hpp+9
...@@ -1190,6 +1190,7 @@ enum BuiltinFnId {...@@ -1190,6 +1190,7 @@ enum BuiltinFnId {
1190 BuiltinFnIdIntToPtr,1190 BuiltinFnIdIntToPtr,
1191 BuiltinFnIdEnumTagName,1191 BuiltinFnIdEnumTagName,
1192 BuiltinFnIdFieldParentPtr,1192 BuiltinFnIdFieldParentPtr,
1193 BuiltinFnIdOffsetOf,
1193};1194};
11941195
1195struct BuiltinFnEntry {1196struct BuiltinFnEntry {
...@@ -1742,6 +1743,7 @@ enum IrInstructionId {...@@ -1742,6 +1743,7 @@ enum IrInstructionId {
1742 IrInstructionIdEnumTagName,1743 IrInstructionIdEnumTagName,
1743 IrInstructionIdSetFnRefInline,1744 IrInstructionIdSetFnRefInline,
1744 IrInstructionIdFieldParentPtr,1745 IrInstructionIdFieldParentPtr,
1746 IrInstructionIdOffsetOf,
1745};1747};
17461748
1747struct IrInstruction {1749struct IrInstruction {
...@@ -2503,6 +2505,13 @@ struct IrInstructionFieldParentPtr {...@@ -2503,6 +2505,13 @@ struct IrInstructionFieldParentPtr {
2503 TypeStructField *field;2505 TypeStructField *field;
2504};2506};
25052507
2508struct IrInstructionOffsetOf {
2509 IrInstruction base;
2510
2511 IrInstruction *type_value;
2512 IrInstruction *field_name;
2513};
2514
2506static const size_t slice_ptr_index = 0;2515static const size_t slice_ptr_index = 0;
2507static const size_t slice_len_index = 1;2516static const size_t slice_len_index = 1;
25082517
src/codegen.cpp+2
...@@ -2888,6 +2888,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -2888,6 +2888,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
2888 case IrInstructionIdDeclRef:2888 case IrInstructionIdDeclRef:
2889 case IrInstructionIdSwitchVar:2889 case IrInstructionIdSwitchVar:
2890 case IrInstructionIdSetFnRefInline:2890 case IrInstructionIdSetFnRefInline:
2891 case IrInstructionIdOffsetOf:
2891 zig_unreachable();2892 zig_unreachable();
2892 case IrInstructionIdReturn:2893 case IrInstructionIdReturn:
2893 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);2894 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
...@@ -4548,6 +4549,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -4548,6 +4549,7 @@ static void define_builtin_fns(CodeGen *g) {
4548 create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);4549 create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
4549 create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1);4550 create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1);
4550 create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);4551 create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);
4552 create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);
4551}4553}
45524554
4553static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) {4555static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) {
src/ir.cpp+78
...@@ -553,6 +553,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr *...@@ -553,6 +553,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr *
553 return IrInstructionIdFieldParentPtr;553 return IrInstructionIdFieldParentPtr;
554}554}
555555
556static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) {
557 return IrInstructionIdOffsetOf;
558}
559
556template<typename T>560template<typename T>
557static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {561static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
558 T *special_instruction = allocate<T>(1);562 T *special_instruction = allocate<T>(1);
...@@ -2183,6 +2187,19 @@ static IrInstruction *ir_build_field_parent_ptr(IrBuilder *irb, Scope *scope, As...@@ -2183,6 +2187,19 @@ static IrInstruction *ir_build_field_parent_ptr(IrBuilder *irb, Scope *scope, As
2183 return &instruction->base;2187 return &instruction->base;
2184}2188}
21852189
2190static 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
2186static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {2203static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
2187 return nullptr;2204 return nullptr;
2188}2205}
...@@ -2863,6 +2880,13 @@ static IrInstruction *ir_instruction_fieldparentptr_get_dep(IrInstructionFieldPa...@@ -2863,6 +2880,13 @@ static IrInstruction *ir_instruction_fieldparentptr_get_dep(IrInstructionFieldPa
2863 }2880 }
2864}2881}
28652882
2883static 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}
28662890
2867static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {2891static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
2868 switch (instruction->id) {2892 switch (instruction->id) {
...@@ -3058,6 +3082,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t...@@ -3058,6 +3082,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
3058 return ir_instruction_setfnrefinline_get_dep((IrInstructionSetFnRefInline *) instruction, index);3082 return ir_instruction_setfnrefinline_get_dep((IrInstructionSetFnRefInline *) instruction, index);
3059 case IrInstructionIdFieldParentPtr:3083 case IrInstructionIdFieldParentPtr:
3060 return ir_instruction_fieldparentptr_get_dep((IrInstructionFieldParentPtr *) instruction, index);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 zig_unreachable();3088 zig_unreachable();
3063}3089}
...@@ -4384,6 +4410,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4384,6 +4410,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
43844410
4385 return ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr);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 zig_unreachable();4428 zig_unreachable();
4389}4429}
...@@ -11401,6 +11441,41 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,...@@ -11401,6 +11441,41 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
11401 return result_type;11441 return result_type;
11402}11442}
1140311443
11444static 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
11404static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) {11479static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) {
11405 IrInstruction *type_value = instruction->type_value->other;11480 IrInstruction *type_value = instruction->type_value->other;
11406 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);11481 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
...@@ -12921,6 +12996,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -12921,6 +12996,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
12921 return ir_analyze_instruction_set_fn_ref_inline(ira, (IrInstructionSetFnRefInline *)instruction);12996 return ir_analyze_instruction_set_fn_ref_inline(ira, (IrInstructionSetFnRefInline *)instruction);
12922 case IrInstructionIdFieldParentPtr:12997 case IrInstructionIdFieldParentPtr:
12923 return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction);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 case IrInstructionIdMaybeWrap:13001 case IrInstructionIdMaybeWrap:
12925 case IrInstructionIdErrWrapCode:13002 case IrInstructionIdErrWrapCode:
12926 case IrInstructionIdErrWrapPayload:13003 case IrInstructionIdErrWrapPayload:
...@@ -13108,6 +13185,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -13108,6 +13185,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
13108 case IrInstructionIdEnumTagName:13185 case IrInstructionIdEnumTagName:
13109 case IrInstructionIdSetFnRefInline:13186 case IrInstructionIdSetFnRefInline:
13110 case IrInstructionIdFieldParentPtr:13187 case IrInstructionIdFieldParentPtr:
13188 case IrInstructionIdOffsetOf:
13111 return false;13189 return false;
13112 case IrInstructionIdAsm:13190 case IrInstructionIdAsm:
13113 {13191 {
src/ir_print.cpp+11
...@@ -885,6 +885,14 @@ static void ir_print_field_parent_ptr(IrPrint *irp, IrInstructionFieldParentPtr...@@ -885,6 +885,14 @@ static void ir_print_field_parent_ptr(IrPrint *irp, IrInstructionFieldParentPtr
885 fprintf(irp->f, ")");885 fprintf(irp->f, ")");
886}886}
887887
888static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction) {
889 fprintf(irp->f, "@offset_of(");
890 ir_print_other_instruction(irp, instruction->type_value);
891 fprintf(irp->f, ",");
892 ir_print_other_instruction(irp, instruction->field_name);
893 fprintf(irp->f, ")");
894}
895
888static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {896static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
889 ir_print_prefix(irp, instruction);897 ir_print_prefix(irp, instruction);
890 switch (instruction->id) {898 switch (instruction->id) {
...@@ -1175,6 +1183,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1175,6 +1183,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1175 case IrInstructionIdFieldParentPtr:1183 case IrInstructionIdFieldParentPtr:
1176 ir_print_field_parent_ptr(irp, (IrInstructionFieldParentPtr *)instruction);1184 ir_print_field_parent_ptr(irp, (IrInstructionFieldParentPtr *)instruction);
1177 break;1185 break;
1186 case IrInstructionIdOffsetOf:
1187 ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction);
1188 break;
1178 }1189 }
1179 fprintf(irp->f, "\n");1190 fprintf(irp->f, "\n");
1180}1191}
test/cases/cast.zig+8-3
...@@ -90,15 +90,20 @@ fn castToMaybeTypeError(z: i32) {...@@ -90,15 +90,20 @@ fn castToMaybeTypeError(z: i32) {
90 const f = z;90 const f = z;
91 const g: %?i32 = f;91 const g: %?i32 = f;
9292
93 const a = A{ .a = 1 };93 const a = A{ .a = z };
94 const b: %?A = a;94 const b: %?A = a;
95 assert((??%%b).a == 1);95 assert((??%%b).a == 1);
96}96}
9797
98test "implicitly cast from int to %?T" {98test "implicitly cast from int to %?T" {
99 const f: %?i32 = 1;99 implicitIntLitToMaybe();
100 comptime const g: %?i32 = 1;100 comptime implicitIntLitToMaybe();
101}101}
102fn implicitIntLitToMaybe() {
103 const f: ?i32 = 1;
104 const g: %?i32 = 1;
105}
106
102107
103test "return null from fn() -> %?&T" {108test "return null from fn() -> %?&T" {
104 const a = returnNullFromMaybeTypeErrorRef();109 const a = returnNullFromMaybeTypeErrorRef();
test/cases/sizeof_and_typeof.zig+26
...@@ -6,3 +6,29 @@ test "sizeofAndTypeOf" {...@@ -6,3 +6,29 @@ test "sizeofAndTypeOf" {
6}6}
7const x: u16 = 13;7const x: u16 = 13;
8const z: @typeOf(x) = 19;8const z: @typeOf(x) = 19;
9
10const A = struct {
11 a: u8,
12 b: u32,
13 c: u8,
14};
15
16const P = packed struct {
17 a: u8,
18 b: u32,
19 c: u8,
20};
21
22test "offsetOf" {
23 // Packed structs have fixed memory layout
24 const p: P = undefined;
25 assert(@offsetOf(P, "a") == 0);
26 assert(@offsetOf(@typeOf(p), "b") == 1);
27 assert(@offsetOf(@typeOf(p), "c") == 5);
28
29 // Non-packed struct fields can be moved/padded
30 const a: A = undefined;
31 assert(usize(&a.a) - usize(&a) == @offsetOf(A, "a"));
32 assert(usize(&a.b) - usize(&a) == @offsetOf(@typeOf(a), "b"));
33 assert(usize(&a.c) - usize(&a) == @offsetOf(@typeOf(a), "c"));
34}
\ No newline at end of file