authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 21:14:56-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 21:14:56-04:00
log2c11acf807b2f52d076e3e35399d9cd5d038759a
tree5f33d7a73f4d577d3c1164b616ded7a28bc4a025
parentc12bc8652ed45dd143932ef0d3a2540c0ef057a4

ir: analyze fieldptr instruction


3 files changed, 137 insertions(+), 35 deletions(-)

src-self-hosted/ir.zig+34-1
......@@ -382,7 +382,7 @@ const Analyze = struct {
382382 return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int);
383383 },
384384 .ptrtoint => return self.analyzeInstPtrToInt(func, old_inst.cast(text.Inst.PtrToInt).?),
385 .fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
385 .fieldptr => return self.analyzeInstFieldPtr(func, old_inst.cast(text.Inst.FieldPtr).?),
386386 .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
387387 .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?),
388388 .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
......@@ -470,6 +470,39 @@ const Analyze = struct {
470470 return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr });
471471 }
472472
473 fn analyzeInstFieldPtr(self: *Analyze, func: ?*Fn, fieldptr: *text.Inst.FieldPtr) InnerError!*Inst {
474 const object_ptr = try self.resolveInst(func, fieldptr.positionals.object_ptr);
475 const field_name = try self.resolveConstString(func, fieldptr.positionals.field_name);
476
477 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
478 .Pointer => object_ptr.ty.elemType(),
479 else => return self.fail(fieldptr.base.src, "expected pointer, found '{}'", .{object_ptr.ty}),
480 };
481 switch (elem_ty.zigTypeTag()) {
482 .Array => {
483 if (mem.eql(u8, field_name, "len")) {
484 const len_payload = try self.arena.allocator.create(Value.Payload.Int_u64);
485 len_payload.* = .{ .int = elem_ty.arrayLen() };
486
487 const ref_payload = try self.arena.allocator.create(Value.Payload.RefVal);
488 ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) };
489
490 return self.constInst(fieldptr.base.src, .{
491 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
492 .val = Value.initPayload(&ref_payload.base),
493 });
494 } else {
495 return self.fail(
496 fieldptr.positionals.field_name.src,
497 "no member named '{}' in '{}'",
498 .{ field_name, elem_ty },
499 );
500 }
501 },
502 else => return self.fail(fieldptr.base.src, "type '{}' does not support field access", .{elem_ty}),
503 }
504 }
505
473506 fn analyzeInstIntCast(self: *Analyze, func: ?*Fn, intcast: *text.Inst.IntCast) InnerError!*Inst {
474507 const dest_type = try self.resolveType(func, intcast.positionals.dest_type);
475508 const new_inst = try self.resolveInst(func, intcast.positionals.value);
src-self-hosted/type.zig+79-28
......@@ -54,6 +54,7 @@ pub const Type = extern union {
5454
5555 .array, .array_u8_sentinel_0 => return .Array,
5656 .single_const_pointer => return .Pointer,
57 .single_const_pointer_to_comptime_int => return .Pointer,
5758 .const_slice_u8 => return .Pointer,
5859 }
5960 }
......@@ -127,6 +128,7 @@ pub const Type = extern union {
127128
128129 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
129130 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
131 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
130132
131133 .array_u8_sentinel_0 => {
132134 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
......@@ -177,6 +179,7 @@ pub const Type = extern union {
177179 .@"comptime_float" => return Value.initTag(.comptime_float_type),
178180 .@"noreturn" => return Value.initTag(.noreturn_type),
179181 .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),
182 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
180183 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
181184 else => {
182185 const ty_payload = try allocator.create(Value.Payload.Ty);
......@@ -219,7 +222,9 @@ pub const Type = extern union {
219222 .fn_naked_noreturn_no_args,
220223 => false,
221224
222 .single_const_pointer => true,
225 .single_const_pointer,
226 .single_const_pointer_to_comptime_int,
227 => true,
223228 };
224229 }
225230
......@@ -253,6 +258,7 @@ pub const Type = extern union {
253258 .array,
254259 .array_u8_sentinel_0,
255260 .single_const_pointer,
261 .single_const_pointer_to_comptime_int,
256262 .fn_naked_noreturn_no_args,
257263 => false,
258264
......@@ -293,7 +299,10 @@ pub const Type = extern union {
293299 .fn_naked_noreturn_no_args,
294300 => unreachable,
295301
296 .single_const_pointer, .const_slice_u8 => true,
302 .single_const_pointer,
303 .single_const_pointer_to_comptime_int,
304 .const_slice_u8,
305 => true,
297306 };
298307 }
299308
......@@ -330,7 +339,47 @@ pub const Type = extern union {
330339
331340 .array => self.cast(Payload.Array).?.elem_type,
332341 .single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type,
333 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.@"u8"),
342 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
343 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
344 };
345 }
346
347 /// Asserts the type is an array.
348 pub fn arrayLen(self: Type) u64 {
349 return switch (self.tag()) {
350 .u8,
351 .i8,
352 .isize,
353 .usize,
354 .c_short,
355 .c_ushort,
356 .c_int,
357 .c_uint,
358 .c_long,
359 .c_ulong,
360 .c_longlong,
361 .c_ulonglong,
362 .c_longdouble,
363 .f16,
364 .f32,
365 .f64,
366 .f128,
367 .c_void,
368 .bool,
369 .void,
370 .type,
371 .anyerror,
372 .comptime_int,
373 .comptime_float,
374 .noreturn,
375 .fn_naked_noreturn_no_args,
376 .single_const_pointer,
377 .single_const_pointer_to_comptime_int,
378 .const_slice_u8,
379 => unreachable,
380
381 .array => self.cast(Payload.Array).?.len,
382 .array_u8_sentinel_0 => self.cast(Payload.Array_u8_Sentinel0).?.len,
334383 };
335384 }
336385
......@@ -353,6 +402,7 @@ pub const Type = extern union {
353402 .fn_naked_noreturn_no_args,
354403 .array,
355404 .single_const_pointer,
405 .single_const_pointer_to_comptime_int,
356406 .array_u8_sentinel_0,
357407 .const_slice_u8,
358408 => unreachable,
......@@ -380,32 +430,33 @@ pub const Type = extern union {
380430 /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`.
381431 pub const Tag = enum {
382432 // The first section of this enum are tags that require no payload.
383 @"u8",
384 @"i8",
385 @"isize",
386 @"usize",
387 @"c_short",
388 @"c_ushort",
389 @"c_int",
390 @"c_uint",
391 @"c_long",
392 @"c_ulong",
393 @"c_longlong",
394 @"c_ulonglong",
395 @"c_longdouble",
396 @"c_void",
397 @"f16",
398 @"f32",
399 @"f64",
400 @"f128",
401 @"bool",
402 @"void",
403 @"type",
404 @"anyerror",
405 @"comptime_int",
406 @"comptime_float",
407 @"noreturn",
433 u8,
434 i8,
435 isize,
436 usize,
437 c_short,
438 c_ushort,
439 c_int,
440 c_uint,
441 c_long,
442 c_ulong,
443 c_longlong,
444 c_ulonglong,
445 c_longdouble,
446 c_void,
447 f16,
448 f32,
449 f64,
450 f128,
451 bool,
452 void,
453 type,
454 anyerror,
455 comptime_int,
456 comptime_float,
457 noreturn,
408458 fn_naked_noreturn_no_args,
459 single_const_pointer_to_comptime_int,
409460 const_slice_u8, // See last_no_payload_tag below.
410461 // After this, the tag requires a payload.
411462
src-self-hosted/value.zig+24-6
......@@ -44,6 +44,7 @@ pub const Value = extern union {
4444 comptime_float_type,
4545 noreturn_type,
4646 fn_naked_noreturn_no_args_type,
47 single_const_pointer_to_comptime_int_type,
4748 const_slice_u8_type,
4849
4950 void_value,
......@@ -58,6 +59,7 @@ pub const Value = extern union {
5859 int_big,
5960 function,
6061 ref,
62 ref_val,
6163 bytes,
6264
6365 pub const last_no_payload_tag = Tag.bool_false;
......@@ -100,7 +102,8 @@ pub const Value = extern union {
100102 out_stream: var,
101103 ) !void {
102104 comptime assert(fmt.len == 0);
103 switch (self.tag()) {
105 var val = self;
106 while (true) switch (val.tag()) {
104107 .u8_type => return out_stream.writeAll("u8"),
105108 .i8_type => return out_stream.writeAll("i8"),
106109 .isize_type => return out_stream.writeAll("isize"),
......@@ -127,20 +130,26 @@ pub const Value = extern union {
127130 .comptime_float_type => return out_stream.writeAll("comptime_float"),
128131 .noreturn_type => return out_stream.writeAll("noreturn"),
129132 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
133 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
130134 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
131135
132136 .void_value => return out_stream.writeAll("{}"),
133137 .noreturn_value => return out_stream.writeAll("unreachable"),
134138 .bool_true => return out_stream.writeAll("true"),
135139 .bool_false => return out_stream.writeAll("false"),
136 .ty => return self.cast(Payload.Ty).?.ty.format("", options, out_stream),
137 .int_u64 => return std.fmt.formatIntValue(self.cast(Payload.Int_u64).?.int, "", options, out_stream),
138 .int_i64 => return std.fmt.formatIntValue(self.cast(Payload.Int_i64).?.int, "", options, out_stream),
139 .int_big => return out_stream.print("{}", .{self.cast(Payload.IntBig).?.big_int}),
140 .ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream),
141 .int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream),
142 .int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream),
143 .int_big => return out_stream.print("{}", .{val.cast(Payload.IntBig).?.big_int}),
140144 .function => return out_stream.writeAll("(function)"),
141145 .ref => return out_stream.writeAll("(ref)"),
146 .ref_val => {
147 try out_stream.writeAll("*const ");
148 val = val.cast(Payload.RefVal).?.val;
149 continue;
150 },
142151 .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),
143 }
152 };
144153 }
145154
146155 /// Asserts that the value is representable as an array of bytes.
......@@ -183,6 +192,7 @@ pub const Value = extern union {
183192 .comptime_float_type => Type.initTag(.@"comptime_float"),
184193 .noreturn_type => Type.initTag(.@"noreturn"),
185194 .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
195 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
186196 .const_slice_u8_type => Type.initTag(.const_slice_u8),
187197
188198 .void_value,
......@@ -194,6 +204,7 @@ pub const Value = extern union {
194204 .int_big,
195205 .function,
196206 .ref,
207 .ref_val,
197208 .bytes,
198209 => unreachable,
199210 };
......@@ -229,6 +240,7 @@ pub const Value = extern union {
229240 .comptime_float_type,
230241 .noreturn_type,
231242 .fn_naked_noreturn_no_args_type,
243 .single_const_pointer_to_comptime_int_type,
232244 .const_slice_u8_type,
233245 .void_value,
234246 .noreturn_value,
......@@ -236,6 +248,7 @@ pub const Value = extern union {
236248 .bool_false,
237249 .function,
238250 .ref,
251 .ref_val,
239252 .bytes,
240253 => unreachable,
241254
......@@ -311,6 +324,11 @@ pub const Value = extern union {
311324 pointee: *MemoryCell,
312325 };
313326
327 pub const RefVal = struct {
328 base: Payload = Payload{ .tag = .ref_val },
329 val: Value,
330 };
331
314332 pub const Bytes = struct {
315333 base: Payload = Payload{ .tag = .bytes },
316334 data: []const u8,