| author | |
| committer | |
| log | 1d85b588eab27830409a62e88bd8444db58787a4 |
| tree | e997fbe7cad2c8c2548a9568b6c59c558ef095a7 |
| parent | 7f1a550760a7a01d4ae8de51be16fb02d56b5cd2 |
* add c int types
* some more ir stubs10 files changed, 879 insertions(+), 43 deletions(-)
CMakeLists.txt+1| ... | @@ -489,6 +489,7 @@ set(ZIG_STD_FILES | ... | @@ -489,6 +489,7 @@ set(ZIG_STD_FILES |
| 489 | "math/atan.zig" | 489 | "math/atan.zig" |
| 490 | "math/atan2.zig" | 490 | "math/atan2.zig" |
| 491 | "math/atanh.zig" | 491 | "math/atanh.zig" |
| 492 | "math/big/index.zig" | ||
| 492 | "math/big/int.zig" | 493 | "math/big/int.zig" |
| 493 | "math/cbrt.zig" | 494 | "math/cbrt.zig" |
| 494 | "math/ceil.zig" | 495 | "math/ceil.zig" |
src-self-hosted/c_int.zig created+68| ... | @@ -0,0 +1,68 @@ | ||
| 1 | pub const CInt = struct { | ||
| 2 | id: Id, | ||
| 3 | zig_name: []const u8, | ||
| 4 | c_name: []const u8, | ||
| 5 | is_signed: bool, | ||
| 6 | |||
| 7 | pub const Id = enum { | ||
| 8 | Short, | ||
| 9 | UShort, | ||
| 10 | Int, | ||
| 11 | UInt, | ||
| 12 | Long, | ||
| 13 | ULong, | ||
| 14 | LongLong, | ||
| 15 | ULongLong, | ||
| 16 | }; | ||
| 17 | |||
| 18 | pub const list = []CInt{ | ||
| 19 | CInt{ | ||
| 20 | .id = Id.Short, | ||
| 21 | .zig_name = "c_short", | ||
| 22 | .c_name = "short", | ||
| 23 | .is_signed = true, | ||
| 24 | }, | ||
| 25 | CInt{ | ||
| 26 | .id = Id.UShort, | ||
| 27 | .zig_name = "c_ushort", | ||
| 28 | .c_name = "unsigned short", | ||
| 29 | .is_signed = false, | ||
| 30 | }, | ||
| 31 | CInt{ | ||
| 32 | .id = Id.Int, | ||
| 33 | .zig_name = "c_int", | ||
| 34 | .c_name = "int", | ||
| 35 | .is_signed = true, | ||
| 36 | }, | ||
| 37 | CInt{ | ||
| 38 | .id = Id.UInt, | ||
| 39 | .zig_name = "c_uint", | ||
| 40 | .c_name = "unsigned int", | ||
| 41 | .is_signed = false, | ||
| 42 | }, | ||
| 43 | CInt{ | ||
| 44 | .id = Id.Long, | ||
| 45 | .zig_name = "c_long", | ||
| 46 | .c_name = "long", | ||
| 47 | .is_signed = true, | ||
| 48 | }, | ||
| 49 | CInt{ | ||
| 50 | .id = Id.ULong, | ||
| 51 | .zig_name = "c_ulong", | ||
| 52 | .c_name = "unsigned long", | ||
| 53 | .is_signed = false, | ||
| 54 | }, | ||
| 55 | CInt{ | ||
| 56 | .id = Id.LongLong, | ||
| 57 | .zig_name = "c_longlong", | ||
| 58 | .c_name = "long long", | ||
| 59 | .is_signed = true, | ||
| 60 | }, | ||
| 61 | CInt{ | ||
| 62 | .id = Id.ULongLong, | ||
| 63 | .zig_name = "c_ulonglong", | ||
| 64 | .c_name = "unsigned long long", | ||
| 65 | .is_signed = false, | ||
| 66 | }, | ||
| 67 | }; | ||
| 68 | }; | ||
src-self-hosted/compilation.zig+78-29| ... | @@ -29,6 +29,7 @@ const codegen = @import("codegen.zig"); | ... | @@ -29,6 +29,7 @@ const codegen = @import("codegen.zig"); |
| 29 | const Package = @import("package.zig").Package; | 29 | const Package = @import("package.zig").Package; |
| 30 | const link = @import("link.zig").link; | 30 | const link = @import("link.zig").link; |
| 31 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | 31 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 32 | const CInt = @import("c_int.zig").CInt; | ||
| 32 | 33 | ||
| 33 | /// Data that is local to the event loop. | 34 | /// Data that is local to the event loop. |
| 34 | pub const EventLoopLocal = struct { | 35 | pub const EventLoopLocal = struct { |
| ... | @@ -59,6 +60,7 @@ pub const EventLoopLocal = struct { | ... | @@ -59,6 +60,7 @@ pub const EventLoopLocal = struct { |
| 59 | }; | 60 | }; |
| 60 | } | 61 | } |
| 61 | 62 | ||
| 63 | /// Must be called only after EventLoop.run completes. | ||
| 62 | fn deinit(self: *EventLoopLocal) void { | 64 | fn deinit(self: *EventLoopLocal) void { |
| 63 | while (self.llvm_handle_pool.pop()) |node| { | 65 | while (self.llvm_handle_pool.pop()) |node| { |
| 64 | c.LLVMContextDispose(node.data); | 66 | c.LLVMContextDispose(node.data); |
| ... | @@ -184,6 +186,7 @@ pub const Compilation = struct { | ... | @@ -184,6 +186,7 @@ pub const Compilation = struct { |
| 184 | void_type: *Type.Void, | 186 | void_type: *Type.Void, |
| 185 | bool_type: *Type.Bool, | 187 | bool_type: *Type.Bool, |
| 186 | noreturn_type: *Type.NoReturn, | 188 | noreturn_type: *Type.NoReturn, |
| 189 | comptime_int_type: *Type.ComptimeInt, | ||
| 187 | 190 | ||
| 188 | void_value: *Value.Void, | 191 | void_value: *Value.Void, |
| 189 | true_value: *Value.Bool, | 192 | true_value: *Value.Bool, |
| ... | @@ -209,6 +212,16 @@ pub const Compilation = struct { | ... | @@ -209,6 +212,16 @@ pub const Compilation = struct { |
| 209 | 212 | ||
| 210 | have_err_ret_tracing: bool, | 213 | have_err_ret_tracing: bool, |
| 211 | 214 | ||
| 215 | /// not locked because it is read-only | ||
| 216 | primitive_type_table: TypeTable, | ||
| 217 | |||
| 218 | int_type_table: event.Locked(IntTypeTable), | ||
| 219 | |||
| 220 | c_int_types: [CInt.list.len]*Type.Int, | ||
| 221 | |||
| 222 | const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql); | ||
| 223 | const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8); | ||
| 224 | |||
| 212 | const CompileErrList = std.ArrayList(*errmsg.Msg); | 225 | const CompileErrList = std.ArrayList(*errmsg.Msg); |
| 213 | 226 | ||
| 214 | // TODO handle some of these earlier and report them in a way other than error codes | 227 | // TODO handle some of these earlier and report them in a way other than error codes |
| ... | @@ -362,6 +375,8 @@ pub const Compilation = struct { | ... | @@ -362,6 +375,8 @@ pub const Compilation = struct { |
| 362 | .prelink_group = event.Group(BuildError!void).init(loop), | 375 | .prelink_group = event.Group(BuildError!void).init(loop), |
| 363 | .deinit_group = event.Group(void).init(loop), | 376 | .deinit_group = event.Group(void).init(loop), |
| 364 | .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)), | 377 | .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)), |
| 378 | .int_type_table = event.Locked(IntTypeTable).init(loop, IntTypeTable.init(loop.allocator)), | ||
| 379 | .c_int_types = undefined, | ||
| 365 | 380 | ||
| 366 | .meta_type = undefined, | 381 | .meta_type = undefined, |
| 367 | .void_type = undefined, | 382 | .void_type = undefined, |
| ... | @@ -371,6 +386,7 @@ pub const Compilation = struct { | ... | @@ -371,6 +386,7 @@ pub const Compilation = struct { |
| 371 | .false_value = undefined, | 386 | .false_value = undefined, |
| 372 | .noreturn_type = undefined, | 387 | .noreturn_type = undefined, |
| 373 | .noreturn_value = undefined, | 388 | .noreturn_value = undefined, |
| 389 | .comptime_int_type = undefined, | ||
| 374 | 390 | ||
| 375 | .target_machine = undefined, | 391 | .target_machine = undefined, |
| 376 | .target_data_ref = undefined, | 392 | .target_data_ref = undefined, |
| ... | @@ -382,8 +398,10 @@ pub const Compilation = struct { | ... | @@ -382,8 +398,10 @@ pub const Compilation = struct { |
| 382 | .override_libc = null, | 398 | .override_libc = null, |
| 383 | .destroy_handle = undefined, | 399 | .destroy_handle = undefined, |
| 384 | .have_err_ret_tracing = false, | 400 | .have_err_ret_tracing = false, |
| 401 | .primitive_type_table = undefined, | ||
| 385 | }); | 402 | }); |
| 386 | errdefer { | 403 | errdefer { |
| 404 | comp.int_type_table.private_data.deinit(); | ||
| 387 | comp.arena_allocator.deinit(); | 405 | comp.arena_allocator.deinit(); |
| 388 | comp.loop.allocator.destroy(comp); | 406 | comp.loop.allocator.destroy(comp); |
| 389 | } | 407 | } |
| ... | @@ -393,6 +411,7 @@ pub const Compilation = struct { | ... | @@ -393,6 +411,7 @@ pub const Compilation = struct { |
| 393 | comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple); | 411 | comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple); |
| 394 | comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena()); | 412 | comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena()); |
| 395 | comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std"); | 413 | comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std"); |
| 414 | comp.primitive_type_table = TypeTable.init(comp.arena()); | ||
| 396 | 415 | ||
| 397 | const opt_level = switch (build_mode) { | 416 | const opt_level = switch (build_mode) { |
| 398 | builtin.Mode.Debug => llvm.CodeGenLevelNone, | 417 | builtin.Mode.Debug => llvm.CodeGenLevelNone, |
| ... | @@ -445,7 +464,6 @@ pub const Compilation = struct { | ... | @@ -445,7 +464,6 @@ pub const Compilation = struct { |
| 445 | } | 464 | } |
| 446 | 465 | ||
| 447 | try comp.initTypes(); | 466 | try comp.initTypes(); |
| 448 | errdefer comp.derefTypes(); | ||
| 449 | 467 | ||
| 450 | comp.destroy_handle = try async<loop.allocator> comp.internalDeinit(); | 468 | comp.destroy_handle = try async<loop.allocator> comp.internalDeinit(); |
| 451 | 469 | ||
| ... | @@ -453,8 +471,9 @@ pub const Compilation = struct { | ... | @@ -453,8 +471,9 @@ pub const Compilation = struct { |
| 453 | } | 471 | } |
| 454 | 472 | ||
| 455 | fn initTypes(comp: *Compilation) !void { | 473 | fn initTypes(comp: *Compilation) !void { |
| 456 | comp.meta_type = try comp.gpa().create(Type.MetaType{ | 474 | comp.meta_type = try comp.arena().create(Type.MetaType{ |
| 457 | .base = Type{ | 475 | .base = Type{ |
| 476 | .name = "type", | ||
| 458 | .base = Value{ | 477 | .base = Value{ |
| 459 | .id = Value.Id.Type, | 478 | .id = Value.Id.Type, |
| 460 | .typeof = undefined, | 479 | .typeof = undefined, |
| ... | @@ -466,10 +485,11 @@ pub const Compilation = struct { | ... | @@ -466,10 +485,11 @@ pub const Compilation = struct { |
| 466 | }); | 485 | }); |
| 467 | comp.meta_type.value = &comp.meta_type.base; | 486 | comp.meta_type.value = &comp.meta_type.base; |
| 468 | comp.meta_type.base.base.typeof = &comp.meta_type.base; | 487 | comp.meta_type.base.base.typeof = &comp.meta_type.base; |
| 469 | errdefer comp.gpa().destroy(comp.meta_type); | 488 | assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null); |
| 470 | 489 | ||
| 471 | comp.void_type = try comp.gpa().create(Type.Void{ | 490 | comp.void_type = try comp.arena().create(Type.Void{ |
| 472 | .base = Type{ | 491 | .base = Type{ |
| 492 | .name = "void", | ||
| 473 | .base = Value{ | 493 | .base = Value{ |
| 474 | .id = Value.Id.Type, | 494 | .id = Value.Id.Type, |
| 475 | .typeof = &Type.MetaType.get(comp).base, | 495 | .typeof = &Type.MetaType.get(comp).base, |
| ... | @@ -478,10 +498,11 @@ pub const Compilation = struct { | ... | @@ -478,10 +498,11 @@ pub const Compilation = struct { |
| 478 | .id = builtin.TypeId.Void, | 498 | .id = builtin.TypeId.Void, |
| 479 | }, | 499 | }, |
| 480 | }); | 500 | }); |
| 481 | errdefer comp.gpa().destroy(comp.void_type); | 501 | assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null); |
| 482 | 502 | ||
| 483 | comp.noreturn_type = try comp.gpa().create(Type.NoReturn{ | 503 | comp.noreturn_type = try comp.arena().create(Type.NoReturn{ |
| 484 | .base = Type{ | 504 | .base = Type{ |
| 505 | .name = "noreturn", | ||
| 485 | .base = Value{ | 506 | .base = Value{ |
| 486 | .id = Value.Id.Type, | 507 | .id = Value.Id.Type, |
| 487 | .typeof = &Type.MetaType.get(comp).base, | 508 | .typeof = &Type.MetaType.get(comp).base, |
| ... | @@ -490,10 +511,24 @@ pub const Compilation = struct { | ... | @@ -490,10 +511,24 @@ pub const Compilation = struct { |
| 490 | .id = builtin.TypeId.NoReturn, | 511 | .id = builtin.TypeId.NoReturn, |
| 491 | }, | 512 | }, |
| 492 | }); | 513 | }); |
| 493 | errdefer comp.gpa().destroy(comp.noreturn_type); | 514 | assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null); |
| 494 | 515 | ||
| 495 | comp.bool_type = try comp.gpa().create(Type.Bool{ | 516 | comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt{ |
| 496 | .base = Type{ | 517 | .base = Type{ |
| 518 | .name = "comptime_int", | ||
| 519 | .base = Value{ | ||
| 520 | .id = Value.Id.Type, | ||
| 521 | .typeof = &Type.MetaType.get(comp).base, | ||
| 522 | .ref_count = std.atomic.Int(usize).init(1), | ||
| 523 | }, | ||
| 524 | .id = builtin.TypeId.ComptimeInt, | ||
| 525 | }, | ||
| 526 | }); | ||
| 527 | assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null); | ||
| 528 | |||
| 529 | comp.bool_type = try comp.arena().create(Type.Bool{ | ||
| 530 | .base = Type{ | ||
| 531 | .name = "bool", | ||
| 497 | .base = Value{ | 532 | .base = Value{ |
| 498 | .id = Value.Id.Type, | 533 | .id = Value.Id.Type, |
| 499 | .typeof = &Type.MetaType.get(comp).base, | 534 | .typeof = &Type.MetaType.get(comp).base, |
| ... | @@ -502,18 +537,17 @@ pub const Compilation = struct { | ... | @@ -502,18 +537,17 @@ pub const Compilation = struct { |
| 502 | .id = builtin.TypeId.Bool, | 537 | .id = builtin.TypeId.Bool, |
| 503 | }, | 538 | }, |
| 504 | }); | 539 | }); |
| 505 | errdefer comp.gpa().destroy(comp.bool_type); | 540 | assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null); |
| 506 | 541 | ||
| 507 | comp.void_value = try comp.gpa().create(Value.Void{ | 542 | comp.void_value = try comp.arena().create(Value.Void{ |
| 508 | .base = Value{ | 543 | .base = Value{ |
| 509 | .id = Value.Id.Void, | 544 | .id = Value.Id.Void, |
| 510 | .typeof = &Type.Void.get(comp).base, | 545 | .typeof = &Type.Void.get(comp).base, |
| 511 | .ref_count = std.atomic.Int(usize).init(1), | 546 | .ref_count = std.atomic.Int(usize).init(1), |
| 512 | }, | 547 | }, |
| 513 | }); | 548 | }); |
| 514 | errdefer comp.gpa().destroy(comp.void_value); | ||
| 515 | 549 | ||
| 516 | comp.true_value = try comp.gpa().create(Value.Bool{ | 550 | comp.true_value = try comp.arena().create(Value.Bool{ |
| 517 | .base = Value{ | 551 | .base = Value{ |
| 518 | .id = Value.Id.Bool, | 552 | .id = Value.Id.Bool, |
| 519 | .typeof = &Type.Bool.get(comp).base, | 553 | .typeof = &Type.Bool.get(comp).base, |
| ... | @@ -521,9 +555,8 @@ pub const Compilation = struct { | ... | @@ -521,9 +555,8 @@ pub const Compilation = struct { |
| 521 | }, | 555 | }, |
| 522 | .x = true, | 556 | .x = true, |
| 523 | }); | 557 | }); |
| 524 | errdefer comp.gpa().destroy(comp.true_value); | ||
| 525 | 558 | ||
| 526 | comp.false_value = try comp.gpa().create(Value.Bool{ | 559 | comp.false_value = try comp.arena().create(Value.Bool{ |
| 527 | .base = Value{ | 560 | .base = Value{ |
| 528 | .id = Value.Id.Bool, | 561 | .id = Value.Id.Bool, |
| 529 | .typeof = &Type.Bool.get(comp).base, | 562 | .typeof = &Type.Bool.get(comp).base, |
| ... | @@ -531,44 +564,56 @@ pub const Compilation = struct { | ... | @@ -531,44 +564,56 @@ pub const Compilation = struct { |
| 531 | }, | 564 | }, |
| 532 | .x = false, | 565 | .x = false, |
| 533 | }); | 566 | }); |
| 534 | errdefer comp.gpa().destroy(comp.false_value); | ||
| 535 | 567 | ||
| 536 | comp.noreturn_value = try comp.gpa().create(Value.NoReturn{ | 568 | comp.noreturn_value = try comp.arena().create(Value.NoReturn{ |
| 537 | .base = Value{ | 569 | .base = Value{ |
| 538 | .id = Value.Id.NoReturn, | 570 | .id = Value.Id.NoReturn, |
| 539 | .typeof = &Type.NoReturn.get(comp).base, | 571 | .typeof = &Type.NoReturn.get(comp).base, |
| 540 | .ref_count = std.atomic.Int(usize).init(1), | 572 | .ref_count = std.atomic.Int(usize).init(1), |
| 541 | }, | 573 | }, |
| 542 | }); | 574 | }); |
| 543 | errdefer comp.gpa().destroy(comp.noreturn_value); | ||
| 544 | } | ||
| 545 | 575 | ||
| 546 | fn derefTypes(self: *Compilation) void { | 576 | for (CInt.list) |cint, i| { |
| 547 | self.noreturn_value.base.deref(self); | 577 | const c_int_type = try comp.arena().create(Type.Int{ |
| 548 | self.void_value.base.deref(self); | 578 | .base = Type{ |
| 549 | self.false_value.base.deref(self); | 579 | .name = cint.zig_name, |
| 550 | self.true_value.base.deref(self); | 580 | .base = Value{ |
| 551 | self.noreturn_type.base.base.deref(self); | 581 | .id = Value.Id.Type, |
| 552 | self.void_type.base.base.deref(self); | 582 | .typeof = &Type.MetaType.get(comp).base, |
| 553 | self.meta_type.base.base.deref(self); | 583 | .ref_count = std.atomic.Int(usize).init(1), |
| 584 | }, | ||
| 585 | .id = builtin.TypeId.Int, | ||
| 586 | }, | ||
| 587 | .key = Type.Int.Key{ | ||
| 588 | .is_signed = cint.is_signed, | ||
| 589 | .bit_count = comp.target.cIntTypeSizeInBits(cint.id), | ||
| 590 | }, | ||
| 591 | .garbage_node = undefined, | ||
| 592 | }); | ||
| 593 | comp.c_int_types[i] = c_int_type; | ||
| 594 | assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null); | ||
| 595 | } | ||
| 554 | } | 596 | } |
| 555 | 597 | ||
| 598 | /// This function can safely use async/await, because it manages Compilation's lifetime, | ||
| 599 | /// and EventLoopLocal.deinit will not be called until the event.Loop.run() completes. | ||
| 556 | async fn internalDeinit(self: *Compilation) void { | 600 | async fn internalDeinit(self: *Compilation) void { |
| 557 | suspend; | 601 | suspend; |
| 602 | |||
| 558 | await (async self.deinit_group.wait() catch unreachable); | 603 | await (async self.deinit_group.wait() catch unreachable); |
| 559 | if (self.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| { | 604 | if (self.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| { |
| 560 | // TODO evented I/O? | 605 | // TODO evented I/O? |
| 561 | os.deleteTree(self.arena(), tmp_dir) catch {}; | 606 | os.deleteTree(self.arena(), tmp_dir) catch {}; |
| 562 | } else |_| {}; | 607 | } else |_| {}; |
| 563 | 608 | ||
| 564 | self.derefTypes(); | ||
| 565 | |||
| 566 | self.events.destroy(); | 609 | self.events.destroy(); |
| 567 | 610 | ||
| 568 | llvm.DisposeMessage(self.target_layout_str); | 611 | llvm.DisposeMessage(self.target_layout_str); |
| 569 | llvm.DisposeTargetData(self.target_data_ref); | 612 | llvm.DisposeTargetData(self.target_data_ref); |
| 570 | llvm.DisposeTargetMachine(self.target_machine); | 613 | llvm.DisposeTargetMachine(self.target_machine); |
| 571 | 614 | ||
| 615 | self.primitive_type_table.deinit(); | ||
| 616 | |||
| 572 | self.arena_allocator.deinit(); | 617 | self.arena_allocator.deinit(); |
| 573 | self.gpa().destroy(self); | 618 | self.gpa().destroy(self); |
| 574 | } | 619 | } |
| ... | @@ -939,6 +984,10 @@ pub const Compilation = struct { | ... | @@ -939,6 +984,10 @@ pub const Compilation = struct { |
| 939 | b64_fs_encoder.encode(result[0..], rand_bytes); | 984 | b64_fs_encoder.encode(result[0..], rand_bytes); |
| 940 | return result; | 985 | return result; |
| 941 | } | 986 | } |
| 987 | |||
| 988 | fn registerGarbage(comp: *Compilation, comptime T: type, node: *std.atomic.Stack(*T).Node) void { | ||
| 989 | // TODO put the garbage somewhere | ||
| 990 | } | ||
| 942 | }; | 991 | }; |
| 943 | 992 | ||
| 944 | fn printError(comptime format: []const u8, args: ...) !void { | 993 | fn printError(comptime format: []const u8, args: ...) !void { |
| ... | @@ -1005,7 +1054,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { | ... | @@ -1005,7 +1054,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 1005 | fn_decl.base.parsed_file, | 1054 | fn_decl.base.parsed_file, |
| 1006 | &fndef_scope.base, | 1055 | &fndef_scope.base, |
| 1007 | body_node, | 1056 | body_node, |
| 1008 | null, | 1057 | return_type, |
| 1009 | ) catch unreachable)) orelse return; | 1058 | ) catch unreachable)) orelse return; |
| 1010 | errdefer analyzed_code.destroy(comp.gpa()); | 1059 | errdefer analyzed_code.destroy(comp.gpa()); |
| 1011 | 1060 |
src-self-hosted/ir.zig+473-2| ... | @@ -705,7 +705,10 @@ pub const Builder = struct { | ... | @@ -705,7 +705,10 @@ pub const Builder = struct { |
| 705 | ast.Node.Id.ErrorType => return error.Unimplemented, | 705 | ast.Node.Id.ErrorType => return error.Unimplemented, |
| 706 | ast.Node.Id.FnProto => return error.Unimplemented, | 706 | ast.Node.Id.FnProto => return error.Unimplemented, |
| 707 | ast.Node.Id.PromiseType => return error.Unimplemented, | 707 | ast.Node.Id.PromiseType => return error.Unimplemented, |
| 708 | ast.Node.Id.IntegerLiteral => return error.Unimplemented, | 708 | ast.Node.Id.IntegerLiteral => { |
| 709 | const int_lit = @fieldParentPtr(ast.Node.IntegerLiteral, "base", node); | ||
| 710 | return irb.lvalWrap(scope, try irb.genIntLit(int_lit, scope), lval); | ||
| 711 | }, | ||
| 709 | ast.Node.Id.FloatLiteral => return error.Unimplemented, | 712 | ast.Node.Id.FloatLiteral => return error.Unimplemented, |
| 710 | ast.Node.Id.StringLiteral => return error.Unimplemented, | 713 | ast.Node.Id.StringLiteral => return error.Unimplemented, |
| 711 | ast.Node.Id.MultilineStringLiteral => return error.Unimplemented, | 714 | ast.Node.Id.MultilineStringLiteral => return error.Unimplemented, |
| ... | @@ -766,6 +769,45 @@ pub const Builder = struct { | ... | @@ -766,6 +769,45 @@ pub const Builder = struct { |
| 766 | } | 769 | } |
| 767 | } | 770 | } |
| 768 | 771 | ||
| 772 | pub fn genIntLit(irb: *Builder, int_lit: *ast.Node.IntegerLiteral, scope: *Scope) !*Inst { | ||
| 773 | const int_token = irb.parsed_file.tree.tokenSlice(int_lit.token); | ||
| 774 | |||
| 775 | var base: u8 = undefined; | ||
| 776 | var rest: []const u8 = undefined; | ||
| 777 | if (int_token.len >= 3 and int_token[0] == '0') { | ||
| 778 | base = switch (int_token[1]) { | ||
| 779 | 'b' => u8(2), | ||
| 780 | 'o' => u8(8), | ||
| 781 | 'x' => u8(16), | ||
| 782 | else => unreachable, | ||
| 783 | }; | ||
| 784 | rest = int_token[2..]; | ||
| 785 | } else { | ||
| 786 | base = 10; | ||
| 787 | rest = int_token; | ||
| 788 | } | ||
| 789 | |||
| 790 | const comptime_int_type = Type.ComptimeInt.get(irb.comp); | ||
| 791 | defer comptime_int_type.base.base.deref(irb.comp); | ||
| 792 | |||
| 793 | const int_val = Value.Int.createFromString( | ||
| 794 | irb.comp, | ||
| 795 | &comptime_int_type.base, | ||
| 796 | base, | ||
| 797 | rest, | ||
| 798 | ) catch |err| switch (err) { | ||
| 799 | error.OutOfMemory => return error.OutOfMemory, | ||
| 800 | error.InvalidBase => unreachable, | ||
| 801 | error.InvalidCharForDigit => unreachable, | ||
| 802 | error.DigitTooLargeForBase => unreachable, | ||
| 803 | }; | ||
| 804 | errdefer int_val.base.deref(irb.comp); | ||
| 805 | |||
| 806 | const inst = try irb.build(Inst.Const, scope, Span.token(int_lit.token), Inst.Const.Params{}); | ||
| 807 | inst.val = IrVal{ .KnownValue = &int_val.base }; | ||
| 808 | return inst; | ||
| 809 | } | ||
| 810 | |||
| 769 | pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst { | 811 | pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst { |
| 770 | const block_scope = try Scope.Block.create(irb.comp, parent_scope); | 812 | const block_scope = try Scope.Block.create(irb.comp, parent_scope); |
| 771 | 813 | ||
| ... | @@ -1306,7 +1348,436 @@ const Analyze = struct { | ... | @@ -1306,7 +1348,436 @@ const Analyze = struct { |
| 1306 | 1348 | ||
| 1307 | fn implicitCast(self: *Analyze, target: *Inst, optional_dest_type: ?*Type) Analyze.Error!*Inst { | 1349 | fn implicitCast(self: *Analyze, target: *Inst, optional_dest_type: ?*Type) Analyze.Error!*Inst { |
| 1308 | const dest_type = optional_dest_type orelse return target; | 1350 | const dest_type = optional_dest_type orelse return target; |
| 1309 | return error.Unimplemented; | 1351 | const from_type = target.getKnownType(); |
| 1352 | if (from_type == dest_type or from_type.id == Type.Id.NoReturn) return target; | ||
| 1353 | return self.analyzeCast(target, target, dest_type); | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | fn analyzeCast(ira: *Analyze, source_instr: *Inst, target: *Inst, dest_type: *Type) !*Inst { | ||
| 1357 | const from_type = target.getKnownType(); | ||
| 1358 | |||
| 1359 | //if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) { | ||
| 1360 | // return ira->codegen->invalid_instruction; | ||
| 1361 | //} | ||
| 1362 | |||
| 1363 | //// perfect match or non-const to const | ||
| 1364 | //ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type, | ||
| 1365 | // source_node, false); | ||
| 1366 | //if (const_cast_result.id == ConstCastResultIdOk) { | ||
| 1367 | // return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); | ||
| 1368 | //} | ||
| 1369 | |||
| 1370 | //// widening conversion | ||
| 1371 | //if (wanted_type->id == TypeTableEntryIdInt && | ||
| 1372 | // actual_type->id == TypeTableEntryIdInt && | ||
| 1373 | // wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed && | ||
| 1374 | // wanted_type->data.integral.bit_count >= actual_type->data.integral.bit_count) | ||
| 1375 | //{ | ||
| 1376 | // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); | ||
| 1377 | //} | ||
| 1378 | |||
| 1379 | //// small enough unsigned ints can get casted to large enough signed ints | ||
| 1380 | //if (wanted_type->id == TypeTableEntryIdInt && wanted_type->data.integral.is_signed && | ||
| 1381 | // actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed && | ||
| 1382 | // wanted_type->data.integral.bit_count > actual_type->data.integral.bit_count) | ||
| 1383 | //{ | ||
| 1384 | // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); | ||
| 1385 | //} | ||
| 1386 | |||
| 1387 | //// float widening conversion | ||
| 1388 | //if (wanted_type->id == TypeTableEntryIdFloat && | ||
| 1389 | // actual_type->id == TypeTableEntryIdFloat && | ||
| 1390 | // wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count) | ||
| 1391 | //{ | ||
| 1392 | // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); | ||
| 1393 | //} | ||
| 1394 | |||
| 1395 | //// cast from [N]T to []const T | ||
| 1396 | //if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) { | ||
| 1397 | // TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; | ||
| 1398 | // assert(ptr_type->id == TypeTableEntryIdPointer); | ||
| 1399 | // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | ||
| 1400 | // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, | ||
| 1401 | // source_node, false).id == ConstCastResultIdOk) | ||
| 1402 | // { | ||
| 1403 | // return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type); | ||
| 1404 | // } | ||
| 1405 | //} | ||
| 1406 | |||
| 1407 | //// cast from *const [N]T to []const T | ||
| 1408 | //if (is_slice(wanted_type) && | ||
| 1409 | // actual_type->id == TypeTableEntryIdPointer && | ||
| 1410 | // actual_type->data.pointer.is_const && | ||
| 1411 | // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray) | ||
| 1412 | //{ | ||
| 1413 | // TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; | ||
| 1414 | // assert(ptr_type->id == TypeTableEntryIdPointer); | ||
| 1415 | |||
| 1416 | // TypeTableEntry *array_type = actual_type->data.pointer.child_type; | ||
| 1417 | |||
| 1418 | // if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) && | ||
| 1419 | // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, | ||
| 1420 | // source_node, false).id == ConstCastResultIdOk) | ||
| 1421 | // { | ||
| 1422 | // return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type); | ||
| 1423 | // } | ||
| 1424 | //} | ||
| 1425 | |||
| 1426 | //// cast from [N]T to *const []const T | ||
| 1427 | //if (wanted_type->id == TypeTableEntryIdPointer && | ||
| 1428 | // wanted_type->data.pointer.is_const && | ||
| 1429 | // is_slice(wanted_type->data.pointer.child_type) && | ||
| 1430 | // actual_type->id == TypeTableEntryIdArray) | ||
| 1431 | //{ | ||
| 1432 | // TypeTableEntry *ptr_type = | ||
| 1433 | // wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry; | ||
| 1434 | // assert(ptr_type->id == TypeTableEntryIdPointer); | ||
| 1435 | // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | ||
| 1436 | // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, | ||
| 1437 | // source_node, false).id == ConstCastResultIdOk) | ||
| 1438 | // { | ||
| 1439 | // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value); | ||
| 1440 | // if (type_is_invalid(cast1->value.type)) | ||
| 1441 | // return ira->codegen->invalid_instruction; | ||
| 1442 | |||
| 1443 | // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 1444 | // if (type_is_invalid(cast2->value.type)) | ||
| 1445 | // return ira->codegen->invalid_instruction; | ||
| 1446 | |||
| 1447 | // return cast2; | ||
| 1448 | // } | ||
| 1449 | //} | ||
| 1450 | |||
| 1451 | //// cast from [N]T to ?[]const T | ||
| 1452 | //if (wanted_type->id == TypeTableEntryIdOptional && | ||
| 1453 | // is_slice(wanted_type->data.maybe.child_type) && | ||
| 1454 | // actual_type->id == TypeTableEntryIdArray) | ||
| 1455 | //{ | ||
| 1456 | // TypeTableEntry *ptr_type = | ||
| 1457 | // wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry; | ||
| 1458 | // assert(ptr_type->id == TypeTableEntryIdPointer); | ||
| 1459 | // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | ||
| 1460 | // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, | ||
| 1461 | // source_node, false).id == ConstCastResultIdOk) | ||
| 1462 | // { | ||
| 1463 | // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value); | ||
| 1464 | // if (type_is_invalid(cast1->value.type)) | ||
| 1465 | // return ira->codegen->invalid_instruction; | ||
| 1466 | |||
| 1467 | // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 1468 | // if (type_is_invalid(cast2->value.type)) | ||
| 1469 | // return ira->codegen->invalid_instruction; | ||
| 1470 | |||
| 1471 | // return cast2; | ||
| 1472 | // } | ||
| 1473 | //} | ||
| 1474 | |||
| 1475 | //// *[N]T to [*]T | ||
| 1476 | //if (wanted_type->id == TypeTableEntryIdPointer && | ||
| 1477 | // wanted_type->data.pointer.ptr_len == PtrLenUnknown && | ||
| 1478 | // actual_type->id == TypeTableEntryIdPointer && | ||
| 1479 | // actual_type->data.pointer.ptr_len == PtrLenSingle && | ||
| 1480 | // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray && | ||
| 1481 | // actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment && | ||
| 1482 | // types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, | ||
| 1483 | // actual_type->data.pointer.child_type->data.array.child_type, source_node, | ||
| 1484 | // !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) | ||
| 1485 | //{ | ||
| 1486 | // return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type); | ||
| 1487 | //} | ||
| 1488 | |||
| 1489 | //// *[N]T to []T | ||
| 1490 | //if (is_slice(wanted_type) && | ||
| 1491 | // actual_type->id == TypeTableEntryIdPointer && | ||
| 1492 | // actual_type->data.pointer.ptr_len == PtrLenSingle && | ||
| 1493 | // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray) | ||
| 1494 | //{ | ||
| 1495 | // TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; | ||
| 1496 | // assert(slice_ptr_type->id == TypeTableEntryIdPointer); | ||
| 1497 | // if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, | ||
| 1498 | // actual_type->data.pointer.child_type->data.array.child_type, source_node, | ||
| 1499 | // !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk) | ||
| 1500 | // { | ||
| 1501 | // return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type); | ||
| 1502 | // } | ||
| 1503 | //} | ||
| 1504 | |||
| 1505 | //// cast from T to ?T | ||
| 1506 | //// note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism | ||
| 1507 | //if (wanted_type->id == TypeTableEntryIdOptional) { | ||
| 1508 | // TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type; | ||
| 1509 | // if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, | ||
| 1510 | // false).id == ConstCastResultIdOk) | ||
| 1511 | // { | ||
| 1512 | // return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); | ||
| 1513 | // } else if (actual_type->id == TypeTableEntryIdComptimeInt || | ||
| 1514 | // actual_type->id == TypeTableEntryIdComptimeFloat) | ||
| 1515 | // { | ||
| 1516 | // if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { | ||
| 1517 | // return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); | ||
| 1518 | // } else { | ||
| 1519 | // return ira->codegen->invalid_instruction; | ||
| 1520 | // } | ||
| 1521 | // } else if (wanted_child_type->id == TypeTableEntryIdPointer && | ||
| 1522 | // wanted_child_type->data.pointer.is_const && | ||
| 1523 | // (actual_type->id == TypeTableEntryIdPointer || is_container(actual_type))) | ||
| 1524 | // { | ||
| 1525 | // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_child_type, value); | ||
| 1526 | // if (type_is_invalid(cast1->value.type)) | ||
| 1527 | // return ira->codegen->invalid_instruction; | ||
| 1528 | |||
| 1529 | // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 1530 | // if (type_is_invalid(cast2->value.type)) | ||
| 1531 | // return ira->codegen->invalid_instruction; | ||
| 1532 | |||
| 1533 | // return cast2; | ||
| 1534 | // } | ||
| 1535 | //} | ||
| 1536 | |||
| 1537 | //// cast from null literal to maybe type | ||
| 1538 | //if (wanted_type->id == TypeTableEntryIdOptional && | ||
| 1539 | // actual_type->id == TypeTableEntryIdNull) | ||
| 1540 | //{ | ||
| 1541 | // return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type); | ||
| 1542 | //} | ||
| 1543 | |||
| 1544 | //// cast from child type of error type to error type | ||
| 1545 | //if (wanted_type->id == TypeTableEntryIdErrorUnion) { | ||
| 1546 | // if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, | ||
| 1547 | // source_node, false).id == ConstCastResultIdOk) | ||
| 1548 | // { | ||
| 1549 | // return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); | ||
| 1550 | // } else if (actual_type->id == TypeTableEntryIdComptimeInt || | ||
| 1551 | // actual_type->id == TypeTableEntryIdComptimeFloat) | ||
| 1552 | // { | ||
| 1553 | // if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) { | ||
| 1554 | // return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); | ||
| 1555 | // } else { | ||
| 1556 | // return ira->codegen->invalid_instruction; | ||
| 1557 | // } | ||
| 1558 | // } | ||
| 1559 | //} | ||
| 1560 | |||
| 1561 | //// cast from [N]T to E![]const T | ||
| 1562 | //if (wanted_type->id == TypeTableEntryIdErrorUnion && | ||
| 1563 | // is_slice(wanted_type->data.error_union.payload_type) && | ||
| 1564 | // actual_type->id == TypeTableEntryIdArray) | ||
| 1565 | //{ | ||
| 1566 | // TypeTableEntry *ptr_type = | ||
| 1567 | // wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry; | ||
| 1568 | // assert(ptr_type->id == TypeTableEntryIdPointer); | ||
| 1569 | // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && | ||
| 1570 | // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, | ||
| 1571 | // source_node, false).id == ConstCastResultIdOk) | ||
| 1572 | // { | ||
| 1573 | // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); | ||
| 1574 | // if (type_is_invalid(cast1->value.type)) | ||
| 1575 | // return ira->codegen->invalid_instruction; | ||
| 1576 | |||
| 1577 | // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 1578 | // if (type_is_invalid(cast2->value.type)) | ||
| 1579 | // return ira->codegen->invalid_instruction; | ||
| 1580 | |||
| 1581 | // return cast2; | ||
| 1582 | // } | ||
| 1583 | //} | ||
| 1584 | |||
| 1585 | //// cast from error set to error union type | ||
| 1586 | //if (wanted_type->id == TypeTableEntryIdErrorUnion && | ||
| 1587 | // actual_type->id == TypeTableEntryIdErrorSet) | ||
| 1588 | //{ | ||
| 1589 | // return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); | ||
| 1590 | //} | ||
| 1591 | |||
| 1592 | //// cast from T to E!?T | ||
| 1593 | //if (wanted_type->id == TypeTableEntryIdErrorUnion && | ||
| 1594 | // wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional && | ||
| 1595 | // actual_type->id != TypeTableEntryIdOptional) | ||
| 1596 | //{ | ||
| 1597 | // TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type; | ||
| 1598 | // if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk || | ||
| 1599 | // actual_type->id == TypeTableEntryIdNull || | ||
| 1600 | // actual_type->id == TypeTableEntryIdComptimeInt || | ||
| 1601 | // actual_type->id == TypeTableEntryIdComptimeFloat) | ||
| 1602 | // { | ||
| 1603 | // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); | ||
| 1604 | // if (type_is_invalid(cast1->value.type)) | ||
| 1605 | // return ira->codegen->invalid_instruction; | ||
| 1606 | |||
| 1607 | // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 1608 | // if (type_is_invalid(cast2->value.type)) | ||
| 1609 | // return ira->codegen->invalid_instruction; | ||
| 1610 | |||
| 1611 | // return cast2; | ||
| 1612 | // } | ||
| 1613 | //} | ||
| 1614 | |||
| 1615 | // cast from number literal to another type | ||
| 1616 | //// cast from number literal to *const integer | ||
| 1617 | //if (actual_type->id == TypeTableEntryIdComptimeFloat || | ||
| 1618 | // actual_type->id == TypeTableEntryIdComptimeInt) | ||
| 1619 | //{ | ||
| 1620 | // ensure_complete_type(ira->codegen, wanted_type); | ||
| 1621 | // if (type_is_invalid(wanted_type)) | ||
| 1622 | // return ira->codegen->invalid_instruction; | ||
| 1623 | // if (wanted_type->id == TypeTableEntryIdEnum) { | ||
| 1624 | // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value); | ||
| 1625 | // if (type_is_invalid(cast1->value.type)) | ||
| 1626 | // return ira->codegen->invalid_instruction; | ||
| 1627 | |||
| 1628 | // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 1629 | // if (type_is_invalid(cast2->value.type)) | ||
| 1630 | // return ira->codegen->invalid_instruction; | ||
| 1631 | |||
| 1632 | // return cast2; | ||
| 1633 | // } else if (wanted_type->id == TypeTableEntryIdPointer && | ||
| 1634 | // wanted_type->data.pointer.is_const) | ||
| 1635 | // { | ||
| 1636 | // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value); | ||
| 1637 | // if (type_is_invalid(cast1->value.type)) | ||
| 1638 | // return ira->codegen->invalid_instruction; | ||
| 1639 | |||
| 1640 | // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 1641 | // if (type_is_invalid(cast2->value.type)) | ||
| 1642 | // return ira->codegen->invalid_instruction; | ||
| 1643 | |||
| 1644 | // return cast2; | ||
| 1645 | // } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { | ||
| 1646 | // CastOp op; | ||
| 1647 | // if ((actual_type->id == TypeTableEntryIdComptimeFloat && | ||
| 1648 | // wanted_type->id == TypeTableEntryIdFloat) || | ||
| 1649 | // (actual_type->id == TypeTableEntryIdComptimeInt && | ||
| 1650 | // wanted_type->id == TypeTableEntryIdInt)) | ||
| 1651 | // { | ||
| 1652 | // op = CastOpNumLitToConcrete; | ||
| 1653 | // } else if (wanted_type->id == TypeTableEntryIdInt) { | ||
| 1654 | // op = CastOpFloatToInt; | ||
| 1655 | // } else if (wanted_type->id == TypeTableEntryIdFloat) { | ||
| 1656 | // op = CastOpIntToFloat; | ||
| 1657 | // } else { | ||
| 1658 | // zig_unreachable(); | ||
| 1659 | // } | ||
| 1660 | // return ir_resolve_cast(ira, source_instr, value, wanted_type, op, false); | ||
| 1661 | // } else { | ||
| 1662 | // return ira->codegen->invalid_instruction; | ||
| 1663 | // } | ||
| 1664 | //} | ||
| 1665 | |||
| 1666 | //// cast from typed number to integer or float literal. | ||
| 1667 | //// works when the number is known at compile time | ||
| 1668 | //if (instr_is_comptime(value) && | ||
| 1669 | // ((actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdComptimeInt) || | ||
| 1670 | // (actual_type->id == TypeTableEntryIdFloat && wanted_type->id == TypeTableEntryIdComptimeFloat))) | ||
| 1671 | //{ | ||
| 1672 | // return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type); | ||
| 1673 | //} | ||
| 1674 | |||
| 1675 | //// cast from union to the enum type of the union | ||
| 1676 | //if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) { | ||
| 1677 | // type_ensure_zero_bits_known(ira->codegen, actual_type); | ||
| 1678 | // if (type_is_invalid(actual_type)) | ||
| 1679 | // return ira->codegen->invalid_instruction; | ||
| 1680 | |||
| 1681 | // if (actual_type->data.unionation.tag_type == wanted_type) { | ||
| 1682 | // return ir_analyze_union_to_tag(ira, source_instr, value, wanted_type); | ||
| 1683 | // } | ||
| 1684 | //} | ||
| 1685 | |||
| 1686 | //// enum to union which has the enum as the tag type | ||
| 1687 | //if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum && | ||
| 1688 | // (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum || | ||
| 1689 | // wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | ||
| 1690 | //{ | ||
| 1691 | // type_ensure_zero_bits_known(ira->codegen, wanted_type); | ||
| 1692 | // if (wanted_type->data.unionation.tag_type == actual_type) { | ||
| 1693 | // return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type); | ||
| 1694 | // } | ||
| 1695 | //} | ||
| 1696 | |||
| 1697 | //// enum to &const union which has the enum as the tag type | ||
| 1698 | //if (actual_type->id == TypeTableEntryIdEnum && wanted_type->id == TypeTableEntryIdPointer) { | ||
| 1699 | // TypeTableEntry *union_type = wanted_type->data.pointer.child_type; | ||
| 1700 | // if (union_type->data.unionation.decl_node->data.container_decl.auto_enum || | ||
| 1701 | // union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr) | ||
| 1702 | // { | ||
| 1703 | // type_ensure_zero_bits_known(ira->codegen, union_type); | ||
| 1704 | // if (union_type->data.unionation.tag_type == actual_type) { | ||
| 1705 | // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, union_type, value); | ||
| 1706 | // if (type_is_invalid(cast1->value.type)) | ||
| 1707 | // return ira->codegen->invalid_instruction; | ||
| 1708 | |||
| 1709 | // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 1710 | // if (type_is_invalid(cast2->value.type)) | ||
| 1711 | // return ira->codegen->invalid_instruction; | ||
| 1712 | |||
| 1713 | // return cast2; | ||
| 1714 | // } | ||
| 1715 | // } | ||
| 1716 | //} | ||
| 1717 | |||
| 1718 | //// cast from *T to *[1]T | ||
| 1719 | //if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle && | ||
| 1720 | // actual_type->id == TypeTableEntryIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle) | ||
| 1721 | //{ | ||
| 1722 | // TypeTableEntry *array_type = wanted_type->data.pointer.child_type; | ||
| 1723 | // if (array_type->id == TypeTableEntryIdArray && array_type->data.array.len == 1 && | ||
| 1724 | // types_match_const_cast_only(ira, array_type->data.array.child_type, | ||
| 1725 | // actual_type->data.pointer.child_type, source_node, | ||
| 1726 | // !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) | ||
| 1727 | // { | ||
| 1728 | // if (wanted_type->data.pointer.alignment > actual_type->data.pointer.alignment) { | ||
| 1729 | // ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment")); | ||
| 1730 | // add_error_note(ira->codegen, msg, value->source_node, | ||
| 1731 | // buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name), | ||
| 1732 | // actual_type->data.pointer.alignment)); | ||
| 1733 | // add_error_note(ira->codegen, msg, source_instr->source_node, | ||
| 1734 | // buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name), | ||
| 1735 | // wanted_type->data.pointer.alignment)); | ||
| 1736 | // return ira->codegen->invalid_instruction; | ||
| 1737 | // } | ||
| 1738 | // return ir_analyze_ptr_to_array(ira, source_instr, value, wanted_type); | ||
| 1739 | // } | ||
| 1740 | //} | ||
| 1741 | |||
| 1742 | //// cast from T to *T where T is zero bits | ||
| 1743 | //if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle && | ||
| 1744 | // types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, | ||
| 1745 | // actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) | ||
| 1746 | //{ | ||
| 1747 | // type_ensure_zero_bits_known(ira->codegen, actual_type); | ||
| 1748 | // if (type_is_invalid(actual_type)) { | ||
| 1749 | // return ira->codegen->invalid_instruction; | ||
| 1750 | // } | ||
| 1751 | // if (!type_has_bits(actual_type)) { | ||
| 1752 | // return ir_get_ref(ira, source_instr, value, false, false); | ||
| 1753 | // } | ||
| 1754 | //} | ||
| 1755 | |||
| 1756 | //// cast from undefined to anything | ||
| 1757 | //if (actual_type->id == TypeTableEntryIdUndefined) { | ||
| 1758 | // return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type); | ||
| 1759 | //} | ||
| 1760 | |||
| 1761 | //// cast from something to const pointer of it | ||
| 1762 | //if (!type_requires_comptime(actual_type)) { | ||
| 1763 | // TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true); | ||
| 1764 | // if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node, false).id == ConstCastResultIdOk) { | ||
| 1765 | // return ir_analyze_cast_ref(ira, source_instr, value, wanted_type); | ||
| 1766 | // } | ||
| 1767 | //} | ||
| 1768 | |||
| 1769 | try ira.addCompileError( | ||
| 1770 | source_instr.span, | ||
| 1771 | "expected type '{}', found '{}'", | ||
| 1772 | dest_type.name, | ||
| 1773 | from_type.name, | ||
| 1774 | ); | ||
| 1775 | //ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node, | ||
| 1776 | // buf_sprintf("expected type '%s', found '%s'", | ||
| 1777 | // buf_ptr(&wanted_type->name), | ||
| 1778 | // buf_ptr(&actual_type->name))); | ||
| 1779 | //report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg); | ||
| 1780 | return error.SemanticAnalysisFailed; | ||
| 1310 | } | 1781 | } |
| 1311 | 1782 | ||
| 1312 | fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Inst) ?*Value { | 1783 | fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Inst) ?*Value { |
src-self-hosted/llvm.zig+2| ... | @@ -30,6 +30,8 @@ pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag; | ... | @@ -30,6 +30,8 @@ pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag; |
| 30 | pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; | 30 | pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; |
| 31 | pub const ConstAllOnes = c.LLVMConstAllOnes; | 31 | pub const ConstAllOnes = c.LLVMConstAllOnes; |
| 32 | pub const ConstInt = c.LLVMConstInt; | 32 | pub const ConstInt = c.LLVMConstInt; |
| 33 | pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision; | ||
| 34 | pub const ConstNeg = c.LLVMConstNeg; | ||
| 33 | pub const ConstNull = c.LLVMConstNull; | 35 | pub const ConstNull = c.LLVMConstNull; |
| 34 | pub const ConstStringInContext = c.LLVMConstStringInContext; | 36 | pub const ConstStringInContext = c.LLVMConstStringInContext; |
| 35 | pub const ConstStructInContext = c.LLVMConstStructInContext; | 37 | pub const ConstStructInContext = c.LLVMConstStructInContext; |
src-self-hosted/target.zig+98-1| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const llvm = @import("llvm.zig"); | 3 | const llvm = @import("llvm.zig"); |
| 4 | const CInt = @import("c_int.zig").CInt; | ||
| 4 | 5 | ||
| 5 | pub const FloatAbi = enum { | 6 | pub const FloatAbi = enum { |
| 6 | Hard, | 7 | Hard, |
| ... | @@ -173,7 +174,7 @@ pub const Target = union(enum) { | ... | @@ -173,7 +174,7 @@ pub const Target = union(enum) { |
| 173 | return self.getArchPtrBitWidth() == 64; | 174 | return self.getArchPtrBitWidth() == 64; |
| 174 | } | 175 | } |
| 175 | 176 | ||
| 176 | pub fn getArchPtrBitWidth(self: Target) u8 { | 177 | pub fn getArchPtrBitWidth(self: Target) u32 { |
| 177 | switch (self.getArch()) { | 178 | switch (self.getArch()) { |
| 178 | builtin.Arch.avr, | 179 | builtin.Arch.avr, |
| 179 | builtin.Arch.msp430, | 180 | builtin.Arch.msp430, |
| ... | @@ -429,4 +430,100 @@ pub const Target = union(enum) { | ... | @@ -429,4 +430,100 @@ pub const Target = union(enum) { |
| 429 | } | 430 | } |
| 430 | return result; | 431 | return result; |
| 431 | } | 432 | } |
| 433 | |||
| 434 | pub fn cIntTypeSizeInBits(self: Target, id: CInt.Id) u32 { | ||
| 435 | const arch = self.getArch(); | ||
| 436 | switch (self.getOs()) { | ||
| 437 | builtin.Os.freestanding => switch (self.getArch()) { | ||
| 438 | builtin.Arch.msp430 => switch (id) { | ||
| 439 | CInt.Id.Short, | ||
| 440 | CInt.Id.UShort, | ||
| 441 | CInt.Id.Int, | ||
| 442 | CInt.Id.UInt, | ||
| 443 | => return 16, | ||
| 444 | CInt.Id.Long, | ||
| 445 | CInt.Id.ULong, | ||
| 446 | => return 32, | ||
| 447 | CInt.Id.LongLong, | ||
| 448 | CInt.Id.ULongLong, | ||
| 449 | => return 64, | ||
| 450 | }, | ||
| 451 | else => switch (id) { | ||
| 452 | CInt.Id.Short, | ||
| 453 | CInt.Id.UShort, | ||
| 454 | => return 16, | ||
| 455 | CInt.Id.Int, | ||
| 456 | CInt.Id.UInt, | ||
| 457 | => return 32, | ||
| 458 | CInt.Id.Long, | ||
| 459 | CInt.Id.ULong, | ||
| 460 | => return self.getArchPtrBitWidth(), | ||
| 461 | CInt.Id.LongLong, | ||
| 462 | CInt.Id.ULongLong, | ||
| 463 | => return 64, | ||
| 464 | }, | ||
| 465 | }, | ||
| 466 | |||
| 467 | builtin.Os.linux, | ||
| 468 | builtin.Os.macosx, | ||
| 469 | builtin.Os.openbsd, | ||
| 470 | builtin.Os.zen, | ||
| 471 | => switch (id) { | ||
| 472 | CInt.Id.Short, | ||
| 473 | CInt.Id.UShort, | ||
| 474 | => return 16, | ||
| 475 | CInt.Id.Int, | ||
| 476 | CInt.Id.UInt, | ||
| 477 | => return 32, | ||
| 478 | CInt.Id.Long, | ||
| 479 | CInt.Id.ULong, | ||
| 480 | => return self.getArchPtrBitWidth(), | ||
| 481 | CInt.Id.LongLong, | ||
| 482 | CInt.Id.ULongLong, | ||
| 483 | => return 64, | ||
| 484 | }, | ||
| 485 | |||
| 486 | builtin.Os.windows => switch (id) { | ||
| 487 | CInt.Id.Short, | ||
| 488 | CInt.Id.UShort, | ||
| 489 | => return 16, | ||
| 490 | CInt.Id.Int, | ||
| 491 | CInt.Id.UInt, | ||
| 492 | => return 32, | ||
| 493 | CInt.Id.Long, | ||
| 494 | CInt.Id.ULong, | ||
| 495 | CInt.Id.LongLong, | ||
| 496 | CInt.Id.ULongLong, | ||
| 497 | => return 64, | ||
| 498 | }, | ||
| 499 | |||
| 500 | builtin.Os.ananas, | ||
| 501 | builtin.Os.cloudabi, | ||
| 502 | builtin.Os.dragonfly, | ||
| 503 | builtin.Os.freebsd, | ||
| 504 | builtin.Os.fuchsia, | ||
| 505 | builtin.Os.ios, | ||
| 506 | builtin.Os.kfreebsd, | ||
| 507 | builtin.Os.lv2, | ||
| 508 | builtin.Os.netbsd, | ||
| 509 | builtin.Os.solaris, | ||
| 510 | builtin.Os.haiku, | ||
| 511 | builtin.Os.minix, | ||
| 512 | builtin.Os.rtems, | ||
| 513 | builtin.Os.nacl, | ||
| 514 | builtin.Os.cnk, | ||
| 515 | builtin.Os.aix, | ||
| 516 | builtin.Os.cuda, | ||
| 517 | builtin.Os.nvcl, | ||
| 518 | builtin.Os.amdhsa, | ||
| 519 | builtin.Os.ps4, | ||
| 520 | builtin.Os.elfiamcu, | ||
| 521 | builtin.Os.tvos, | ||
| 522 | builtin.Os.watchos, | ||
| 523 | builtin.Os.mesa3d, | ||
| 524 | builtin.Os.contiki, | ||
| 525 | builtin.Os.amdpal, | ||
| 526 | => @panic("TODO specify the C integer type sizes for this OS"), | ||
| 527 | } | ||
| 528 | } | ||
| 432 | }; | 529 | }; |
src-self-hosted/type.zig+88-10| ... | @@ -9,6 +9,7 @@ const ObjectFile = @import("codegen.zig").ObjectFile; | ... | @@ -9,6 +9,7 @@ const ObjectFile = @import("codegen.zig").ObjectFile; |
| 9 | pub const Type = struct { | 9 | pub const Type = struct { |
| 10 | base: Value, | 10 | base: Value, |
| 11 | id: Id, | 11 | id: Id, |
| 12 | name: []const u8, | ||
| 12 | 13 | ||
| 13 | pub const Id = builtin.TypeId; | 14 | pub const Id = builtin.TypeId; |
| 14 | 15 | ||
| ... | @@ -151,6 +152,18 @@ pub const Type = struct { | ... | @@ -151,6 +152,18 @@ pub const Type = struct { |
| 151 | std.debug.warn("{}", @tagName(base.id)); | 152 | std.debug.warn("{}", @tagName(base.id)); |
| 152 | } | 153 | } |
| 153 | 154 | ||
| 155 | fn init(base: *Type, comp: *Compilation, id: Id, name: []const u8) void { | ||
| 156 | base.* = Type{ | ||
| 157 | .base = Value{ | ||
| 158 | .id = Value.Id.Type, | ||
| 159 | .typeof = &MetaType.get(comp).base, | ||
| 160 | .ref_count = std.atomic.Int(usize).init(1), | ||
| 161 | }, | ||
| 162 | .id = id, | ||
| 163 | .name = name, | ||
| 164 | }; | ||
| 165 | } | ||
| 166 | |||
| 154 | pub fn getAbiAlignment(base: *Type, comp: *Compilation) u32 { | 167 | pub fn getAbiAlignment(base: *Type, comp: *Compilation) u32 { |
| 155 | @panic("TODO getAbiAlignment"); | 168 | @panic("TODO getAbiAlignment"); |
| 156 | } | 169 | } |
| ... | @@ -181,20 +194,15 @@ pub const Type = struct { | ... | @@ -181,20 +194,15 @@ pub const Type = struct { |
| 181 | 194 | ||
| 182 | pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn { | 195 | pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn { |
| 183 | const result = try comp.gpa().create(Fn{ | 196 | const result = try comp.gpa().create(Fn{ |
| 184 | .base = Type{ | 197 | .base = undefined, |
| 185 | .base = Value{ | ||
| 186 | .id = Value.Id.Type, | ||
| 187 | .typeof = &MetaType.get(comp).base, | ||
| 188 | .ref_count = std.atomic.Int(usize).init(1), | ||
| 189 | }, | ||
| 190 | .id = builtin.TypeId.Fn, | ||
| 191 | }, | ||
| 192 | .return_type = return_type, | 198 | .return_type = return_type, |
| 193 | .params = params, | 199 | .params = params, |
| 194 | .is_var_args = is_var_args, | 200 | .is_var_args = is_var_args, |
| 195 | }); | 201 | }); |
| 196 | errdefer comp.gpa().destroy(result); | 202 | errdefer comp.gpa().destroy(result); |
| 197 | 203 | ||
| 204 | result.base.init(comp, Id.Fn, "TODO fn type name"); | ||
| 205 | |||
| 198 | result.return_type.base.ref(); | 206 | result.return_type.base.ref(); |
| 199 | for (result.params) |param| { | 207 | for (result.params) |param| { |
| 200 | param.typeof.base.ref(); | 208 | param.typeof.base.ref(); |
| ... | @@ -293,13 +301,77 @@ pub const Type = struct { | ... | @@ -293,13 +301,77 @@ pub const Type = struct { |
| 293 | 301 | ||
| 294 | pub const Int = struct { | 302 | pub const Int = struct { |
| 295 | base: Type, | 303 | base: Type, |
| 304 | key: Key, | ||
| 305 | garbage_node: std.atomic.Stack(*Int).Node, | ||
| 306 | |||
| 307 | pub const Key = struct { | ||
| 308 | bit_count: u32, | ||
| 309 | is_signed: bool, | ||
| 310 | |||
| 311 | pub fn hash(self: *const Key) u32 { | ||
| 312 | const rands = [2]u32{ 0xa4ba6498, 0x75fc5af7 }; | ||
| 313 | return rands[@boolToInt(self.is_signed)] *% self.bit_count; | ||
| 314 | } | ||
| 315 | |||
| 316 | pub fn eql(self: *const Key, other: *const Key) bool { | ||
| 317 | return self.bit_count == other.bit_count and self.is_signed == other.is_signed; | ||
| 318 | } | ||
| 319 | }; | ||
| 320 | |||
| 321 | pub async fn get(comp: *Compilation, key: Key) !*Int { | ||
| 322 | { | ||
| 323 | const held = await (async comp.int_type_table.acquire() catch unreachable); | ||
| 324 | defer held.release(); | ||
| 325 | |||
| 326 | if (held.value.get(&key)) |entry| { | ||
| 327 | return entry.value; | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | const self = try comp.gpa().create(Int{ | ||
| 332 | .base = undefined, | ||
| 333 | .key = key, | ||
| 334 | .garbage_node = undefined, | ||
| 335 | }); | ||
| 336 | errdefer comp.gpa().destroy(self); | ||
| 337 | |||
| 338 | const u_or_i = "ui"[@boolToInt(key.is_signed)]; | ||
| 339 | const name = std.fmt.allocPrint(comp.gpa(), "{c}{}", u_or_i, key.bit_count); | ||
| 340 | errdefer comp.gpa().free(name); | ||
| 341 | |||
| 342 | self.base.init(comp, Id.Int, name); | ||
| 343 | |||
| 344 | { | ||
| 345 | const held = await (async comp.int_type_table.acquire() catch unreachable); | ||
| 346 | defer held.release(); | ||
| 347 | |||
| 348 | held.value.put(&self.key, self); | ||
| 349 | } | ||
| 350 | return self; | ||
| 351 | } | ||
| 296 | 352 | ||
| 297 | pub fn destroy(self: *Int, comp: *Compilation) void { | 353 | pub fn destroy(self: *Int, comp: *Compilation) void { |
| 354 | self.garbage_node = std.atomic.Stack(*Int).Node{ | ||
| 355 | .data = self, | ||
| 356 | .next = undefined, | ||
| 357 | }; | ||
| 358 | comp.registerGarbage(Int, &self.garbage_node); | ||
| 359 | } | ||
| 360 | |||
| 361 | pub async fn gcDestroy(self: *Int, comp: *Compilation) void { | ||
| 362 | { | ||
| 363 | const held = await (async comp.int_type_table.acquire() catch unreachable); | ||
| 364 | defer held.release(); | ||
| 365 | |||
| 366 | _ = held.value.remove(&self.key).?; | ||
| 367 | } | ||
| 368 | // we allocated the name | ||
| 369 | comp.gpa().free(self.base.name); | ||
| 298 | comp.gpa().destroy(self); | 370 | comp.gpa().destroy(self); |
| 299 | } | 371 | } |
| 300 | 372 | ||
| 301 | pub fn getLlvmType(self: *Int, ofile: *ObjectFile) llvm.TypeRef { | 373 | pub fn getLlvmType(self: *Int, ofile: *ObjectFile) !llvm.TypeRef { |
| 302 | @panic("TODO"); | 374 | return llvm.IntTypeInContext(ofile.context, self.key.bit_count) orelse return error.OutOfMemory; |
| 303 | } | 375 | } |
| 304 | }; | 376 | }; |
| 305 | 377 | ||
| ... | @@ -374,6 +446,12 @@ pub const Type = struct { | ... | @@ -374,6 +446,12 @@ pub const Type = struct { |
| 374 | pub const ComptimeInt = struct { | 446 | pub const ComptimeInt = struct { |
| 375 | base: Type, | 447 | base: Type, |
| 376 | 448 | ||
| 449 | /// Adds 1 reference to the resulting type | ||
| 450 | pub fn get(comp: *Compilation) *ComptimeInt { | ||
| 451 | comp.comptime_int_type.base.base.ref(); | ||
| 452 | return comp.comptime_int_type; | ||
| 453 | } | ||
| 454 | |||
| 377 | pub fn destroy(self: *ComptimeInt, comp: *Compilation) void { | 455 | pub fn destroy(self: *ComptimeInt, comp: *Compilation) void { |
| 378 | comp.gpa().destroy(self); | 456 | comp.gpa().destroy(self); |
| 379 | } | 457 | } |
src-self-hosted/value.zig+58| ... | @@ -29,6 +29,7 @@ pub const Value = struct { | ... | @@ -29,6 +29,7 @@ pub const Value = struct { |
| 29 | Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp), | 29 | Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp), |
| 30 | Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp), | 30 | Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp), |
| 31 | Id.Ptr => @fieldParentPtr(Ptr, "base", base).destroy(comp), | 31 | Id.Ptr => @fieldParentPtr(Ptr, "base", base).destroy(comp), |
| 32 | Id.Int => @fieldParentPtr(Int, "base", base).destroy(comp), | ||
| 32 | } | 33 | } |
| 33 | } | 34 | } |
| 34 | } | 35 | } |
| ... | @@ -50,6 +51,7 @@ pub const Value = struct { | ... | @@ -50,6 +51,7 @@ pub const Value = struct { |
| 50 | Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile), | 51 | Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile), |
| 51 | Id.NoReturn => unreachable, | 52 | Id.NoReturn => unreachable, |
| 52 | Id.Ptr => @panic("TODO"), | 53 | Id.Ptr => @panic("TODO"), |
| 54 | Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmConst(ofile), | ||
| 53 | } | 55 | } |
| 54 | } | 56 | } |
| 55 | 57 | ||
| ... | @@ -60,6 +62,7 @@ pub const Value = struct { | ... | @@ -60,6 +62,7 @@ pub const Value = struct { |
| 60 | Bool, | 62 | Bool, |
| 61 | NoReturn, | 63 | NoReturn, |
| 62 | Ptr, | 64 | Ptr, |
| 65 | Int, | ||
| 63 | }; | 66 | }; |
| 64 | 67 | ||
| 65 | pub const Type = @import("type.zig").Type; | 68 | pub const Type = @import("type.zig").Type; |
| ... | @@ -198,4 +201,59 @@ pub const Value = struct { | ... | @@ -198,4 +201,59 @@ pub const Value = struct { |
| 198 | comp.gpa().destroy(self); | 201 | comp.gpa().destroy(self); |
| 199 | } | 202 | } |
| 200 | }; | 203 | }; |
| 204 | |||
| 205 | pub const Int = struct { | ||
| 206 | base: Value, | ||
| 207 | big_int: std.math.big.Int, | ||
| 208 | |||
| 209 | pub fn createFromString(comp: *Compilation, typeof: *Type, base: u8, value: []const u8) !*Int { | ||
| 210 | const self = try comp.gpa().create(Value.Int{ | ||
| 211 | .base = Value{ | ||
| 212 | .id = Value.Id.Int, | ||
| 213 | .typeof = typeof, | ||
| 214 | .ref_count = std.atomic.Int(usize).init(1), | ||
| 215 | }, | ||
| 216 | .big_int = undefined, | ||
| 217 | }); | ||
| 218 | typeof.base.ref(); | ||
| 219 | errdefer comp.gpa().destroy(self); | ||
| 220 | |||
| 221 | self.big_int = try std.math.big.Int.init(comp.gpa()); | ||
| 222 | errdefer self.big_int.deinit(); | ||
| 223 | |||
| 224 | try self.big_int.setString(base, value); | ||
| 225 | |||
| 226 | return self; | ||
| 227 | } | ||
| 228 | |||
| 229 | pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef { | ||
| 230 | switch (self.base.typeof.id) { | ||
| 231 | Type.Id.Int => { | ||
| 232 | const type_ref = try self.base.typeof.getLlvmType(ofile); | ||
| 233 | if (self.big_int.len == 0) { | ||
| 234 | return llvm.ConstNull(type_ref); | ||
| 235 | } | ||
| 236 | const unsigned_val = if (self.big_int.len == 1) blk: { | ||
| 237 | break :blk llvm.ConstInt(type_ref, self.big_int.limbs[0], @boolToInt(false)); | ||
| 238 | } else if (@sizeOf(std.math.big.Limb) == @sizeOf(u64)) blk: { | ||
| 239 | break :blk llvm.ConstIntOfArbitraryPrecision( | ||
| 240 | type_ref, | ||
| 241 | @intCast(c_uint, self.big_int.len), | ||
| 242 | @ptrCast([*]u64, self.big_int.limbs.ptr), | ||
| 243 | ); | ||
| 244 | } else { | ||
| 245 | @compileError("std.math.Big.Int.Limb size does not match LLVM"); | ||
| 246 | }; | ||
| 247 | return if (self.big_int.positive) unsigned_val else llvm.ConstNeg(unsigned_val); | ||
| 248 | }, | ||
| 249 | Type.Id.ComptimeInt => unreachable, | ||
| 250 | else => unreachable, | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | pub fn destroy(self: *Int, comp: *Compilation) void { | ||
| 255 | self.big_int.deinit(); | ||
| 256 | comp.gpa().destroy(self); | ||
| 257 | } | ||
| 258 | }; | ||
| 201 | }; | 259 | }; |
std/event/group.zig+11| ... | @@ -38,6 +38,15 @@ pub fn Group(comptime ReturnType: type) type { | ... | @@ -38,6 +38,15 @@ pub fn Group(comptime ReturnType: type) type { |
| 38 | self.alloc_stack.push(node); | 38 | self.alloc_stack.push(node); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | /// Add a node to the group. Thread-safe. Cannot fail. | ||
| 42 | /// `node.data` should be the promise handle to add to the group. | ||
| 43 | /// The node's memory should be in the coroutine frame of | ||
| 44 | /// the handle that is in the node, or somewhere guaranteed to live | ||
| 45 | /// at least as long. | ||
| 46 | pub fn addNode(self: *Self, node: *Stack.Node) void { | ||
| 47 | self.coro_stack.push(node); | ||
| 48 | } | ||
| 49 | |||
| 41 | /// This is equivalent to an async call, but the async function is added to the group, instead | 50 | /// This is equivalent to an async call, but the async function is added to the group, instead |
| 42 | /// of returning a promise. func must be async and have return type ReturnType. | 51 | /// of returning a promise. func must be async and have return type ReturnType. |
| 43 | /// Thread-safe. | 52 | /// Thread-safe. |
| ... | @@ -98,6 +107,8 @@ pub fn Group(comptime ReturnType: type) type { | ... | @@ -98,6 +107,8 @@ pub fn Group(comptime ReturnType: type) type { |
| 98 | } | 107 | } |
| 99 | 108 | ||
| 100 | /// Cancel all the outstanding promises. May only be called if wait was never called. | 109 | /// Cancel all the outstanding promises. May only be called if wait was never called. |
| 110 | /// TODO These should be `cancelasync` not `cancel`. | ||
| 111 | /// See https://github.com/ziglang/zig/issues/1261 | ||
| 101 | pub fn cancelAll(self: *Self) void { | 112 | pub fn cancelAll(self: *Self) void { |
| 102 | while (self.coro_stack.pop()) |node| { | 113 | while (self.coro_stack.pop()) |node| { |
| 103 | cancel node.data; | 114 | cancel node.data; |
std/math/big/int.zig+2-1| ... | @@ -60,8 +60,9 @@ pub const Int = struct { | ... | @@ -60,8 +60,9 @@ pub const Int = struct { |
| 60 | self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity); | 60 | self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | pub fn deinit(self: Int) void { | 63 | pub fn deinit(self: *Int) void { |
| 64 | self.allocator.free(self.limbs); | 64 | self.allocator.free(self.limbs); |
| 65 | self.* = undefined; | ||
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | pub fn clone(other: Int) !Int { | 68 | pub fn clone(other: Int) !Int { |