| 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 | 382 | return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int); |
| 383 | 383 | }, |
| 384 | 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 | 386 | .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 387 | 387 | .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?), |
| 388 | 388 | .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| ... | ... | @@ -470,6 +470,39 @@ const Analyze = struct { |
| 470 | 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 | 506 | fn analyzeInstIntCast(self: *Analyze, func: ?*Fn, intcast: *text.Inst.IntCast) InnerError!*Inst { |
| 474 | 507 | const dest_type = try self.resolveType(func, intcast.positionals.dest_type); |
| 475 | 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 | 54 | |
| 55 | 55 | .array, .array_u8_sentinel_0 => return .Array, |
| 56 | 56 | .single_const_pointer => return .Pointer, |
| 57 | .single_const_pointer_to_comptime_int => return .Pointer, | |
| 57 | 58 | .const_slice_u8 => return .Pointer, |
| 58 | 59 | } |
| 59 | 60 | } |
| ... | ... | @@ -127,6 +128,7 @@ pub const Type = extern union { |
| 127 | 128 | |
| 128 | 129 | .const_slice_u8 => return out_stream.writeAll("[]const u8"), |
| 129 | 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 | 133 | .array_u8_sentinel_0 => { |
| 132 | 134 | const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise); |
| ... | ... | @@ -177,6 +179,7 @@ pub const Type = extern union { |
| 177 | 179 | .@"comptime_float" => return Value.initTag(.comptime_float_type), |
| 178 | 180 | .@"noreturn" => return Value.initTag(.noreturn_type), |
| 179 | 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 | 183 | .const_slice_u8 => return Value.initTag(.const_slice_u8_type), |
| 181 | 184 | else => { |
| 182 | 185 | const ty_payload = try allocator.create(Value.Payload.Ty); |
| ... | ... | @@ -219,7 +222,9 @@ pub const Type = extern union { |
| 219 | 222 | .fn_naked_noreturn_no_args, |
| 220 | 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 | 258 | .array, |
| 254 | 259 | .array_u8_sentinel_0, |
| 255 | 260 | .single_const_pointer, |
| 261 | .single_const_pointer_to_comptime_int, | |
| 256 | 262 | .fn_naked_noreturn_no_args, |
| 257 | 263 | => false, |
| 258 | 264 | |
| ... | ... | @@ -293,7 +299,10 @@ pub const Type = extern union { |
| 293 | 299 | .fn_naked_noreturn_no_args, |
| 294 | 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 | 339 | |
| 331 | 340 | .array => self.cast(Payload.Array).?.elem_type, |
| 332 | 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 | 402 | .fn_naked_noreturn_no_args, |
| 354 | 403 | .array, |
| 355 | 404 | .single_const_pointer, |
| 405 | .single_const_pointer_to_comptime_int, | |
| 356 | 406 | .array_u8_sentinel_0, |
| 357 | 407 | .const_slice_u8, |
| 358 | 408 | => unreachable, |
| ... | ... | @@ -380,32 +430,33 @@ pub const Type = extern union { |
| 380 | 430 | /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`. |
| 381 | 431 | pub const Tag = enum { |
| 382 | 432 | // 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, | |
| 408 | 458 | fn_naked_noreturn_no_args, |
| 459 | single_const_pointer_to_comptime_int, | |
| 409 | 460 | const_slice_u8, // See last_no_payload_tag below. |
| 410 | 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 | 44 | comptime_float_type, |
| 45 | 45 | noreturn_type, |
| 46 | 46 | fn_naked_noreturn_no_args_type, |
| 47 | single_const_pointer_to_comptime_int_type, | |
| 47 | 48 | const_slice_u8_type, |
| 48 | 49 | |
| 49 | 50 | void_value, |
| ... | ... | @@ -58,6 +59,7 @@ pub const Value = extern union { |
| 58 | 59 | int_big, |
| 59 | 60 | function, |
| 60 | 61 | ref, |
| 62 | ref_val, | |
| 61 | 63 | bytes, |
| 62 | 64 | |
| 63 | 65 | pub const last_no_payload_tag = Tag.bool_false; |
| ... | ... | @@ -100,7 +102,8 @@ pub const Value = extern union { |
| 100 | 102 | out_stream: var, |
| 101 | 103 | ) !void { |
| 102 | 104 | comptime assert(fmt.len == 0); |
| 103 | switch (self.tag()) { | |
| 105 | var val = self; | |
| 106 | while (true) switch (val.tag()) { | |
| 104 | 107 | .u8_type => return out_stream.writeAll("u8"), |
| 105 | 108 | .i8_type => return out_stream.writeAll("i8"), |
| 106 | 109 | .isize_type => return out_stream.writeAll("isize"), |
| ... | ... | @@ -127,20 +130,26 @@ pub const Value = extern union { |
| 127 | 130 | .comptime_float_type => return out_stream.writeAll("comptime_float"), |
| 128 | 131 | .noreturn_type => return out_stream.writeAll("noreturn"), |
| 129 | 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 | 134 | .const_slice_u8_type => return out_stream.writeAll("[]const u8"), |
| 131 | 135 | |
| 132 | 136 | .void_value => return out_stream.writeAll("{}"), |
| 133 | 137 | .noreturn_value => return out_stream.writeAll("unreachable"), |
| 134 | 138 | .bool_true => return out_stream.writeAll("true"), |
| 135 | 139 | .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}), | |
| 140 | 144 | .function => return out_stream.writeAll("(function)"), |
| 141 | 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 | 151 | .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream), |
| 143 | } | |
| 152 | }; | |
| 144 | 153 | } |
| 145 | 154 | |
| 146 | 155 | /// Asserts that the value is representable as an array of bytes. |
| ... | ... | @@ -183,6 +192,7 @@ pub const Value = extern union { |
| 183 | 192 | .comptime_float_type => Type.initTag(.@"comptime_float"), |
| 184 | 193 | .noreturn_type => Type.initTag(.@"noreturn"), |
| 185 | 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 | 196 | .const_slice_u8_type => Type.initTag(.const_slice_u8), |
| 187 | 197 | |
| 188 | 198 | .void_value, |
| ... | ... | @@ -194,6 +204,7 @@ pub const Value = extern union { |
| 194 | 204 | .int_big, |
| 195 | 205 | .function, |
| 196 | 206 | .ref, |
| 207 | .ref_val, | |
| 197 | 208 | .bytes, |
| 198 | 209 | => unreachable, |
| 199 | 210 | }; |
| ... | ... | @@ -229,6 +240,7 @@ pub const Value = extern union { |
| 229 | 240 | .comptime_float_type, |
| 230 | 241 | .noreturn_type, |
| 231 | 242 | .fn_naked_noreturn_no_args_type, |
| 243 | .single_const_pointer_to_comptime_int_type, | |
| 232 | 244 | .const_slice_u8_type, |
| 233 | 245 | .void_value, |
| 234 | 246 | .noreturn_value, |
| ... | ... | @@ -236,6 +248,7 @@ pub const Value = extern union { |
| 236 | 248 | .bool_false, |
| 237 | 249 | .function, |
| 238 | 250 | .ref, |
| 251 | .ref_val, | |
| 239 | 252 | .bytes, |
| 240 | 253 | => unreachable, |
| 241 | 254 | |
| ... | ... | @@ -311,6 +324,11 @@ pub const Value = extern union { |
| 311 | 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 | 332 | pub const Bytes = struct { |
| 315 | 333 | base: Payload = Payload{ .tag = .bytes }, |
| 316 | 334 | data: []const u8, |