| 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 | 489 | "math/atan.zig" |
| 490 | 490 | "math/atan2.zig" |
| 491 | 491 | "math/atanh.zig" |
| 492 | "math/big/index.zig" | |
| 492 | 493 | "math/big/int.zig" |
| 493 | 494 | "math/cbrt.zig" |
| 494 | 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 | 29 | const Package = @import("package.zig").Package; |
| 30 | 30 | const link = @import("link.zig").link; |
| 31 | 31 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 32 | const CInt = @import("c_int.zig").CInt; | |
| 32 | 33 | |
| 33 | 34 | /// Data that is local to the event loop. |
| 34 | 35 | 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 | 64 | fn deinit(self: *EventLoopLocal) void { |
| 63 | 65 | while (self.llvm_handle_pool.pop()) |node| { |
| 64 | 66 | c.LLVMContextDispose(node.data); |
| ... | ... | @@ -184,6 +186,7 @@ pub const Compilation = struct { |
| 184 | 186 | void_type: *Type.Void, |
| 185 | 187 | bool_type: *Type.Bool, |
| 186 | 188 | noreturn_type: *Type.NoReturn, |
| 189 | comptime_int_type: *Type.ComptimeInt, | |
| 187 | 190 | |
| 188 | 191 | void_value: *Value.Void, |
| 189 | 192 | true_value: *Value.Bool, |
| ... | ... | @@ -209,6 +212,16 @@ pub const Compilation = struct { |
| 209 | 212 | |
| 210 | 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 | 225 | const CompileErrList = std.ArrayList(*errmsg.Msg); |
| 213 | 226 | |
| 214 | 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 | 375 | .prelink_group = event.Group(BuildError!void).init(loop), |
| 363 | 376 | .deinit_group = event.Group(void).init(loop), |
| 364 | 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 | 381 | .meta_type = undefined, |
| 367 | 382 | .void_type = undefined, |
| ... | ... | @@ -371,6 +386,7 @@ pub const Compilation = struct { |
| 371 | 386 | .false_value = undefined, |
| 372 | 387 | .noreturn_type = undefined, |
| 373 | 388 | .noreturn_value = undefined, |
| 389 | .comptime_int_type = undefined, | |
| 374 | 390 | |
| 375 | 391 | .target_machine = undefined, |
| 376 | 392 | .target_data_ref = undefined, |
| ... | ... | @@ -382,8 +398,10 @@ pub const Compilation = struct { |
| 382 | 398 | .override_libc = null, |
| 383 | 399 | .destroy_handle = undefined, |
| 384 | 400 | .have_err_ret_tracing = false, |
| 401 | .primitive_type_table = undefined, | |
| 385 | 402 | }); |
| 386 | 403 | errdefer { |
| 404 | comp.int_type_table.private_data.deinit(); | |
| 387 | 405 | comp.arena_allocator.deinit(); |
| 388 | 406 | comp.loop.allocator.destroy(comp); |
| 389 | 407 | } |
| ... | ... | @@ -393,6 +411,7 @@ pub const Compilation = struct { |
| 393 | 411 | comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple); |
| 394 | 412 | comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena()); |
| 395 | 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 | 416 | const opt_level = switch (build_mode) { |
| 398 | 417 | builtin.Mode.Debug => llvm.CodeGenLevelNone, |
| ... | ... | @@ -445,7 +464,6 @@ pub const Compilation = struct { |
| 445 | 464 | } |
| 446 | 465 | |
| 447 | 466 | try comp.initTypes(); |
| 448 | errdefer comp.derefTypes(); | |
| 449 | 467 | |
| 450 | 468 | comp.destroy_handle = try async<loop.allocator> comp.internalDeinit(); |
| 451 | 469 | |
| ... | ... | @@ -453,8 +471,9 @@ pub const Compilation = struct { |
| 453 | 471 | } |
| 454 | 472 | |
| 455 | 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 | 475 | .base = Type{ |
| 476 | .name = "type", | |
| 458 | 477 | .base = Value{ |
| 459 | 478 | .id = Value.Id.Type, |
| 460 | 479 | .typeof = undefined, |
| ... | ... | @@ -466,10 +485,11 @@ pub const Compilation = struct { |
| 466 | 485 | }); |
| 467 | 486 | comp.meta_type.value = &comp.meta_type.base; |
| 468 | 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 | 491 | .base = Type{ |
| 492 | .name = "void", | |
| 473 | 493 | .base = Value{ |
| 474 | 494 | .id = Value.Id.Type, |
| 475 | 495 | .typeof = &Type.MetaType.get(comp).base, |
| ... | ... | @@ -478,10 +498,11 @@ pub const Compilation = struct { |
| 478 | 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 | 504 | .base = Type{ |
| 505 | .name = "noreturn", | |
| 485 | 506 | .base = Value{ |
| 486 | 507 | .id = Value.Id.Type, |
| 487 | 508 | .typeof = &Type.MetaType.get(comp).base, |
| ... | ... | @@ -490,10 +511,24 @@ pub const Compilation = struct { |
| 490 | 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 | 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 | 532 | .base = Value{ |
| 498 | 533 | .id = Value.Id.Type, |
| 499 | 534 | .typeof = &Type.MetaType.get(comp).base, |
| ... | ... | @@ -502,18 +537,17 @@ pub const Compilation = struct { |
| 502 | 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 | 543 | .base = Value{ |
| 509 | 544 | .id = Value.Id.Void, |
| 510 | 545 | .typeof = &Type.Void.get(comp).base, |
| 511 | 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 | 551 | .base = Value{ |
| 518 | 552 | .id = Value.Id.Bool, |
| 519 | 553 | .typeof = &Type.Bool.get(comp).base, |
| ... | ... | @@ -521,9 +555,8 @@ pub const Compilation = struct { |
| 521 | 555 | }, |
| 522 | 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 | 560 | .base = Value{ |
| 528 | 561 | .id = Value.Id.Bool, |
| 529 | 562 | .typeof = &Type.Bool.get(comp).base, |
| ... | ... | @@ -531,44 +564,56 @@ pub const Compilation = struct { |
| 531 | 564 | }, |
| 532 | 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 | 569 | .base = Value{ |
| 538 | 570 | .id = Value.Id.NoReturn, |
| 539 | 571 | .typeof = &Type.NoReturn.get(comp).base, |
| 540 | 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 { | |
| 547 | self.noreturn_value.base.deref(self); | |
| 548 | self.void_value.base.deref(self); | |
| 549 | self.false_value.base.deref(self); | |
| 550 | self.true_value.base.deref(self); | |
| 551 | self.noreturn_type.base.base.deref(self); | |
| 552 | self.void_type.base.base.deref(self); | |
| 553 | self.meta_type.base.base.deref(self); | |
| 576 | for (CInt.list) |cint, i| { | |
| 577 | const c_int_type = try comp.arena().create(Type.Int{ | |
| 578 | .base = Type{ | |
| 579 | .name = cint.zig_name, | |
| 580 | .base = Value{ | |
| 581 | .id = Value.Id.Type, | |
| 582 | .typeof = &Type.MetaType.get(comp).base, | |
| 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 | 600 | async fn internalDeinit(self: *Compilation) void { |
| 557 | 601 | suspend; |
| 602 | ||
| 558 | 603 | await (async self.deinit_group.wait() catch unreachable); |
| 559 | 604 | if (self.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| { |
| 560 | 605 | // TODO evented I/O? |
| 561 | 606 | os.deleteTree(self.arena(), tmp_dir) catch {}; |
| 562 | 607 | } else |_| {}; |
| 563 | 608 | |
| 564 | self.derefTypes(); | |
| 565 | ||
| 566 | 609 | self.events.destroy(); |
| 567 | 610 | |
| 568 | 611 | llvm.DisposeMessage(self.target_layout_str); |
| 569 | 612 | llvm.DisposeTargetData(self.target_data_ref); |
| 570 | 613 | llvm.DisposeTargetMachine(self.target_machine); |
| 571 | 614 | |
| 615 | self.primitive_type_table.deinit(); | |
| 616 | ||
| 572 | 617 | self.arena_allocator.deinit(); |
| 573 | 618 | self.gpa().destroy(self); |
| 574 | 619 | } |
| ... | ... | @@ -939,6 +984,10 @@ pub const Compilation = struct { |
| 939 | 984 | b64_fs_encoder.encode(result[0..], rand_bytes); |
| 940 | 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 | 993 | fn printError(comptime format: []const u8, args: ...) !void { |
| ... | ... | @@ -1005,7 +1054,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 1005 | 1054 | fn_decl.base.parsed_file, |
| 1006 | 1055 | &fndef_scope.base, |
| 1007 | 1056 | body_node, |
| 1008 | null, | |
| 1057 | return_type, | |
| 1009 | 1058 | ) catch unreachable)) orelse return; |
| 1010 | 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 | 705 | ast.Node.Id.ErrorType => return error.Unimplemented, |
| 706 | 706 | ast.Node.Id.FnProto => return error.Unimplemented, |
| 707 | 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 | 712 | ast.Node.Id.FloatLiteral => return error.Unimplemented, |
| 710 | 713 | ast.Node.Id.StringLiteral => return error.Unimplemented, |
| 711 | 714 | ast.Node.Id.MultilineStringLiteral => return error.Unimplemented, |
| ... | ... | @@ -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 | 811 | pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst { |
| 770 | 812 | const block_scope = try Scope.Block.create(irb.comp, parent_scope); |
| 771 | 813 | |
| ... | ... | @@ -1306,7 +1348,436 @@ const Analyze = struct { |
| 1306 | 1348 | |
| 1307 | 1349 | fn implicitCast(self: *Analyze, target: *Inst, optional_dest_type: ?*Type) Analyze.Error!*Inst { |
| 1308 | 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 | 1783 | fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Inst) ?*Value { |
src-self-hosted/llvm.zig+2| ... | ... | @@ -30,6 +30,8 @@ pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag; |
| 30 | 30 | pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; |
| 31 | 31 | pub const ConstAllOnes = c.LLVMConstAllOnes; |
| 32 | 32 | pub const ConstInt = c.LLVMConstInt; |
| 33 | pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision; | |
| 34 | pub const ConstNeg = c.LLVMConstNeg; | |
| 33 | 35 | pub const ConstNull = c.LLVMConstNull; |
| 34 | 36 | pub const ConstStringInContext = c.LLVMConstStringInContext; |
| 35 | 37 | pub const ConstStructInContext = c.LLVMConstStructInContext; |
src-self-hosted/target.zig+98-1| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | const llvm = @import("llvm.zig"); |
| 4 | const CInt = @import("c_int.zig").CInt; | |
| 4 | 5 | |
| 5 | 6 | pub const FloatAbi = enum { |
| 6 | 7 | Hard, |
| ... | ... | @@ -173,7 +174,7 @@ pub const Target = union(enum) { |
| 173 | 174 | return self.getArchPtrBitWidth() == 64; |
| 174 | 175 | } |
| 175 | 176 | |
| 176 | pub fn getArchPtrBitWidth(self: Target) u8 { | |
| 177 | pub fn getArchPtrBitWidth(self: Target) u32 { | |
| 177 | 178 | switch (self.getArch()) { |
| 178 | 179 | builtin.Arch.avr, |
| 179 | 180 | builtin.Arch.msp430, |
| ... | ... | @@ -429,4 +430,100 @@ pub const Target = union(enum) { |
| 429 | 430 | } |
| 430 | 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 | 9 | pub const Type = struct { |
| 10 | 10 | base: Value, |
| 11 | 11 | id: Id, |
| 12 | name: []const u8, | |
| 12 | 13 | |
| 13 | 14 | pub const Id = builtin.TypeId; |
| 14 | 15 | |
| ... | ... | @@ -151,6 +152,18 @@ pub const Type = struct { |
| 151 | 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 | 167 | pub fn getAbiAlignment(base: *Type, comp: *Compilation) u32 { |
| 155 | 168 | @panic("TODO getAbiAlignment"); |
| 156 | 169 | } |
| ... | ... | @@ -181,20 +194,15 @@ pub const Type = struct { |
| 181 | 194 | |
| 182 | 195 | pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn { |
| 183 | 196 | const result = try comp.gpa().create(Fn{ |
| 184 | .base = Type{ | |
| 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 | }, | |
| 197 | .base = undefined, | |
| 192 | 198 | .return_type = return_type, |
| 193 | 199 | .params = params, |
| 194 | 200 | .is_var_args = is_var_args, |
| 195 | 201 | }); |
| 196 | 202 | errdefer comp.gpa().destroy(result); |
| 197 | 203 | |
| 204 | result.base.init(comp, Id.Fn, "TODO fn type name"); | |
| 205 | ||
| 198 | 206 | result.return_type.base.ref(); |
| 199 | 207 | for (result.params) |param| { |
| 200 | 208 | param.typeof.base.ref(); |
| ... | ... | @@ -293,13 +301,77 @@ pub const Type = struct { |
| 293 | 301 | |
| 294 | 302 | pub const Int = struct { |
| 295 | 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 | 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 | 370 | comp.gpa().destroy(self); |
| 299 | 371 | } |
| 300 | 372 | |
| 301 | pub fn getLlvmType(self: *Int, ofile: *ObjectFile) llvm.TypeRef { | |
| 302 | @panic("TODO"); | |
| 373 | pub fn getLlvmType(self: *Int, ofile: *ObjectFile) !llvm.TypeRef { | |
| 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 | 446 | pub const ComptimeInt = struct { |
| 375 | 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 | 455 | pub fn destroy(self: *ComptimeInt, comp: *Compilation) void { |
| 378 | 456 | comp.gpa().destroy(self); |
| 379 | 457 | } |
src-self-hosted/value.zig+58| ... | ... | @@ -29,6 +29,7 @@ pub const Value = struct { |
| 29 | 29 | Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp), |
| 30 | 30 | Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp), |
| 31 | 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 | 51 | Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile), |
| 51 | 52 | Id.NoReturn => unreachable, |
| 52 | 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 | 62 | Bool, |
| 61 | 63 | NoReturn, |
| 62 | 64 | Ptr, |
| 65 | Int, | |
| 63 | 66 | }; |
| 64 | 67 | |
| 65 | 68 | pub const Type = @import("type.zig").Type; |
| ... | ... | @@ -198,4 +201,59 @@ pub const Value = struct { |
| 198 | 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 | 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 | 50 | /// This is equivalent to an async call, but the async function is added to the group, instead |
| 42 | 51 | /// of returning a promise. func must be async and have return type ReturnType. |
| 43 | 52 | /// Thread-safe. |
| ... | ... | @@ -98,6 +107,8 @@ pub fn Group(comptime ReturnType: type) type { |
| 98 | 107 | } |
| 99 | 108 | |
| 100 | 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 | 112 | pub fn cancelAll(self: *Self) void { |
| 102 | 113 | while (self.coro_stack.pop()) |node| { |
| 103 | 114 | cancel node.data; |
std/math/big/int.zig+2-1| ... | ... | @@ -60,8 +60,9 @@ pub const Int = struct { |
| 60 | 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 | 64 | self.allocator.free(self.limbs); |
| 65 | self.* = undefined; | |
| 65 | 66 | } |
| 66 | 67 | |
| 67 | 68 | pub fn clone(other: Int) !Int { |