| author | |
| committer | |
| log | 2c11acf807b2f52d076e3e35399d9cd5d038759a |
| tree | 5f33d7a73f4d577d3c1164b616ded7a28bc4a025 |
| parent | c12bc8652ed45dd143932ef0d3a2540c0ef057a4 |
3 files changed, 137 insertions(+), 35 deletions(-)
src-self-hosted/ir.zig+34-1| ... | @@ -382,7 +382,7 @@ const Analyze = struct { | ... | @@ -382,7 +382,7 @@ const Analyze = struct { |
| 382 | return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int); | 382 | return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int); |
| 383 | }, | 383 | }, |
| 384 | .ptrtoint => return self.analyzeInstPtrToInt(func, old_inst.cast(text.Inst.PtrToInt).?), | 384 | .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).?), |
| 386 | .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 386 | .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 387 | .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?), | 387 | .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?), |
| 388 | .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 388 | .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| ... | @@ -470,6 +470,39 @@ const Analyze = struct { | ... | @@ -470,6 +470,39 @@ const Analyze = struct { |
| 470 | return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr }); | 470 | return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr }); |
| 471 | } | 471 | } |
| 472 | 472 | ||
| 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 | |||
| 473 | fn analyzeInstIntCast(self: *Analyze, func: ?*Fn, intcast: *text.Inst.IntCast) InnerError!*Inst { | 506 | fn analyzeInstIntCast(self: *Analyze, func: ?*Fn, intcast: *text.Inst.IntCast) InnerError!*Inst { |
| 474 | const dest_type = try self.resolveType(func, intcast.positionals.dest_type); | 507 | const dest_type = try self.resolveType(func, intcast.positionals.dest_type); |
| 475 | const new_inst = try self.resolveInst(func, intcast.positionals.value); | 508 | 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 { | ... | @@ -54,6 +54,7 @@ pub const Type = extern union { |
| 54 | 54 | ||
| 55 | .array, .array_u8_sentinel_0 => return .Array, | 55 | .array, .array_u8_sentinel_0 => return .Array, |
| 56 | .single_const_pointer => return .Pointer, | 56 | .single_const_pointer => return .Pointer, |
| 57 | .single_const_pointer_to_comptime_int => return .Pointer, | ||
| 57 | .const_slice_u8 => return .Pointer, | 58 | .const_slice_u8 => return .Pointer, |
| 58 | } | 59 | } |
| 59 | } | 60 | } |
| ... | @@ -127,6 +128,7 @@ pub const Type = extern union { | ... | @@ -127,6 +128,7 @@ pub const Type = extern union { |
| 127 | 128 | ||
| 128 | .const_slice_u8 => return out_stream.writeAll("[]const u8"), | 129 | .const_slice_u8 => return out_stream.writeAll("[]const u8"), |
| 129 | .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), | 130 | .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"), | ||
| 130 | 132 | ||
| 131 | .array_u8_sentinel_0 => { | 133 | .array_u8_sentinel_0 => { |
| 132 | const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise); | 134 | const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise); |
| ... | @@ -177,6 +179,7 @@ pub const Type = extern union { | ... | @@ -177,6 +179,7 @@ pub const Type = extern union { |
| 177 | .@"comptime_float" => return Value.initTag(.comptime_float_type), | 179 | .@"comptime_float" => return Value.initTag(.comptime_float_type), |
| 178 | .@"noreturn" => return Value.initTag(.noreturn_type), | 180 | .@"noreturn" => return Value.initTag(.noreturn_type), |
| 179 | .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type), | 181 | .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), | ||
| 180 | .const_slice_u8 => return Value.initTag(.const_slice_u8_type), | 183 | .const_slice_u8 => return Value.initTag(.const_slice_u8_type), |
| 181 | else => { | 184 | else => { |
| 182 | const ty_payload = try allocator.create(Value.Payload.Ty); | 185 | const ty_payload = try allocator.create(Value.Payload.Ty); |
| ... | @@ -219,7 +222,9 @@ pub const Type = extern union { | ... | @@ -219,7 +222,9 @@ pub const Type = extern union { |
| 219 | .fn_naked_noreturn_no_args, | 222 | .fn_naked_noreturn_no_args, |
| 220 | => false, | 223 | => false, |
| 221 | 224 | ||
| 222 | .single_const_pointer => true, | 225 | .single_const_pointer, |
| 226 | .single_const_pointer_to_comptime_int, | ||
| 227 | => true, | ||
| 223 | }; | 228 | }; |
| 224 | } | 229 | } |
| 225 | 230 | ||
| ... | @@ -253,6 +258,7 @@ pub const Type = extern union { | ... | @@ -253,6 +258,7 @@ pub const Type = extern union { |
| 253 | .array, | 258 | .array, |
| 254 | .array_u8_sentinel_0, | 259 | .array_u8_sentinel_0, |
| 255 | .single_const_pointer, | 260 | .single_const_pointer, |
| 261 | .single_const_pointer_to_comptime_int, | ||
| 256 | .fn_naked_noreturn_no_args, | 262 | .fn_naked_noreturn_no_args, |
| 257 | => false, | 263 | => false, |
| 258 | 264 | ||
| ... | @@ -293,7 +299,10 @@ pub const Type = extern union { | ... | @@ -293,7 +299,10 @@ pub const Type = extern union { |
| 293 | .fn_naked_noreturn_no_args, | 299 | .fn_naked_noreturn_no_args, |
| 294 | => unreachable, | 300 | => unreachable, |
| 295 | 301 | ||
| 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, | ||
| 297 | }; | 306 | }; |
| 298 | } | 307 | } |
| 299 | 308 | ||
| ... | @@ -330,7 +339,47 @@ pub const Type = extern union { | ... | @@ -330,7 +339,47 @@ pub const Type = extern union { |
| 330 | 339 | ||
| 331 | .array => self.cast(Payload.Array).?.elem_type, | 340 | .array => self.cast(Payload.Array).?.elem_type, |
| 332 | .single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type, | 341 | .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, | ||
| 334 | }; | 383 | }; |
| 335 | } | 384 | } |
| 336 | 385 | ||
| ... | @@ -353,6 +402,7 @@ pub const Type = extern union { | ... | @@ -353,6 +402,7 @@ pub const Type = extern union { |
| 353 | .fn_naked_noreturn_no_args, | 402 | .fn_naked_noreturn_no_args, |
| 354 | .array, | 403 | .array, |
| 355 | .single_const_pointer, | 404 | .single_const_pointer, |
| 405 | .single_const_pointer_to_comptime_int, | ||
| 356 | .array_u8_sentinel_0, | 406 | .array_u8_sentinel_0, |
| 357 | .const_slice_u8, | 407 | .const_slice_u8, |
| 358 | => unreachable, | 408 | => unreachable, |
| ... | @@ -380,32 +430,33 @@ pub const Type = extern union { | ... | @@ -380,32 +430,33 @@ pub const Type = extern union { |
| 380 | /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`. | 430 | /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`. |
| 381 | pub const Tag = enum { | 431 | pub const Tag = enum { |
| 382 | // The first section of this enum are tags that require no payload. | 432 | // The first section of this enum are tags that require no payload. |
| 383 | @"u8", | 433 | u8, |
| 384 | @"i8", | 434 | i8, |
| 385 | @"isize", | 435 | isize, |
| 386 | @"usize", | 436 | usize, |
| 387 | @"c_short", | 437 | c_short, |
| 388 | @"c_ushort", | 438 | c_ushort, |
| 389 | @"c_int", | 439 | c_int, |
| 390 | @"c_uint", | 440 | c_uint, |
| 391 | @"c_long", | 441 | c_long, |
| 392 | @"c_ulong", | 442 | c_ulong, |
| 393 | @"c_longlong", | 443 | c_longlong, |
| 394 | @"c_ulonglong", | 444 | c_ulonglong, |
| 395 | @"c_longdouble", | 445 | c_longdouble, |
| 396 | @"c_void", | 446 | c_void, |
| 397 | @"f16", | 447 | f16, |
| 398 | @"f32", | 448 | f32, |
| 399 | @"f64", | 449 | f64, |
| 400 | @"f128", | 450 | f128, |
| 401 | @"bool", | 451 | bool, |
| 402 | @"void", | 452 | void, |
| 403 | @"type", | 453 | type, |
| 404 | @"anyerror", | 454 | anyerror, |
| 405 | @"comptime_int", | 455 | comptime_int, |
| 406 | @"comptime_float", | 456 | comptime_float, |
| 407 | @"noreturn", | 457 | noreturn, |
| 408 | fn_naked_noreturn_no_args, | 458 | fn_naked_noreturn_no_args, |
| 459 | single_const_pointer_to_comptime_int, | ||
| 409 | const_slice_u8, // See last_no_payload_tag below. | 460 | const_slice_u8, // See last_no_payload_tag below. |
| 410 | // After this, the tag requires a payload. | 461 | // After this, the tag requires a payload. |
| 411 | 462 |
src-self-hosted/value.zig+24-6| ... | @@ -44,6 +44,7 @@ pub const Value = extern union { | ... | @@ -44,6 +44,7 @@ pub const Value = extern union { |
| 44 | comptime_float_type, | 44 | comptime_float_type, |
| 45 | noreturn_type, | 45 | noreturn_type, |
| 46 | fn_naked_noreturn_no_args_type, | 46 | fn_naked_noreturn_no_args_type, |
| 47 | single_const_pointer_to_comptime_int_type, | ||
| 47 | const_slice_u8_type, | 48 | const_slice_u8_type, |
| 48 | 49 | ||
| 49 | void_value, | 50 | void_value, |
| ... | @@ -58,6 +59,7 @@ pub const Value = extern union { | ... | @@ -58,6 +59,7 @@ pub const Value = extern union { |
| 58 | int_big, | 59 | int_big, |
| 59 | function, | 60 | function, |
| 60 | ref, | 61 | ref, |
| 62 | ref_val, | ||
| 61 | bytes, | 63 | bytes, |
| 62 | 64 | ||
| 63 | pub const last_no_payload_tag = Tag.bool_false; | 65 | pub const last_no_payload_tag = Tag.bool_false; |
| ... | @@ -100,7 +102,8 @@ pub const Value = extern union { | ... | @@ -100,7 +102,8 @@ pub const Value = extern union { |
| 100 | out_stream: var, | 102 | out_stream: var, |
| 101 | ) !void { | 103 | ) !void { |
| 102 | comptime assert(fmt.len == 0); | 104 | comptime assert(fmt.len == 0); |
| 103 | switch (self.tag()) { | 105 | var val = self; |
| 106 | while (true) switch (val.tag()) { | ||
| 104 | .u8_type => return out_stream.writeAll("u8"), | 107 | .u8_type => return out_stream.writeAll("u8"), |
| 105 | .i8_type => return out_stream.writeAll("i8"), | 108 | .i8_type => return out_stream.writeAll("i8"), |
| 106 | .isize_type => return out_stream.writeAll("isize"), | 109 | .isize_type => return out_stream.writeAll("isize"), |
| ... | @@ -127,20 +130,26 @@ pub const Value = extern union { | ... | @@ -127,20 +130,26 @@ pub const Value = extern union { |
| 127 | .comptime_float_type => return out_stream.writeAll("comptime_float"), | 130 | .comptime_float_type => return out_stream.writeAll("comptime_float"), |
| 128 | .noreturn_type => return out_stream.writeAll("noreturn"), | 131 | .noreturn_type => return out_stream.writeAll("noreturn"), |
| 129 | .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), | 132 | .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"), | ||
| 130 | .const_slice_u8_type => return out_stream.writeAll("[]const u8"), | 134 | .const_slice_u8_type => return out_stream.writeAll("[]const u8"), |
| 131 | 135 | ||
| 132 | .void_value => return out_stream.writeAll("{}"), | 136 | .void_value => return out_stream.writeAll("{}"), |
| 133 | .noreturn_value => return out_stream.writeAll("unreachable"), | 137 | .noreturn_value => return out_stream.writeAll("unreachable"), |
| 134 | .bool_true => return out_stream.writeAll("true"), | 138 | .bool_true => return out_stream.writeAll("true"), |
| 135 | .bool_false => return out_stream.writeAll("false"), | 139 | .bool_false => return out_stream.writeAll("false"), |
| 136 | .ty => return self.cast(Payload.Ty).?.ty.format("", options, out_stream), | 140 | .ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream), |
| 137 | .int_u64 => return std.fmt.formatIntValue(self.cast(Payload.Int_u64).?.int, "", options, out_stream), | 141 | .int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream), |
| 138 | .int_i64 => return std.fmt.formatIntValue(self.cast(Payload.Int_i64).?.int, "", options, out_stream), | 142 | .int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream), |
| 139 | .int_big => return out_stream.print("{}", .{self.cast(Payload.IntBig).?.big_int}), | 143 | .int_big => return out_stream.print("{}", .{val.cast(Payload.IntBig).?.big_int}), |
| 140 | .function => return out_stream.writeAll("(function)"), | 144 | .function => return out_stream.writeAll("(function)"), |
| 141 | .ref => return out_stream.writeAll("(ref)"), | 145 | .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 | }, | ||
| 142 | .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream), | 151 | .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream), |
| 143 | } | 152 | }; |
| 144 | } | 153 | } |
| 145 | 154 | ||
| 146 | /// Asserts that the value is representable as an array of bytes. | 155 | /// Asserts that the value is representable as an array of bytes. |
| ... | @@ -183,6 +192,7 @@ pub const Value = extern union { | ... | @@ -183,6 +192,7 @@ pub const Value = extern union { |
| 183 | .comptime_float_type => Type.initTag(.@"comptime_float"), | 192 | .comptime_float_type => Type.initTag(.@"comptime_float"), |
| 184 | .noreturn_type => Type.initTag(.@"noreturn"), | 193 | .noreturn_type => Type.initTag(.@"noreturn"), |
| 185 | .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args), | 194 | .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), | ||
| 186 | .const_slice_u8_type => Type.initTag(.const_slice_u8), | 196 | .const_slice_u8_type => Type.initTag(.const_slice_u8), |
| 187 | 197 | ||
| 188 | .void_value, | 198 | .void_value, |
| ... | @@ -194,6 +204,7 @@ pub const Value = extern union { | ... | @@ -194,6 +204,7 @@ pub const Value = extern union { |
| 194 | .int_big, | 204 | .int_big, |
| 195 | .function, | 205 | .function, |
| 196 | .ref, | 206 | .ref, |
| 207 | .ref_val, | ||
| 197 | .bytes, | 208 | .bytes, |
| 198 | => unreachable, | 209 | => unreachable, |
| 199 | }; | 210 | }; |
| ... | @@ -229,6 +240,7 @@ pub const Value = extern union { | ... | @@ -229,6 +240,7 @@ pub const Value = extern union { |
| 229 | .comptime_float_type, | 240 | .comptime_float_type, |
| 230 | .noreturn_type, | 241 | .noreturn_type, |
| 231 | .fn_naked_noreturn_no_args_type, | 242 | .fn_naked_noreturn_no_args_type, |
| 243 | .single_const_pointer_to_comptime_int_type, | ||
| 232 | .const_slice_u8_type, | 244 | .const_slice_u8_type, |
| 233 | .void_value, | 245 | .void_value, |
| 234 | .noreturn_value, | 246 | .noreturn_value, |
| ... | @@ -236,6 +248,7 @@ pub const Value = extern union { | ... | @@ -236,6 +248,7 @@ pub const Value = extern union { |
| 236 | .bool_false, | 248 | .bool_false, |
| 237 | .function, | 249 | .function, |
| 238 | .ref, | 250 | .ref, |
| 251 | .ref_val, | ||
| 239 | .bytes, | 252 | .bytes, |
| 240 | => unreachable, | 253 | => unreachable, |
| 241 | 254 | ||
| ... | @@ -311,6 +324,11 @@ pub const Value = extern union { | ... | @@ -311,6 +324,11 @@ pub const Value = extern union { |
| 311 | pointee: *MemoryCell, | 324 | pointee: *MemoryCell, |
| 312 | }; | 325 | }; |
| 313 | 326 | ||
| 327 | pub const RefVal = struct { | ||
| 328 | base: Payload = Payload{ .tag = .ref_val }, | ||
| 329 | val: Value, | ||
| 330 | }; | ||
| 331 | |||
| 314 | pub const Bytes = struct { | 332 | pub const Bytes = struct { |
| 315 | base: Payload = Payload{ .tag = .bytes }, | 333 | base: Payload = Payload{ .tag = .bytes }, |
| 316 | data: []const u8, | 334 | data: []const u8, |