authorgravatar for raulgrell@gmail.comRaul Leal <raulgrell@gmail.com> 2017-04-20 11:36:59+00:00
committergravatar for raulgrell@gmail.comRaul Leal <raulgrell@gmail.com> 2017-04-20 11:53:00+00:00
log5234016561ab4a771e908fdff78b2871850626c6
treea04b9bb3fca7fcc650bf7928e7ea5413225d20e7
parent037a9d937d41552a44f8fd597e14a2d3491cb499

Add @offsetOf builtin function


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

doc/langref.md+4
......@@ -314,6 +314,10 @@ for the current target.
314314
315315The 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
317321### Overflow Arithmetic
318322
319323These functions take an integer type, two variables of the specified type,
src/all_types.hpp+9
......@@ -1190,6 +1190,7 @@ enum BuiltinFnId {
11901190 BuiltinFnIdIntToPtr,
11911191 BuiltinFnIdEnumTagName,
11921192 BuiltinFnIdFieldParentPtr,
1193 BuiltinFnIdOffsetOf,
11931194};
11941195
11951196struct BuiltinFnEntry {
......@@ -1742,6 +1743,7 @@ enum IrInstructionId {
17421743 IrInstructionIdEnumTagName,
17431744 IrInstructionIdSetFnRefInline,
17441745 IrInstructionIdFieldParentPtr,
1746 IrInstructionIdOffsetOf,
17451747};
17461748
17471749struct IrInstruction {
......@@ -2503,6 +2505,13 @@ struct IrInstructionFieldParentPtr {
25032505 TypeStructField *field;
25042506};
25052507
2508struct IrInstructionOffsetOf {
2509 IrInstruction base;
2510
2511 IrInstruction *type_value;
2512 IrInstruction *field_name;
2513};
2514
25062515static const size_t slice_ptr_index = 0;
25072516static 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,
28882888 case IrInstructionIdDeclRef:
28892889 case IrInstructionIdSwitchVar:
28902890 case IrInstructionIdSetFnRefInline:
2891 case IrInstructionIdOffsetOf:
28912892 zig_unreachable();
28922893 case IrInstructionIdReturn:
28932894 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
......@@ -4548,6 +4549,7 @@ static void define_builtin_fns(CodeGen *g) {
45484549 create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
45494550 create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1);
45504551 create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);
4552 create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);
45514553}
45524554
45534555static 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 *
553553 return IrInstructionIdFieldParentPtr;
554554}
555555
556static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) {
557 return IrInstructionIdOffsetOf;
558}
559
556560template<typename T>
557561static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
558562 T *special_instruction = allocate<T>(1);
......@@ -2183,6 +2187,19 @@ static IrInstruction *ir_build_field_parent_ptr(IrBuilder *irb, Scope *scope, As
21832187 return &instruction->base;
21842188}
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
21862203static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
21872204 return nullptr;
21882205}
......@@ -2863,6 +2880,13 @@ static IrInstruction *ir_instruction_fieldparentptr_get_dep(IrInstructionFieldPa
28632880 }
28642881}
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
28672891static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
28682892 switch (instruction->id) {
......@@ -3058,6 +3082,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
30583082 return ir_instruction_setfnrefinline_get_dep((IrInstructionSetFnRefInline *) instruction, index);
30593083 case IrInstructionIdFieldParentPtr:
30603084 return ir_instruction_fieldparentptr_get_dep((IrInstructionFieldParentPtr *) instruction, index);
3085 case IrInstructionIdOffsetOf:
3086 return ir_instruction_offsetof_get_dep((IrInstructionOffsetOf *) instruction, index);
30613087 }
30623088 zig_unreachable();
30633089}
......@@ -4384,6 +4410,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
43844410
43854411 return ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr);
43864412 }
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 }
43874427 }
43884428 zig_unreachable();
43894429}
......@@ -11401,6 +11441,41 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
1140111441 return result_type;
1140211442}
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
1140411479static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) {
1140511480 IrInstruction *type_value = instruction->type_value->other;
1140611481 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
......@@ -12921,6 +12996,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1292112996 return ir_analyze_instruction_set_fn_ref_inline(ira, (IrInstructionSetFnRefInline *)instruction);
1292212997 case IrInstructionIdFieldParentPtr:
1292312998 return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction);
12999 case IrInstructionIdOffsetOf:
13000 return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction);
1292413001 case IrInstructionIdMaybeWrap:
1292513002 case IrInstructionIdErrWrapCode:
1292613003 case IrInstructionIdErrWrapPayload:
......@@ -13108,6 +13185,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1310813185 case IrInstructionIdEnumTagName:
1310913186 case IrInstructionIdSetFnRefInline:
1311013187 case IrInstructionIdFieldParentPtr:
13188 case IrInstructionIdOffsetOf:
1311113189 return false;
1311213190 case IrInstructionIdAsm:
1311313191 {
src/ir_print.cpp+11
......@@ -885,6 +885,14 @@ static void ir_print_field_parent_ptr(IrPrint *irp, IrInstructionFieldParentPtr
885885 fprintf(irp->f, ")");
886886}
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
888896static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
889897 ir_print_prefix(irp, instruction);
890898 switch (instruction->id) {
......@@ -1175,6 +1183,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
11751183 case IrInstructionIdFieldParentPtr:
11761184 ir_print_field_parent_ptr(irp, (IrInstructionFieldParentPtr *)instruction);
11771185 break;
1186 case IrInstructionIdOffsetOf:
1187 ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction);
1188 break;
11781189 }
11791190 fprintf(irp->f, "\n");
11801191}
test/cases/cast.zig+8-3
......@@ -90,15 +90,20 @@ fn castToMaybeTypeError(z: i32) {
9090 const f = z;
9191 const g: %?i32 = f;
9292
93 const a = A{ .a = 1 };
93 const a = A{ .a = z };
9494 const b: %?A = a;
9595 assert((??%%b).a == 1);
9696}
9797
9898test "implicitly cast from int to %?T" {
99 const f: %?i32 = 1;
100 comptime const g: %?i32 = 1;
99 implicitIntLitToMaybe();
100 comptime implicitIntLitToMaybe();
101101}
102fn implicitIntLitToMaybe() {
103 const f: ?i32 = 1;
104 const g: %?i32 = 1;
105}
106
102107
103108test "return null from fn() -> %?&T" {
104109 const a = returnNullFromMaybeTypeErrorRef();
test/cases/sizeof_and_typeof.zig+26
......@@ -6,3 +6,29 @@ test "sizeofAndTypeOf" {
66}
77const x: u16 = 13;
88const 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