| ... | @@ -90,7 +90,15 @@ const FormatTypeAsCIdentContext = struct { | ... | @@ -90,7 +90,15 @@ const FormatTypeAsCIdentContext = struct { |
| 90 | const ValueRenderLocation = enum { | 90 | const ValueRenderLocation = enum { |
| 91 | FunctionArgument, | 91 | FunctionArgument, |
| 92 | Initializer, | 92 | Initializer, |
| | 93 | StaticInitializer, |
| 93 | Other, | 94 | Other, |
| | 95 | |
| | 96 | pub fn isInitializer(self: ValueRenderLocation) bool { |
| | 97 | return switch (self) { |
| | 98 | .Initializer, .StaticInitializer => true, |
| | 99 | else => false, |
| | 100 | }; |
| | 101 | } |
| 94 | }; | 102 | }; |
| 95 | | 103 | |
| 96 | const BuiltinInfo = enum { | 104 | const BuiltinInfo = enum { |
| ... | @@ -312,7 +320,7 @@ pub const Function = struct { | ... | @@ -312,7 +320,7 @@ pub const Function = struct { |
| 312 | try writer.writeAll("static "); | 320 | try writer.writeAll("static "); |
| 313 | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete); | 321 | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete); |
| 314 | try writer.writeAll(" = "); | 322 | try writer.writeAll(" = "); |
| 315 | try f.object.dg.renderValue(writer, ty, val, .Initializer); | 323 | try f.object.dg.renderValue(writer, ty, val, .StaticInitializer); |
| 316 | try writer.writeAll(";\n "); | 324 | try writer.writeAll(";\n "); |
| 317 | break :result decl_c_value; | 325 | break :result decl_c_value; |
| 318 | } else CValue{ .constant = inst }; | 326 | } else CValue{ .constant = inst }; |
| ... | @@ -431,6 +439,10 @@ pub const Function = struct { | ... | @@ -431,6 +439,10 @@ pub const Function = struct { |
| 431 | return f.object.dg.renderTypecast(w, t); | 439 | return f.object.dg.renderTypecast(w, t); |
| 432 | } | 440 | } |
| 433 | | 441 | |
| | 442 | fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void { |
| | 443 | return f.object.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src } }, src_ty, location); |
| | 444 | } |
| | 445 | |
| 434 | fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) { | 446 | fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) { |
| 435 | return f.object.dg.fmtIntLiteral(ty, val); | 447 | return f.object.dg.fmtIntLiteral(ty, val); |
| 436 | } | 448 | } |
| ... | @@ -502,6 +514,7 @@ pub const DeclGen = struct { | ... | @@ -502,6 +514,7 @@ pub const DeclGen = struct { |
| 502 | ty: Type, | 514 | ty: Type, |
| 503 | val: Value, | 515 | val: Value, |
| 504 | decl_index: Decl.Index, | 516 | decl_index: Decl.Index, |
| | 517 | location: ValueRenderLocation, |
| 505 | ) error{ OutOfMemory, AnalysisFail }!void { | 518 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 506 | const decl = dg.module.declPtr(decl_index); | 519 | const decl = dg.module.declPtr(decl_index); |
| 507 | assert(decl.has_tv); | 520 | assert(decl.has_tv); |
| ... | @@ -515,12 +528,16 @@ pub const DeclGen = struct { | ... | @@ -515,12 +528,16 @@ pub const DeclGen = struct { |
| 515 | inline for (.{ .function, .extern_fn }) |tag| | 528 | inline for (.{ .function, .extern_fn }) |tag| |
| 516 | if (decl.val.castTag(tag)) |func| | 529 | if (decl.val.castTag(tag)) |func| |
| 517 | if (func.data.owner_decl != decl_index) | 530 | if (func.data.owner_decl != decl_index) |
| 518 | return dg.renderDeclValue(writer, ty, val, func.data.owner_decl); | 531 | return dg.renderDeclValue(writer, ty, val, func.data.owner_decl, location); |
| 519 | | 532 | |
| 520 | if (ty.isSlice()) { | 533 | if (ty.isSlice()) { |
| 521 | try writer.writeByte('('); | 534 | if (location == .StaticInitializer) { |
| 522 | try dg.renderTypecast(writer, ty); | 535 | try writer.writeByte('{'); |
| 523 | try writer.writeAll("){ .ptr = "); | 536 | } else { |
| | 537 | try writer.writeByte('('); |
| | 538 | try dg.renderTypecast(writer, ty); |
| | 539 | try writer.writeAll("){ .ptr = "); |
| | 540 | } |
| 524 | | 541 | |
| 525 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 542 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 526 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer); | 543 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer); |
| ... | @@ -530,7 +547,12 @@ pub const DeclGen = struct { | ... | @@ -530,7 +547,12 @@ pub const DeclGen = struct { |
| 530 | .data = val.sliceLen(dg.module), | 547 | .data = val.sliceLen(dg.module), |
| 531 | }; | 548 | }; |
| 532 | const len_val = Value.initPayload(&len_pl.base); | 549 | const len_val = Value.initPayload(&len_pl.base); |
| 533 | return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)}); | 550 | |
| | 551 | if (location == .StaticInitializer) { |
| | 552 | return writer.print(", {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)}); |
| | 553 | } else { |
| | 554 | return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)}); |
| | 555 | } |
| 534 | } | 556 | } |
| 535 | | 557 | |
| 536 | // We shouldn't cast C function pointers as this is UB (when you call | 558 | // We shouldn't cast C function pointers as this is UB (when you call |
| ... | @@ -552,7 +574,7 @@ pub const DeclGen = struct { | ... | @@ -552,7 +574,7 @@ pub const DeclGen = struct { |
| 552 | // that its contents are defined with respect to. | 574 | // that its contents are defined with respect to. |
| 553 | // | 575 | // |
| 554 | // Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr | 576 | // Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr |
| 555 | fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type) error{ OutOfMemory, AnalysisFail }!void { | 577 | fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void { |
| 556 | if (!ptr_ty.isSlice()) { | 578 | if (!ptr_ty.isSlice()) { |
| 557 | try writer.writeByte('('); | 579 | try writer.writeByte('('); |
| 558 | try dg.renderTypecast(writer, ptr_ty); | 580 | try dg.renderTypecast(writer, ptr_ty); |
| ... | @@ -567,7 +589,7 @@ pub const DeclGen = struct { | ... | @@ -567,7 +589,7 @@ pub const DeclGen = struct { |
| 567 | .variable => ptr_val.castTag(.variable).?.data.owner_decl, | 589 | .variable => ptr_val.castTag(.variable).?.data.owner_decl, |
| 568 | else => unreachable, | 590 | else => unreachable, |
| 569 | }; | 591 | }; |
| 570 | try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index); | 592 | try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location); |
| 571 | }, | 593 | }, |
| 572 | .field_ptr => { | 594 | .field_ptr => { |
| 573 | const ptr_info = ptr_ty.ptrInfo(); | 595 | const ptr_info = ptr_ty.ptrInfo(); |
| ... | @@ -605,7 +627,7 @@ pub const DeclGen = struct { | ... | @@ -605,7 +627,7 @@ pub const DeclGen = struct { |
| 605 | try writer.writeAll("&(("); | 627 | try writer.writeAll("&(("); |
| 606 | try dg.renderTypecast(writer, u8_ptr_ty); | 628 | try dg.renderTypecast(writer, u8_ptr_ty); |
| 607 | try writer.writeByte(')'); | 629 | try writer.writeByte(')'); |
| 608 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); | 630 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location); |
| 609 | return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)}); | 631 | return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)}); |
| 610 | } else { | 632 | } else { |
| 611 | var host_pl = Type.Payload.Bits{ | 633 | var host_pl = Type.Payload.Bits{ |
| ... | @@ -617,7 +639,7 @@ pub const DeclGen = struct { | ... | @@ -617,7 +639,7 @@ pub const DeclGen = struct { |
| 617 | try writer.writeByte('('); | 639 | try writer.writeByte('('); |
| 618 | try dg.renderTypecast(writer, ptr_ty); | 640 | try dg.renderTypecast(writer, ptr_ty); |
| 619 | try writer.writeByte(')'); | 641 | try writer.writeByte(')'); |
| 620 | return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty); | 642 | return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty, location); |
| 621 | }, | 643 | }, |
| 622 | }, | 644 | }, |
| 623 | .Union => switch (container_ty.containerLayout()) { | 645 | .Union => switch (container_ty.containerLayout()) { |
| ... | @@ -626,7 +648,7 @@ pub const DeclGen = struct { | ... | @@ -626,7 +648,7 @@ pub const DeclGen = struct { |
| 626 | .ty = container_ty.unionFields().values()[index].ty, | 648 | .ty = container_ty.unionFields().values()[index].ty, |
| 627 | }, | 649 | }, |
| 628 | .Packed => { | 650 | .Packed => { |
| 629 | return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty); | 651 | return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty, location); |
| 630 | }, | 652 | }, |
| 631 | }, | 653 | }, |
| 632 | .Pointer => field_info: { | 654 | .Pointer => field_info: { |
| ... | @@ -645,7 +667,7 @@ pub const DeclGen = struct { | ... | @@ -645,7 +667,7 @@ pub const DeclGen = struct { |
| 645 | try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete); | 667 | try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete); |
| 646 | | 668 | |
| 647 | try writer.writeAll("&("); | 669 | try writer.writeAll("&("); |
| 648 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); | 670 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location); |
| 649 | try writer.writeAll(")->"); | 671 | try writer.writeAll(")->"); |
| 650 | switch (field_ptr.container_ty.tag()) { | 672 | switch (field_ptr.container_ty.tag()) { |
| 651 | .union_tagged, .union_safety_tagged => try writer.writeAll("payload."), | 673 | .union_tagged, .union_safety_tagged => try writer.writeAll("payload."), |
| ... | @@ -653,7 +675,7 @@ pub const DeclGen = struct { | ... | @@ -653,7 +675,7 @@ pub const DeclGen = struct { |
| 653 | } | 675 | } |
| 654 | try writer.print("{ }", .{fmtIdent(field_info.name)}); | 676 | try writer.print("{ }", .{fmtIdent(field_info.name)}); |
| 655 | } else { | 677 | } else { |
| 656 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); | 678 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location); |
| 657 | } | 679 | } |
| 658 | }, | 680 | }, |
| 659 | .elem_ptr => { | 681 | .elem_ptr => { |
| ... | @@ -665,7 +687,7 @@ pub const DeclGen = struct { | ... | @@ -665,7 +687,7 @@ pub const DeclGen = struct { |
| 665 | const elem_ptr_ty = Type.initPayload(&elem_ptr_ty_pl.base); | 687 | const elem_ptr_ty = Type.initPayload(&elem_ptr_ty_pl.base); |
| 666 | | 688 | |
| 667 | try writer.writeAll("&("); | 689 | try writer.writeAll("&("); |
| 668 | try dg.renderParentPtr(writer, elem_ptr.array_ptr, elem_ptr_ty); | 690 | try dg.renderParentPtr(writer, elem_ptr.array_ptr, elem_ptr_ty, location); |
| 669 | try writer.print(")[{d}]", .{elem_ptr.index}); | 691 | try writer.print(")[{d}]", .{elem_ptr.index}); |
| 670 | }, | 692 | }, |
| 671 | .opt_payload_ptr, .eu_payload_ptr => { | 693 | .opt_payload_ptr, .eu_payload_ptr => { |
| ... | @@ -680,7 +702,7 @@ pub const DeclGen = struct { | ... | @@ -680,7 +702,7 @@ pub const DeclGen = struct { |
| 680 | try dg.renderType(std.io.null_writer, payload_ptr.container_ty, .Complete); | 702 | try dg.renderType(std.io.null_writer, payload_ptr.container_ty, .Complete); |
| 681 | | 703 | |
| 682 | try writer.writeAll("&("); | 704 | try writer.writeAll("&("); |
| 683 | try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty); | 705 | try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location); |
| 684 | try writer.writeAll(")->payload"); | 706 | try writer.writeAll(")->payload"); |
| 685 | }, | 707 | }, |
| 686 | else => unreachable, | 708 | else => unreachable, |
| ... | @@ -699,6 +721,10 @@ pub const DeclGen = struct { | ... | @@ -699,6 +721,10 @@ pub const DeclGen = struct { |
| 699 | val = rt.data; | 721 | val = rt.data; |
| 700 | } | 722 | } |
| 701 | const target = dg.module.getTarget(); | 723 | const target = dg.module.getTarget(); |
| | 724 | const initializer_type: ValueRenderLocation = switch (location) { |
| | 725 | .StaticInitializer => .StaticInitializer, |
| | 726 | else => .Initializer, |
| | 727 | }; |
| 702 | | 728 | |
| 703 | const safety_on = switch (dg.module.optimizeMode()) { | 729 | const safety_on = switch (dg.module.optimizeMode()) { |
| 704 | .Debug, .ReleaseSafe => true, | 730 | .Debug, .ReleaseSafe => true, |
| ... | @@ -714,15 +740,15 @@ pub const DeclGen = struct { | ... | @@ -714,15 +740,15 @@ pub const DeclGen = struct { |
| 714 | return writer.writeAll("false"); | 740 | return writer.writeAll("false"); |
| 715 | } | 741 | } |
| 716 | }, | 742 | }, |
| 717 | .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val)}), | 743 | .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteralLoc(ty, val, location)}), |
| 718 | .Float => { | 744 | .Float => { |
| 719 | const bits = ty.floatBits(target); | 745 | const bits = ty.floatBits(target); |
| 720 | var int_pl = Type.Payload.Bits{ .base = .{ .tag = .int_signed }, .data = bits }; | 746 | var int_pl = Type.Payload.Bits{ .base = .{ .tag = .int_signed }, .data = bits }; |
| 721 | const int_ty = Type.initPayload(&int_pl.base); | 747 | const int_ty = Type.initPayload(&int_pl.base); |
| 722 | | 748 | |
| 723 | try writer.writeByte('('); | 749 | try writer.writeAll("zig_cast_"); |
| 724 | try dg.renderTypecast(writer, ty); | 750 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 725 | try writer.writeAll(")zig_as_"); | 751 | try writer.writeAll(" zig_as_"); |
| 726 | try dg.renderTypeForBuiltinFnName(writer, ty); | 752 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 727 | try writer.writeByte('('); | 753 | try writer.writeByte('('); |
| 728 | switch (bits) { | 754 | switch (bits) { |
| ... | @@ -738,7 +764,7 @@ pub const DeclGen = struct { | ... | @@ -738,7 +764,7 @@ pub const DeclGen = struct { |
| 738 | return writer.writeByte(')'); | 764 | return writer.writeByte(')'); |
| 739 | }, | 765 | }, |
| 740 | .Pointer => if (ty.isSlice()) { | 766 | .Pointer => if (ty.isSlice()) { |
| 741 | if (location != .Initializer) { | 767 | if (!location.isInitializer()) { |
| 742 | try writer.writeByte('('); | 768 | try writer.writeByte('('); |
| 743 | try dg.renderTypecast(writer, ty); | 769 | try dg.renderTypecast(writer, ty); |
| 744 | try writer.writeByte(')'); | 770 | try writer.writeByte(')'); |
| ... | @@ -766,21 +792,21 @@ pub const DeclGen = struct { | ... | @@ -766,21 +792,21 @@ pub const DeclGen = struct { |
| 766 | return dg.renderValue(writer, payload_ty, val, location); | 792 | return dg.renderValue(writer, payload_ty, val, location); |
| 767 | } | 793 | } |
| 768 | | 794 | |
| 769 | if (location != .Initializer) { | 795 | if (!location.isInitializer()) { |
| 770 | try writer.writeByte('('); | 796 | try writer.writeByte('('); |
| 771 | try dg.renderTypecast(writer, ty); | 797 | try dg.renderTypecast(writer, ty); |
| 772 | try writer.writeByte(')'); | 798 | try writer.writeByte(')'); |
| 773 | } | 799 | } |
| 774 | | 800 | |
| 775 | try writer.writeAll("{ .payload = "); | 801 | try writer.writeAll("{ .payload = "); |
| 776 | try dg.renderValue(writer, payload_ty, val, .Initializer); | 802 | try dg.renderValue(writer, payload_ty, val, initializer_type); |
| 777 | try writer.writeAll(", .is_null = "); | 803 | try writer.writeAll(", .is_null = "); |
| 778 | try dg.renderValue(writer, Type.bool, val, .Initializer); | 804 | try dg.renderValue(writer, Type.bool, val, initializer_type); |
| 779 | return writer.writeAll(" }"); | 805 | return writer.writeAll(" }"); |
| 780 | }, | 806 | }, |
| 781 | .Struct => switch (ty.containerLayout()) { | 807 | .Struct => switch (ty.containerLayout()) { |
| 782 | .Auto, .Extern => { | 808 | .Auto, .Extern => { |
| 783 | if (location != .Initializer) { | 809 | if (!location.isInitializer()) { |
| 784 | try writer.writeByte('('); | 810 | try writer.writeByte('('); |
| 785 | try dg.renderTypecast(writer, ty); | 811 | try dg.renderTypecast(writer, ty); |
| 786 | try writer.writeByte(')'); | 812 | try writer.writeByte(')'); |
| ... | @@ -792,7 +818,7 @@ pub const DeclGen = struct { | ... | @@ -792,7 +818,7 @@ pub const DeclGen = struct { |
| 792 | if (!field.ty.hasRuntimeBits()) continue; | 818 | if (!field.ty.hasRuntimeBits()) continue; |
| 793 | | 819 | |
| 794 | if (!empty) try writer.writeByte(','); | 820 | if (!empty) try writer.writeByte(','); |
| 795 | try dg.renderValue(writer, field.ty, val, .Initializer); | 821 | try dg.renderValue(writer, field.ty, val, initializer_type); |
| 796 | | 822 | |
| 797 | empty = false; | 823 | empty = false; |
| 798 | } | 824 | } |
| ... | @@ -802,7 +828,7 @@ pub const DeclGen = struct { | ... | @@ -802,7 +828,7 @@ pub const DeclGen = struct { |
| 802 | .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}), | 828 | .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}), |
| 803 | }, | 829 | }, |
| 804 | .Union => { | 830 | .Union => { |
| 805 | if (location != .Initializer) { | 831 | if (!location.isInitializer()) { |
| 806 | try writer.writeByte('('); | 832 | try writer.writeByte('('); |
| 807 | try dg.renderTypecast(writer, ty); | 833 | try dg.renderTypecast(writer, ty); |
| 808 | try writer.writeByte(')'); | 834 | try writer.writeByte(')'); |
| ... | @@ -813,34 +839,34 @@ pub const DeclGen = struct { | ... | @@ -813,34 +839,34 @@ pub const DeclGen = struct { |
| 813 | const layout = ty.unionGetLayout(target); | 839 | const layout = ty.unionGetLayout(target); |
| 814 | if (layout.tag_size != 0) { | 840 | if (layout.tag_size != 0) { |
| 815 | try writer.writeAll(" .tag = "); | 841 | try writer.writeAll(" .tag = "); |
| 816 | try dg.renderValue(writer, tag_ty, val, .Initializer); | 842 | try dg.renderValue(writer, tag_ty, val, initializer_type); |
| 817 | try writer.writeByte(','); | 843 | try writer.writeByte(','); |
| 818 | } | 844 | } |
| 819 | try writer.writeAll(" .payload = {"); | 845 | try writer.writeAll(" .payload = {"); |
| 820 | } | 846 | } |
| 821 | for (ty.unionFields().values()) |field| { | 847 | for (ty.unionFields().values()) |field| { |
| 822 | if (!field.ty.hasRuntimeBits()) continue; | 848 | if (!field.ty.hasRuntimeBits()) continue; |
| 823 | try dg.renderValue(writer, field.ty, val, .Initializer); | 849 | try dg.renderValue(writer, field.ty, val, initializer_type); |
| 824 | break; | 850 | break; |
| 825 | } else try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)}); | 851 | } else try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)}); |
| 826 | if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); | 852 | if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); |
| 827 | return writer.writeByte('}'); | 853 | return writer.writeByte('}'); |
| 828 | }, | 854 | }, |
| 829 | .ErrorUnion => { | 855 | .ErrorUnion => { |
| 830 | if (location != .Initializer) { | 856 | if (!location.isInitializer()) { |
| 831 | try writer.writeByte('('); | 857 | try writer.writeByte('('); |
| 832 | try dg.renderTypecast(writer, ty); | 858 | try dg.renderTypecast(writer, ty); |
| 833 | try writer.writeByte(')'); | 859 | try writer.writeByte(')'); |
| 834 | } | 860 | } |
| 835 | | 861 | |
| 836 | try writer.writeAll("{ .payload = "); | 862 | try writer.writeAll("{ .payload = "); |
| 837 | try dg.renderValue(writer, ty.errorUnionPayload(), val, .Initializer); | 863 | try dg.renderValue(writer, ty.errorUnionPayload(), val, initializer_type); |
| 838 | return writer.print(", .error = {x} }}", .{ | 864 | return writer.print(", .error = {x} }}", .{ |
| 839 | try dg.fmtIntLiteral(ty.errorUnionSet(), val), | 865 | try dg.fmtIntLiteral(ty.errorUnionSet(), val), |
| 840 | }); | 866 | }); |
| 841 | }, | 867 | }, |
| 842 | .Array, .Vector => { | 868 | .Array, .Vector => { |
| 843 | if (location != .Initializer) { | 869 | if (!location.isInitializer()) { |
| 844 | try writer.writeByte('('); | 870 | try writer.writeByte('('); |
| 845 | try dg.renderTypecast(writer, ty); | 871 | try dg.renderTypecast(writer, ty); |
| 846 | try writer.writeByte(')'); | 872 | try writer.writeByte(')'); |
| ... | @@ -848,19 +874,20 @@ pub const DeclGen = struct { | ... | @@ -848,19 +874,20 @@ pub const DeclGen = struct { |
| 848 | | 874 | |
| 849 | const ai = ty.arrayInfo(); | 875 | const ai = ty.arrayInfo(); |
| 850 | if (ai.elem_type.eql(Type.u8, dg.module)) { | 876 | if (ai.elem_type.eql(Type.u8, dg.module)) { |
| 851 | try writer.writeByte('"'); | 877 | var literal = stringLiteral(writer); |
| | 878 | try literal.start(); |
| 852 | const c_len = ty.arrayLenIncludingSentinel(); | 879 | const c_len = ty.arrayLenIncludingSentinel(); |
| 853 | var index: usize = 0; | 880 | var index: usize = 0; |
| 854 | while (index < c_len) : (index += 1) | 881 | while (index < c_len) : (index += 1) |
| 855 | try writeStringLiteralChar(writer, 0xaa); | 882 | try literal.writeChar(0xaa); |
| 856 | return writer.writeByte('"'); | 883 | return literal.end(); |
| 857 | } else { | 884 | } else { |
| 858 | try writer.writeByte('{'); | 885 | try writer.writeByte('{'); |
| 859 | const c_len = ty.arrayLenIncludingSentinel(); | 886 | const c_len = ty.arrayLenIncludingSentinel(); |
| 860 | var index: usize = 0; | 887 | var index: usize = 0; |
| 861 | while (index < c_len) : (index += 1) { | 888 | while (index < c_len) : (index += 1) { |
| 862 | if (index > 0) try writer.writeAll(", "); | 889 | if (index > 0) try writer.writeAll(", "); |
| 863 | try dg.renderValue(writer, ty.childType(), val, .Initializer); | 890 | try dg.renderValue(writer, ty.childType(), val, initializer_type); |
| 864 | } | 891 | } |
| 865 | return writer.writeByte('}'); | 892 | return writer.writeByte('}'); |
| 866 | } | 893 | } |
| ... | @@ -893,8 +920,8 @@ pub const DeclGen = struct { | ... | @@ -893,8 +920,8 @@ pub const DeclGen = struct { |
| 893 | .eu_payload_ptr, | 920 | .eu_payload_ptr, |
| 894 | .decl_ref_mut, | 921 | .decl_ref_mut, |
| 895 | .decl_ref, | 922 | .decl_ref, |
| 896 | => try dg.renderParentPtr(writer, val, ty), | 923 | => try dg.renderParentPtr(writer, val, ty, location), |
| 897 | else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val)}), | 924 | else => try writer.print("{}", .{try dg.fmtIntLiteralLoc(ty, val, location)}), |
| 898 | }, | 925 | }, |
| 899 | .Float => { | 926 | .Float => { |
| 900 | const bits = ty.floatBits(target); | 927 | const bits = ty.floatBits(target); |
| ... | @@ -926,9 +953,10 @@ pub const DeclGen = struct { | ... | @@ -926,9 +953,10 @@ pub const DeclGen = struct { |
| 926 | }; | 953 | }; |
| 927 | const int_val = Value.initPayload(&int_val_pl.base); | 954 | const int_val = Value.initPayload(&int_val_pl.base); |
| 928 | | 955 | |
| 929 | try writer.writeByte('('); | 956 | try writer.writeAll("zig_cast_"); |
| 930 | try dg.renderTypecast(writer, ty); | 957 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 931 | try writer.writeByte(')'); | 958 | try writer.writeByte(' '); |
| | 959 | var empty = true; |
| 932 | if (std.math.isFinite(f128_val)) { | 960 | if (std.math.isFinite(f128_val)) { |
| 933 | try writer.writeAll("zig_as_"); | 961 | try writer.writeAll("zig_as_"); |
| 934 | try dg.renderTypeForBuiltinFnName(writer, ty); | 962 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| ... | @@ -941,17 +969,32 @@ pub const DeclGen = struct { | ... | @@ -941,17 +969,32 @@ pub const DeclGen = struct { |
| 941 | 128 => try writer.print("{x}", .{f128_val}), | 969 | 128 => try writer.print("{x}", .{f128_val}), |
| 942 | else => unreachable, | 970 | else => unreachable, |
| 943 | } | 971 | } |
| | 972 | try writer.writeAll(", "); |
| | 973 | empty = false; |
| 944 | } else { | 974 | } else { |
| 945 | const operation = if (std.math.isSignalNan(f128_val)) | 975 | // isSignalNan is equivalent to isNan currently, and MSVC doens't have nans, so prefer nan |
| 946 | "nans" | 976 | const operation = if (std.math.isNan(f128_val)) |
| 947 | else if (std.math.isNan(f128_val)) | | |
| 948 | "nan" | 977 | "nan" |
| | 978 | else if (std.math.isSignalNan(f128_val)) |
| | 979 | "nans" |
| 949 | else if (std.math.isInf(f128_val)) | 980 | else if (std.math.isInf(f128_val)) |
| 950 | "inf" | 981 | "inf" |
| 951 | else | 982 | else |
| 952 | unreachable; | 983 | unreachable; |
| 953 | | 984 | |
| | 985 | if (location == .StaticInitializer) { |
| | 986 | if (!std.math.isNan(f128_val) and std.math.isSignalNan(f128_val)) |
| | 987 | return dg.fail("TODO: C backend: implement nans rendering in static initializers", .{}); |
| | 988 | |
| | 989 | // MSVC doesn't have a way to define a custom or signaling NaN value in a constant expression |
| | 990 | |
| | 991 | // TODO: Re-enable this check, otherwise we're writing qnan bit patterns on msvc incorrectly |
| | 992 | // if (std.math.isNan(f128_val) and f128_val != std.math.qnan_f128) |
| | 993 | // return dg.fail("Only quiet nans are supported in global variable initializers", .{}); |
| | 994 | } |
| | 995 | |
| 954 | try writer.writeAll("zig_as_special_"); | 996 | try writer.writeAll("zig_as_special_"); |
| | 997 | if (location == .StaticInitializer) try writer.writeAll("constant_"); |
| 955 | try dg.renderTypeForBuiltinFnName(writer, ty); | 998 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 956 | try writer.writeByte('('); | 999 | try writer.writeByte('('); |
| 957 | if (std.math.signbit(f128_val)) try writer.writeByte('-'); | 1000 | if (std.math.signbit(f128_val)) try writer.writeByte('-'); |
| ... | @@ -968,8 +1011,12 @@ pub const DeclGen = struct { | ... | @@ -968,8 +1011,12 @@ pub const DeclGen = struct { |
| 968 | 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}), | 1011 | 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}), |
| 969 | else => unreachable, | 1012 | else => unreachable, |
| 970 | }; | 1013 | }; |
| | 1014 | try writer.writeAll(", "); |
| | 1015 | empty = false; |
| 971 | } | 1016 | } |
| 972 | return writer.print(", {x})", .{try dg.fmtIntLiteral(int_ty, int_val)}); | 1017 | try writer.print("{x}", .{try dg.fmtIntLiteralLoc(int_ty, int_val, location)}); |
| | 1018 | if (!empty) try writer.writeByte(')'); |
| | 1019 | return; |
| 973 | }, | 1020 | }, |
| 974 | .Pointer => switch (val.tag()) { | 1021 | .Pointer => switch (val.tag()) { |
| 975 | .null_value, .zero => if (ty.isSlice()) { | 1022 | .null_value, .zero => if (ty.isSlice()) { |
| ... | @@ -987,10 +1034,10 @@ pub const DeclGen = struct { | ... | @@ -987,10 +1034,10 @@ pub const DeclGen = struct { |
| 987 | }, | 1034 | }, |
| 988 | .variable => { | 1035 | .variable => { |
| 989 | const decl = val.castTag(.variable).?.data.owner_decl; | 1036 | const decl = val.castTag(.variable).?.data.owner_decl; |
| 990 | return dg.renderDeclValue(writer, ty, val, decl); | 1037 | return dg.renderDeclValue(writer, ty, val, decl, location); |
| 991 | }, | 1038 | }, |
| 992 | .slice => { | 1039 | .slice => { |
| 993 | if (location != .Initializer) { | 1040 | if (!location.isInitializer()) { |
| 994 | try writer.writeByte('('); | 1041 | try writer.writeByte('('); |
| 995 | try dg.renderTypecast(writer, ty); | 1042 | try dg.renderTypecast(writer, ty); |
| 996 | try writer.writeByte(')'); | 1043 | try writer.writeByte(')'); |
| ... | @@ -1000,9 +1047,9 @@ pub const DeclGen = struct { | ... | @@ -1000,9 +1047,9 @@ pub const DeclGen = struct { |
| 1000 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1047 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1001 | | 1048 | |
| 1002 | try writer.writeByte('{'); | 1049 | try writer.writeByte('{'); |
| 1003 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, .Initializer); | 1050 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, initializer_type); |
| 1004 | try writer.writeAll(", "); | 1051 | try writer.writeAll(", "); |
| 1005 | try dg.renderValue(writer, Type.usize, slice.len, .Initializer); | 1052 | try dg.renderValue(writer, Type.usize, slice.len, initializer_type); |
| 1006 | try writer.writeByte('}'); | 1053 | try writer.writeByte('}'); |
| 1007 | }, | 1054 | }, |
| 1008 | .function => { | 1055 | .function => { |
| ... | @@ -1024,7 +1071,7 @@ pub const DeclGen = struct { | ... | @@ -1024,7 +1071,7 @@ pub const DeclGen = struct { |
| 1024 | .eu_payload_ptr, | 1071 | .eu_payload_ptr, |
| 1025 | .decl_ref_mut, | 1072 | .decl_ref_mut, |
| 1026 | .decl_ref, | 1073 | .decl_ref, |
| 1027 | => try dg.renderParentPtr(writer, val, ty), | 1074 | => try dg.renderParentPtr(writer, val, ty, location), |
| 1028 | else => unreachable, | 1075 | else => unreachable, |
| 1029 | }, | 1076 | }, |
| 1030 | .Array, .Vector => { | 1077 | .Array, .Vector => { |
| ... | @@ -1040,7 +1087,7 @@ pub const DeclGen = struct { | ... | @@ -1040,7 +1087,7 @@ pub const DeclGen = struct { |
| 1040 | try writer.writeByte('{'); | 1087 | try writer.writeByte('{'); |
| 1041 | const ai = ty.arrayInfo(); | 1088 | const ai = ty.arrayInfo(); |
| 1042 | if (ai.sentinel) |s| { | 1089 | if (ai.sentinel) |s| { |
| 1043 | try dg.renderValue(writer, ai.elem_type, s, .Initializer); | 1090 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); |
| 1044 | } else { | 1091 | } else { |
| 1045 | try writer.writeByte('0'); | 1092 | try writer.writeByte('0'); |
| 1046 | } | 1093 | } |
| ... | @@ -1060,34 +1107,51 @@ pub const DeclGen = struct { | ... | @@ -1060,34 +1107,51 @@ pub const DeclGen = struct { |
| 1060 | defer arena.deinit(); | 1107 | defer arena.deinit(); |
| 1061 | const arena_allocator = arena.allocator(); | 1108 | const arena_allocator = arena.allocator(); |
| 1062 | | 1109 | |
| | 1110 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal |
| | 1111 | const max_string_initializer_len = 65535; |
| | 1112 | |
| 1063 | const ai = ty.arrayInfo(); | 1113 | const ai = ty.arrayInfo(); |
| 1064 | if (ai.elem_type.eql(Type.u8, dg.module)) { | 1114 | if (ai.elem_type.eql(Type.u8, dg.module)) { |
| 1065 | try writer.writeByte('"'); | 1115 | if (ai.len <= max_string_initializer_len) { |
| 1066 | var index: usize = 0; | 1116 | var literal = stringLiteral(writer); |
| 1067 | while (index < ai.len) : (index += 1) { | 1117 | try literal.start(); |
| 1068 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | 1118 | var index: usize = 0; |
| 1069 | const elem_val_u8 = if (elem_val.isUndef()) | 1119 | while (index < ai.len) : (index += 1) { |
| 1070 | undefPattern(u8) | 1120 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); |
| 1071 | else | 1121 | const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(target)); |
| 1072 | @intCast(u8, elem_val.toUnsignedInt(target)); | 1122 | try literal.writeChar(elem_val_u8); |
| 1073 | try writeStringLiteralChar(writer, elem_val_u8); | 1123 | } |
| 1074 | } | 1124 | if (ai.sentinel) |s| { |
| 1075 | if (ai.sentinel) |s| { | 1125 | const s_u8 = @intCast(u8, s.toUnsignedInt(target)); |
| 1076 | const s_u8 = @intCast(u8, s.toUnsignedInt(target)); | 1126 | try literal.writeChar(s_u8); |
| 1077 | try writeStringLiteralChar(writer, s_u8); | 1127 | } |
| | 1128 | try literal.end(); |
| | 1129 | } else { |
| | 1130 | try writer.writeByte('{'); |
| | 1131 | var index: usize = 0; |
| | 1132 | while (index < ai.len) : (index += 1) { |
| | 1133 | if (index != 0) try writer.writeByte(','); |
| | 1134 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); |
| | 1135 | const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(target)); |
| | 1136 | try writer.print("'\\x{x}'", .{elem_val_u8}); |
| | 1137 | } |
| | 1138 | if (ai.sentinel) |s| { |
| | 1139 | if (index != 0) try writer.writeByte(','); |
| | 1140 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); |
| | 1141 | } |
| | 1142 | try writer.writeByte('}'); |
| 1078 | } | 1143 | } |
| 1079 | try writer.writeByte('"'); | | |
| 1080 | } else { | 1144 | } else { |
| 1081 | try writer.writeByte('{'); | 1145 | try writer.writeByte('{'); |
| 1082 | var index: usize = 0; | 1146 | var index: usize = 0; |
| 1083 | while (index < ai.len) : (index += 1) { | 1147 | while (index < ai.len) : (index += 1) { |
| 1084 | if (index != 0) try writer.writeByte(','); | 1148 | if (index != 0) try writer.writeByte(','); |
| 1085 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | 1149 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); |
| 1086 | try dg.renderValue(writer, ai.elem_type, elem_val, .Initializer); | 1150 | try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type); |
| 1087 | } | 1151 | } |
| 1088 | if (ai.sentinel) |s| { | 1152 | if (ai.sentinel) |s| { |
| 1089 | if (index != 0) try writer.writeByte(','); | 1153 | if (index != 0) try writer.writeByte(','); |
| 1090 | try dg.renderValue(writer, ai.elem_type, s, .Initializer); | 1154 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); |
| 1091 | } | 1155 | } |
| 1092 | try writer.writeByte('}'); | 1156 | try writer.writeByte('}'); |
| 1093 | } | 1157 | } |
| ... | @@ -1114,7 +1178,7 @@ pub const DeclGen = struct { | ... | @@ -1114,7 +1178,7 @@ pub const DeclGen = struct { |
| 1114 | return dg.renderValue(writer, payload_ty, payload_val, location); | 1178 | return dg.renderValue(writer, payload_ty, payload_val, location); |
| 1115 | } | 1179 | } |
| 1116 | | 1180 | |
| 1117 | if (location != .Initializer) { | 1181 | if (!location.isInitializer()) { |
| 1118 | try writer.writeByte('('); | 1182 | try writer.writeByte('('); |
| 1119 | try dg.renderTypecast(writer, ty); | 1183 | try dg.renderTypecast(writer, ty); |
| 1120 | try writer.writeByte(')'); | 1184 | try writer.writeByte(')'); |
| ... | @@ -1123,9 +1187,9 @@ pub const DeclGen = struct { | ... | @@ -1123,9 +1187,9 @@ pub const DeclGen = struct { |
| 1123 | const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else Value.undef; | 1187 | const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else Value.undef; |
| 1124 | | 1188 | |
| 1125 | try writer.writeAll("{ .payload = "); | 1189 | try writer.writeAll("{ .payload = "); |
| 1126 | try dg.renderValue(writer, payload_ty, payload_val, .Initializer); | 1190 | try dg.renderValue(writer, payload_ty, payload_val, initializer_type); |
| 1127 | try writer.writeAll(", .is_null = "); | 1191 | try writer.writeAll(", .is_null = "); |
| 1128 | try dg.renderValue(writer, Type.bool, is_null_val, .Initializer); | 1192 | try dg.renderValue(writer, Type.bool, is_null_val, initializer_type); |
| 1129 | try writer.writeAll(" }"); | 1193 | try writer.writeAll(" }"); |
| 1130 | }, | 1194 | }, |
| 1131 | .ErrorSet => { | 1195 | .ErrorSet => { |
| ... | @@ -1148,7 +1212,7 @@ pub const DeclGen = struct { | ... | @@ -1148,7 +1212,7 @@ pub const DeclGen = struct { |
| 1148 | return dg.renderValue(writer, error_ty, val, location); | 1212 | return dg.renderValue(writer, error_ty, val, location); |
| 1149 | } | 1213 | } |
| 1150 | | 1214 | |
| 1151 | if (location != .Initializer) { | 1215 | if (!location.isInitializer()) { |
| 1152 | try writer.writeByte('('); | 1216 | try writer.writeByte('('); |
| 1153 | try dg.renderTypecast(writer, ty); | 1217 | try dg.renderTypecast(writer, ty); |
| 1154 | try writer.writeByte(')'); | 1218 | try writer.writeByte(')'); |
| ... | @@ -1158,9 +1222,9 @@ pub const DeclGen = struct { | ... | @@ -1158,9 +1222,9 @@ pub const DeclGen = struct { |
| 1158 | const error_val = if (val.errorUnionIsPayload()) Value.zero else val; | 1222 | const error_val = if (val.errorUnionIsPayload()) Value.zero else val; |
| 1159 | | 1223 | |
| 1160 | try writer.writeAll("{ .payload = "); | 1224 | try writer.writeAll("{ .payload = "); |
| 1161 | try dg.renderValue(writer, payload_ty, payload_val, .Initializer); | 1225 | try dg.renderValue(writer, payload_ty, payload_val, initializer_type); |
| 1162 | try writer.writeAll(", .error = "); | 1226 | try writer.writeAll(", .error = "); |
| 1163 | try dg.renderValue(writer, error_ty, error_val, .Initializer); | 1227 | try dg.renderValue(writer, error_ty, error_val, initializer_type); |
| 1164 | try writer.writeAll(" }"); | 1228 | try writer.writeAll(" }"); |
| 1165 | }, | 1229 | }, |
| 1166 | .Enum => { | 1230 | .Enum => { |
| ... | @@ -1200,11 +1264,11 @@ pub const DeclGen = struct { | ... | @@ -1200,11 +1264,11 @@ pub const DeclGen = struct { |
| 1200 | .Fn => switch (val.tag()) { | 1264 | .Fn => switch (val.tag()) { |
| 1201 | .function => { | 1265 | .function => { |
| 1202 | const decl = val.castTag(.function).?.data.owner_decl; | 1266 | const decl = val.castTag(.function).?.data.owner_decl; |
| 1203 | return dg.renderDeclValue(writer, ty, val, decl); | 1267 | return dg.renderDeclValue(writer, ty, val, decl, location); |
| 1204 | }, | 1268 | }, |
| 1205 | .extern_fn => { | 1269 | .extern_fn => { |
| 1206 | const decl = val.castTag(.extern_fn).?.data.owner_decl; | 1270 | const decl = val.castTag(.extern_fn).?.data.owner_decl; |
| 1207 | return dg.renderDeclValue(writer, ty, val, decl); | 1271 | return dg.renderDeclValue(writer, ty, val, decl, location); |
| 1208 | }, | 1272 | }, |
| 1209 | else => unreachable, | 1273 | else => unreachable, |
| 1210 | }, | 1274 | }, |
| ... | @@ -1212,7 +1276,7 @@ pub const DeclGen = struct { | ... | @@ -1212,7 +1276,7 @@ pub const DeclGen = struct { |
| 1212 | .Auto, .Extern => { | 1276 | .Auto, .Extern => { |
| 1213 | const field_vals = val.castTag(.aggregate).?.data; | 1277 | const field_vals = val.castTag(.aggregate).?.data; |
| 1214 | | 1278 | |
| 1215 | if (location != .Initializer) { | 1279 | if (!location.isInitializer()) { |
| 1216 | try writer.writeByte('('); | 1280 | try writer.writeByte('('); |
| 1217 | try dg.renderTypecast(writer, ty); | 1281 | try dg.renderTypecast(writer, ty); |
| 1218 | try writer.writeByte(')'); | 1282 | try writer.writeByte(')'); |
| ... | @@ -1225,7 +1289,7 @@ pub const DeclGen = struct { | ... | @@ -1225,7 +1289,7 @@ pub const DeclGen = struct { |
| 1225 | if (!field_ty.hasRuntimeBits()) continue; | 1289 | if (!field_ty.hasRuntimeBits()) continue; |
| 1226 | | 1290 | |
| 1227 | if (!empty) try writer.writeByte(','); | 1291 | if (!empty) try writer.writeByte(','); |
| 1228 | try dg.renderValue(writer, field_ty, field_val, .Initializer); | 1292 | try dg.renderValue(writer, field_ty, field_val, initializer_type); |
| 1229 | | 1293 | |
| 1230 | empty = false; | 1294 | empty = false; |
| 1231 | } | 1295 | } |
| ... | @@ -1245,31 +1309,85 @@ pub const DeclGen = struct { | ... | @@ -1245,31 +1309,85 @@ pub const DeclGen = struct { |
| 1245 | var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; | 1309 | var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; |
| 1246 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); | 1310 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); |
| 1247 | | 1311 | |
| 1248 | try writer.writeByte('('); | 1312 | var eff_num_fields: usize = 0; |
| 1249 | var empty = true; | 1313 | for (field_vals) |_, index| { |
| 1250 | for (field_vals) |field_val, index| { | | |
| 1251 | const field_ty = ty.structFieldType(index); | 1314 | const field_ty = ty.structFieldType(index); |
| 1252 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 1315 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1253 | | 1316 | |
| 1254 | if (!empty) try writer.writeAll(" | "); | 1317 | eff_num_fields += 1; |
| | 1318 | } |
| | 1319 | |
| | 1320 | if (eff_num_fields == 0) { |
| 1255 | try writer.writeByte('('); | 1321 | try writer.writeByte('('); |
| 1256 | try dg.renderTypecast(writer, ty); | 1322 | try dg.renderValue(writer, ty, Value.undef, initializer_type); |
| 1257 | try writer.writeByte(')'); | 1323 | try writer.writeByte(')'); |
| 1258 | try dg.renderValue(writer, field_ty, field_val, .Other); | 1324 | } else if (ty.bitSize(target) > 64) { |
| 1259 | try writer.writeAll(" << "); | 1325 | // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) |
| 1260 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | 1326 | var num_or = eff_num_fields - 1; |
| | 1327 | while (num_or > 0) : (num_or -= 1) { |
| | 1328 | try writer.writeAll("zig_or_"); |
| | 1329 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| | 1330 | try writer.writeByte('('); |
| | 1331 | } |
| 1261 | | 1332 | |
| 1262 | bit_offset_val_pl.data += field_ty.bitSize(target); | 1333 | var eff_index: usize = 0; |
| 1263 | empty = false; | 1334 | var needs_closing_paren = false; |
| | 1335 | for (field_vals) |field_val, index| { |
| | 1336 | const field_ty = ty.structFieldType(index); |
| | 1337 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| | 1338 | |
| | 1339 | const cast_context = IntCastContext{ .value = .{ .value = field_val } }; |
| | 1340 | if (bit_offset_val_pl.data != 0) { |
| | 1341 | try writer.writeAll("zig_shl_"); |
| | 1342 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| | 1343 | try writer.writeByte('('); |
| | 1344 | try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); |
| | 1345 | try writer.writeAll(", "); |
| | 1346 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| | 1347 | try writer.writeByte(')'); |
| | 1348 | } else { |
| | 1349 | try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); |
| | 1350 | } |
| | 1351 | |
| | 1352 | if (needs_closing_paren) try writer.writeByte(')'); |
| | 1353 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); |
| | 1354 | |
| | 1355 | bit_offset_val_pl.data += field_ty.bitSize(target); |
| | 1356 | needs_closing_paren = true; |
| | 1357 | eff_index += 1; |
| | 1358 | } |
| | 1359 | } else { |
| | 1360 | try writer.writeByte('('); |
| | 1361 | // a << a_off | b << b_off | c << c_off |
| | 1362 | var empty = true; |
| | 1363 | for (field_vals) |field_val, index| { |
| | 1364 | const field_ty = ty.structFieldType(index); |
| | 1365 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| | 1366 | |
| | 1367 | if (!empty) try writer.writeAll(" | "); |
| | 1368 | try writer.writeByte('('); |
| | 1369 | try dg.renderTypecast(writer, ty); |
| | 1370 | try writer.writeByte(')'); |
| | 1371 | |
| | 1372 | if (bit_offset_val_pl.data != 0) { |
| | 1373 | try dg.renderValue(writer, field_ty, field_val, .Other); |
| | 1374 | try writer.writeAll(" << "); |
| | 1375 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| | 1376 | } else { |
| | 1377 | try dg.renderValue(writer, field_ty, field_val, .Other); |
| | 1378 | } |
| | 1379 | |
| | 1380 | bit_offset_val_pl.data += field_ty.bitSize(target); |
| | 1381 | empty = false; |
| | 1382 | } |
| | 1383 | try writer.writeByte(')'); |
| 1264 | } | 1384 | } |
| 1265 | if (empty) try dg.renderValue(writer, ty, Value.undef, .Initializer); | | |
| 1266 | try writer.writeByte(')'); | | |
| 1267 | }, | 1385 | }, |
| 1268 | }, | 1386 | }, |
| 1269 | .Union => { | 1387 | .Union => { |
| 1270 | const union_obj = val.castTag(.@"union").?.data; | 1388 | const union_obj = val.castTag(.@"union").?.data; |
| 1271 | | 1389 | |
| 1272 | if (location != .Initializer) { | 1390 | if (!location.isInitializer()) { |
| 1273 | try writer.writeByte('('); | 1391 | try writer.writeByte('('); |
| 1274 | try dg.renderTypecast(writer, ty); | 1392 | try dg.renderTypecast(writer, ty); |
| 1275 | try writer.writeByte(')'); | 1393 | try writer.writeByte(')'); |
| ... | @@ -1289,7 +1407,7 @@ pub const DeclGen = struct { | ... | @@ -1289,7 +1407,7 @@ pub const DeclGen = struct { |
| 1289 | try dg.renderTypecast(writer, ty); | 1407 | try dg.renderTypecast(writer, ty); |
| 1290 | try writer.writeByte(')'); | 1408 | try writer.writeByte(')'); |
| 1291 | } | 1409 | } |
| 1292 | try dg.renderValue(writer, field_ty, union_obj.val, .Initializer); | 1410 | try dg.renderValue(writer, field_ty, union_obj.val, initializer_type); |
| 1293 | } else { | 1411 | } else { |
| 1294 | try writer.writeAll("0"); | 1412 | try writer.writeAll("0"); |
| 1295 | } | 1413 | } |
| ... | @@ -1301,7 +1419,7 @@ pub const DeclGen = struct { | ... | @@ -1301,7 +1419,7 @@ pub const DeclGen = struct { |
| 1301 | const layout = ty.unionGetLayout(target); | 1419 | const layout = ty.unionGetLayout(target); |
| 1302 | if (layout.tag_size != 0) { | 1420 | if (layout.tag_size != 0) { |
| 1303 | try writer.writeAll(".tag = "); | 1421 | try writer.writeAll(".tag = "); |
| 1304 | try dg.renderValue(writer, tag_ty, union_obj.tag, .Initializer); | 1422 | try dg.renderValue(writer, tag_ty, union_obj.tag, initializer_type); |
| 1305 | try writer.writeAll(", "); | 1423 | try writer.writeAll(", "); |
| 1306 | } | 1424 | } |
| 1307 | try writer.writeAll(".payload = {"); | 1425 | try writer.writeAll(".payload = {"); |
| ... | @@ -1310,11 +1428,11 @@ pub const DeclGen = struct { | ... | @@ -1310,11 +1428,11 @@ pub const DeclGen = struct { |
| 1310 | var it = ty.unionFields().iterator(); | 1428 | var it = ty.unionFields().iterator(); |
| 1311 | if (field_ty.hasRuntimeBits()) { | 1429 | if (field_ty.hasRuntimeBits()) { |
| 1312 | try writer.print(".{ } = ", .{fmtIdent(field_name)}); | 1430 | try writer.print(".{ } = ", .{fmtIdent(field_name)}); |
| 1313 | try dg.renderValue(writer, field_ty, union_obj.val, .Initializer); | 1431 | try dg.renderValue(writer, field_ty, union_obj.val, initializer_type); |
| 1314 | } else while (it.next()) |field| { | 1432 | } else while (it.next()) |field| { |
| 1315 | if (!field.value_ptr.ty.hasRuntimeBits()) continue; | 1433 | if (!field.value_ptr.ty.hasRuntimeBits()) continue; |
| 1316 | try writer.print(".{ } = ", .{fmtIdent(field.key_ptr.*)}); | 1434 | try writer.print(".{ } = ", .{fmtIdent(field.key_ptr.*)}); |
| 1317 | try dg.renderValue(writer, field.value_ptr.ty, Value.undef, .Initializer); | 1435 | try dg.renderValue(writer, field.value_ptr.ty, Value.undef, initializer_type); |
| 1318 | break; | 1436 | break; |
| 1319 | } else try writer.writeAll(".empty_union = 0"); | 1437 | } else try writer.writeAll(".empty_union = 0"); |
| 1320 | if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); | 1438 | if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); |
| ... | @@ -2085,6 +2203,103 @@ pub const DeclGen = struct { | ... | @@ -2085,6 +2203,103 @@ pub const DeclGen = struct { |
| 2085 | }); | 2203 | }); |
| 2086 | } | 2204 | } |
| 2087 | | 2205 | |
| | 2206 | const IntCastContext = union(enum) { |
| | 2207 | c_value: struct { |
| | 2208 | f: *Function, |
| | 2209 | value: CValue, |
| | 2210 | }, |
| | 2211 | value: struct { |
| | 2212 | value: Value, |
| | 2213 | }, |
| | 2214 | |
| | 2215 | pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: anytype, value_ty: Type, location: ValueRenderLocation) !void { |
| | 2216 | switch (self.*) { |
| | 2217 | .c_value => |v| { |
| | 2218 | try v.f.writeCValue(w, v.value, location); |
| | 2219 | }, |
| | 2220 | .value => |v| { |
| | 2221 | try dg.renderValue(w, value_ty, v.value, location); |
| | 2222 | }, |
| | 2223 | } |
| | 2224 | } |
| | 2225 | }; |
| | 2226 | |
| | 2227 | /// Renders a cast to an int type, from either an int or a pointer. |
| | 2228 | /// |
| | 2229 | /// Some platforms don't have 128 bit integers, so we need to use |
| | 2230 | /// the zig_as_ and zig_lo_ macros in those cases. |
| | 2231 | /// |
| | 2232 | /// | Dest type bits | Src type | Result |
| | 2233 | /// |------------------|------------------|---------------------------| |
| | 2234 | /// | < 64 bit integer | pointer | (zig_<dest_ty>)(zig_<u|i>size)src |
| | 2235 | /// | < 64 bit integer | < 64 bit integer | (zig_<dest_ty>)src |
| | 2236 | /// | < 64 bit integer | > 64 bit integer | zig_lo(src) |
| | 2237 | /// | > 64 bit integer | pointer | zig_as_<dest_ty>(0, (zig_<u|i>size)src) |
| | 2238 | /// | > 64 bit integer | < 64 bit integer | zig_as_<dest_ty>(0, src) |
| | 2239 | /// | > 64 bit integer | > 64 bit integer | zig_as_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src)) |
| | 2240 | fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void { |
| | 2241 | const target = dg.module.getTarget(); |
| | 2242 | const dest_bits = dest_ty.bitSize(target); |
| | 2243 | const dest_int_info = dest_ty.intInfo(target); |
| | 2244 | |
| | 2245 | const src_is_ptr = src_ty.isPtrAtRuntime(); |
| | 2246 | const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) { |
| | 2247 | .unsigned => Type.usize, |
| | 2248 | .signed => Type.isize, |
| | 2249 | } else src_ty; |
| | 2250 | |
| | 2251 | const src_bits = src_eff_ty.bitSize(target); |
| | 2252 | const src_int_info = if (src_eff_ty.isAbiInt()) src_eff_ty.intInfo(target) else null; |
| | 2253 | if (dest_bits <= 64 and src_bits <= 64) { |
| | 2254 | const needs_cast = src_int_info == null or |
| | 2255 | (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or |
| | 2256 | dest_int_info.signedness != src_int_info.?.signedness); |
| | 2257 | |
| | 2258 | if (needs_cast) { |
| | 2259 | try w.writeByte('('); |
| | 2260 | try dg.renderTypecast(w, dest_ty); |
| | 2261 | try w.writeByte(')'); |
| | 2262 | } |
| | 2263 | if (src_is_ptr) { |
| | 2264 | try w.writeByte('('); |
| | 2265 | try dg.renderTypecast(w, src_eff_ty); |
| | 2266 | try w.writeByte(')'); |
| | 2267 | } |
| | 2268 | try context.writeValue(dg, w, src_ty, location); |
| | 2269 | } else if (dest_bits <= 64 and src_bits > 64) { |
| | 2270 | assert(!src_is_ptr); |
| | 2271 | try w.writeAll("zig_lo_"); |
| | 2272 | try dg.renderTypeForBuiltinFnName(w, src_eff_ty); |
| | 2273 | try w.writeByte('('); |
| | 2274 | try context.writeValue(dg, w, src_ty, .FunctionArgument); |
| | 2275 | try w.writeByte(')'); |
| | 2276 | } else if (dest_bits > 64 and src_bits <= 64) { |
| | 2277 | try w.writeAll("zig_as_"); |
| | 2278 | try dg.renderTypeForBuiltinFnName(w, dest_ty); |
| | 2279 | try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral? |
| | 2280 | if (src_is_ptr) { |
| | 2281 | try w.writeByte('('); |
| | 2282 | try dg.renderTypecast(w, src_eff_ty); |
| | 2283 | try w.writeByte(')'); |
| | 2284 | } |
| | 2285 | try context.writeValue(dg, w, src_ty, .FunctionArgument); |
| | 2286 | try w.writeByte(')'); |
| | 2287 | } else { |
| | 2288 | assert(!src_is_ptr); |
| | 2289 | try w.writeAll("zig_as_"); |
| | 2290 | try dg.renderTypeForBuiltinFnName(w, dest_ty); |
| | 2291 | try w.writeAll("(zig_hi_"); |
| | 2292 | try dg.renderTypeForBuiltinFnName(w, src_eff_ty); |
| | 2293 | try w.writeByte('('); |
| | 2294 | try context.writeValue(dg, w, src_ty, .FunctionArgument); |
| | 2295 | try w.writeAll("), zig_lo_"); |
| | 2296 | try dg.renderTypeForBuiltinFnName(w, src_eff_ty); |
| | 2297 | try w.writeByte('('); |
| | 2298 | try context.writeValue(dg, w, src_ty, .FunctionArgument); |
| | 2299 | try w.writeAll("))"); |
| | 2300 | } |
| | 2301 | } |
| | 2302 | |
| 2088 | /// Renders a type in C typecast format. | 2303 | /// Renders a type in C typecast format. |
| 2089 | /// | 2304 | /// |
| 2090 | /// This is guaranteed to be valid in a typecast expression, but not | 2305 | /// This is guaranteed to be valid in a typecast expression, but not |
| ... | @@ -2134,7 +2349,7 @@ pub const DeclGen = struct { | ... | @@ -2134,7 +2349,7 @@ pub const DeclGen = struct { |
| 2134 | const c_len_val = Value.initPayload(&c_len_pl.base); | 2349 | const c_len_val = Value.initPayload(&c_len_pl.base); |
| 2135 | | 2350 | |
| 2136 | try suffix_writer.writeByte('['); | 2351 | try suffix_writer.writeByte('['); |
| 2137 | if (mutability == .ConstArgument and depth == 0) try suffix_writer.writeAll("static const "); | 2352 | if (mutability == .ConstArgument and depth == 0) try suffix_writer.writeAll("zig_const_arr "); |
| 2138 | try suffix.writer().print("{}]", .{try dg.fmtIntLiteral(Type.usize, c_len_val)}); | 2353 | try suffix.writer().print("{}]", .{try dg.fmtIntLiteral(Type.usize, c_len_val)}); |
| 2139 | render_ty = array_info.elem_type; | 2354 | render_ty = array_info.elem_type; |
| 2140 | depth += 1; | 2355 | depth += 1; |
| ... | @@ -2306,6 +2521,9 @@ pub const DeclGen = struct { | ... | @@ -2306,6 +2521,9 @@ pub const DeclGen = struct { |
| 2306 | try dg.writeCValue(writer, member); | 2521 | try dg.writeCValue(writer, member); |
| 2307 | } | 2522 | } |
| 2308 | | 2523 | |
| | 2524 | const IdentHasher = std.crypto.auth.siphash.SipHash128(1, 3); |
| | 2525 | const ident_hasher_init: IdentHasher = IdentHasher.init(&[_]u8{0} ** IdentHasher.key_length); |
| | 2526 | |
| 2309 | fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void { | 2527 | fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void { |
| 2310 | const decl = dg.module.declPtr(decl_index); | 2528 | const decl = dg.module.declPtr(decl_index); |
| 2311 | dg.module.markDeclAlive(decl); | 2529 | dg.module.markDeclAlive(decl); |
| ... | @@ -2323,7 +2541,18 @@ pub const DeclGen = struct { | ... | @@ -2323,7 +2541,18 @@ pub const DeclGen = struct { |
| 2323 | const gpa = dg.gpa; | 2541 | const gpa = dg.gpa; |
| 2324 | const name = try decl.getFullyQualifiedName(dg.module); | 2542 | const name = try decl.getFullyQualifiedName(dg.module); |
| 2325 | defer gpa.free(name); | 2543 | defer gpa.free(name); |
| 2326 | return writer.print("{}", .{fmtIdent(name)}); | 2544 | |
| | 2545 | // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), expand |
| | 2546 | // to 3x the length of its input |
| | 2547 | if (name.len > 1365) { |
| | 2548 | var hash = ident_hasher_init; |
| | 2549 | hash.update(name); |
| | 2550 | const ident_hash = hash.finalInt(); |
| | 2551 | try writer.writeAll("zig_D_"); |
| | 2552 | return std.fmt.formatIntValue(ident_hash, "x", .{}, writer); |
| | 2553 | } else { |
| | 2554 | return writer.print("{}", .{fmtIdent(name)}); |
| | 2555 | } |
| 2327 | } | 2556 | } |
| 2328 | } | 2557 | } |
| 2329 | | 2558 | |
| ... | @@ -2336,6 +2565,10 @@ pub const DeclGen = struct { | ... | @@ -2336,6 +2565,10 @@ pub const DeclGen = struct { |
| 2336 | try writer.print("{c}{d}", .{ signAbbrev(int_info.signedness), c_bits }); | 2565 | try writer.print("{c}{d}", .{ signAbbrev(int_info.signedness), c_bits }); |
| 2337 | } else if (ty.isRuntimeFloat()) { | 2566 | } else if (ty.isRuntimeFloat()) { |
| 2338 | try ty.print(writer, dg.module); | 2567 | try ty.print(writer, dg.module); |
| | 2568 | } else if (ty.isPtrAtRuntime()) { |
| | 2569 | try writer.print("p{d}", .{ty.bitSize(target)}); |
| | 2570 | } else if (ty.zigTypeTag() == .Bool) { |
| | 2571 | try writer.print("u8", .{}); |
| 2339 | } else return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{ | 2572 | } else return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{ |
| 2340 | ty.fmt(dg.module), | 2573 | ty.fmt(dg.module), |
| 2341 | }); | 2574 | }); |
| ... | @@ -2388,6 +2621,19 @@ pub const DeclGen = struct { | ... | @@ -2388,6 +2621,19 @@ pub const DeclGen = struct { |
| 2388 | .mod = dg.module, | 2621 | .mod = dg.module, |
| 2389 | } }; | 2622 | } }; |
| 2390 | } | 2623 | } |
| | 2624 | |
| | 2625 | fn fmtIntLiteralLoc( |
| | 2626 | dg: *DeclGen, |
| | 2627 | ty: Type, |
| | 2628 | val: Value, |
| | 2629 | location: ValueRenderLocation, // TODO: Instead add this as optional arg to fmtIntLiteral |
| | 2630 | ) !std.fmt.Formatter(formatIntLiteral) { |
| | 2631 | const int_info = ty.intInfo(dg.module.getTarget()); |
| | 2632 | const c_bits = toCIntBits(int_info.bits); |
| | 2633 | if (c_bits == null or c_bits.? > 128) |
| | 2634 | return dg.fail("TODO implement integer constants larger than 128 bits", .{}); |
| | 2635 | return std.fmt.Formatter(formatIntLiteral){ .data = .{ .ty = ty, .val = val, .mod = dg.module, .location = location } }; |
| | 2636 | } |
| 2391 | }; | 2637 | }; |
| 2392 | | 2638 | |
| 2393 | pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void { | 2639 | pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void { |
| ... | @@ -2433,7 +2679,7 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -2433,7 +2679,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2433 | try writer.writeAll("static "); | 2679 | try writer.writeAll("static "); |
| 2434 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete); | 2680 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete); |
| 2435 | try writer.writeAll(" = "); | 2681 | try writer.writeAll(" = "); |
| 2436 | try o.dg.renderValue(writer, name_ty, name_val, .Initializer); | 2682 | try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer); |
| 2437 | try writer.writeAll(";\n"); | 2683 | try writer.writeAll(";\n"); |
| 2438 | } | 2684 | } |
| 2439 | | 2685 | |
| ... | @@ -2604,7 +2850,7 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2604,7 +2850,7 @@ pub fn genDecl(o: *Object) !void { |
| 2604 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); | 2850 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); |
| 2605 | try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); | 2851 | try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2606 | try w.writeAll(" = "); | 2852 | try w.writeAll(" = "); |
| 2607 | try o.dg.renderValue(w, tv.ty, variable.init, .Initializer); | 2853 | try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer); |
| 2608 | try w.writeByte(';'); | 2854 | try w.writeByte(';'); |
| 2609 | try o.indent_writer.insertNewline(); | 2855 | try o.indent_writer.insertNewline(); |
| 2610 | } else { | 2856 | } else { |
| ... | @@ -2621,7 +2867,7 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2621,7 +2867,7 @@ pub fn genDecl(o: *Object) !void { |
| 2621 | // https://github.com/ziglang/zig/issues/7582 | 2867 | // https://github.com/ziglang/zig/issues/7582 |
| 2622 | try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); | 2868 | try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2623 | try writer.writeAll(" = "); | 2869 | try writer.writeAll(" = "); |
| 2624 | try o.dg.renderValue(writer, tv.ty, tv.val, .Initializer); | 2870 | try o.dg.renderValue(writer, tv.ty, tv.val, .StaticInitializer); |
| 2625 | try writer.writeAll(";\n"); | 2871 | try writer.writeAll(";\n"); |
| 2626 | } | 2872 | } |
| 2627 | } | 2873 | } |
| ... | @@ -3244,11 +3490,20 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3244,11 +3490,20 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3244 | try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty); | 3490 | try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty); |
| 3245 | try writer.writeAll("(("); | 3491 | try writer.writeAll("(("); |
| 3246 | try f.renderTypecast(writer, field_ty); | 3492 | try f.renderTypecast(writer, field_ty); |
| 3247 | try writer.writeAll(")zig_shr_"); | 3493 | try writer.writeByte(')'); |
| | 3494 | const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64; |
| | 3495 | if (cant_cast) { |
| | 3496 | if (field_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); |
| | 3497 | try writer.writeAll("zig_lo_"); |
| | 3498 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| | 3499 | try writer.writeByte('('); |
| | 3500 | } |
| | 3501 | try writer.writeAll("zig_shr_"); |
| 3248 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); | 3502 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3249 | try writer.writeByte('('); | 3503 | try writer.writeByte('('); |
| 3250 | try f.writeCValueDeref(writer, operand); | 3504 | try f.writeCValueDeref(writer, operand); |
| 3251 | try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); | 3505 | try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); |
| | 3506 | if (cant_cast) try writer.writeByte(')'); |
| 3252 | try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits); | 3507 | try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits); |
| 3253 | try writer.writeByte(')'); | 3508 | try writer.writeByte(')'); |
| 3254 | } else { | 3509 | } else { |
| ... | @@ -3322,11 +3577,11 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3322,11 +3577,11 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3322 | const writer = f.object.writer(); | 3577 | const writer = f.object.writer(); |
| 3323 | const inst_ty = f.air.typeOfIndex(inst); | 3578 | const inst_ty = f.air.typeOfIndex(inst); |
| 3324 | const local = try f.allocLocal(inst, inst_ty); | 3579 | const local = try f.allocLocal(inst, inst_ty); |
| | 3580 | const operand_ty = f.air.typeOf(ty_op.operand); |
| | 3581 | |
| 3325 | try f.writeCValue(writer, local, .Other); | 3582 | try f.writeCValue(writer, local, .Other); |
| 3326 | try writer.writeAll(" = ("); | 3583 | try writer.writeAll(" = "); |
| 3327 | try f.renderTypecast(writer, inst_ty); | 3584 | try f.renderIntCast(writer, inst_ty, operand, operand_ty, .Other); |
| 3328 | try writer.writeByte(')'); | | |
| 3329 | try f.writeCValue(writer, operand, .Other); | | |
| 3330 | try writer.writeAll(";\n"); | 3585 | try writer.writeAll(";\n"); |
| 3331 | return local; | 3586 | return local; |
| 3332 | } | 3587 | } |
| ... | @@ -3346,15 +3601,27 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3346,15 +3601,27 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3346 | const target = f.object.dg.module.getTarget(); | 3601 | const target = f.object.dg.module.getTarget(); |
| 3347 | const dest_int_info = inst_ty.intInfo(target); | 3602 | const dest_int_info = inst_ty.intInfo(target); |
| 3348 | const dest_bits = dest_int_info.bits; | 3603 | const dest_bits = dest_int_info.bits; |
| | 3604 | const dest_c_bits = toCIntBits(dest_int_info.bits) orelse |
| | 3605 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| | 3606 | const operand_ty = f.air.typeOf(ty_op.operand); |
| | 3607 | const operand_int_info = operand_ty.intInfo(target); |
| 3349 | | 3608 | |
| 3350 | try f.writeCValue(writer, local, .Other); | 3609 | try f.writeCValue(writer, local, .Other); |
| 3351 | try writer.writeAll(" = ("); | 3610 | try writer.writeAll(" = "); |
| 3352 | try f.renderTypecast(writer, inst_ty); | 3611 | |
| 3353 | try writer.writeByte(')'); | 3612 | const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64; |
| | 3613 | if (needs_lo) { |
| | 3614 | try writer.writeAll("zig_lo_"); |
| | 3615 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); |
| | 3616 | try writer.writeByte('('); |
| | 3617 | } else if (dest_c_bits <= 64) { |
| | 3618 | try writer.writeByte('('); |
| | 3619 | try f.renderTypecast(writer, inst_ty); |
| | 3620 | try writer.writeByte(')'); |
| | 3621 | } |
| 3354 | | 3622 | |
| 3355 | if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) { | 3623 | if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) { |
| 3356 | try f.writeCValue(writer, operand, .Other); | 3624 | try f.writeCValue(writer, operand, .Other); |
| 3357 | try writer.writeAll(";\n"); | | |
| 3358 | } else switch (dest_int_info.signedness) { | 3625 | } else switch (dest_int_info.signedness) { |
| 3359 | .unsigned => { | 3626 | .unsigned => { |
| 3360 | var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa); | 3627 | var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa); |
| ... | @@ -3365,14 +3632,14 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3365,14 +3632,14 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3365 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); | 3632 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); |
| 3366 | | 3633 | |
| 3367 | const mask_val = try inst_ty.maxInt(stack.get(), target); | 3634 | const mask_val = try inst_ty.maxInt(stack.get(), target); |
| 3368 | | 3635 | try writer.writeAll("zig_and_"); |
| | 3636 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); |
| 3369 | try writer.writeByte('('); | 3637 | try writer.writeByte('('); |
| 3370 | try f.writeCValue(writer, operand, .Other); | 3638 | try f.writeCValue(writer, operand, .FunctionArgument); |
| 3371 | try writer.print(" & {x});\n", .{try f.fmtIntLiteral(inst_ty, mask_val)}); | 3639 | try writer.print(", {x})", .{try f.fmtIntLiteral(operand_ty, mask_val)}); |
| 3372 | }, | 3640 | }, |
| 3373 | .signed => { | 3641 | .signed => { |
| 3374 | const operand_ty = f.air.typeOf(ty_op.operand); | 3642 | const c_bits = toCIntBits(operand_int_info.bits) orelse |
| 3375 | const c_bits = toCIntBits(operand_ty.intInfo(target).bits) orelse | | |
| 3376 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); | 3643 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| 3377 | var shift_pl = Value.Payload.U64{ | 3644 | var shift_pl = Value.Payload.U64{ |
| 3378 | .base = .{ .tag = .int_u64 }, | 3645 | .base = .{ .tag = .int_u64 }, |
| ... | @@ -3380,11 +3647,29 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3380,11 +3647,29 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3380 | }; | 3647 | }; |
| 3381 | const shift_val = Value.initPayload(&shift_pl.base); | 3648 | const shift_val = Value.initPayload(&shift_pl.base); |
| 3382 | | 3649 | |
| 3383 | try writer.print("((int{d}_t)((uint{0d}_t)", .{c_bits}); | 3650 | try writer.writeAll("zig_shr_"); |
| 3384 | try f.writeCValue(writer, operand, .Other); | 3651 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); |
| 3385 | try writer.print(" << {}) >> {0});\n", .{try f.fmtIntLiteral(Type.u8, shift_val)}); | 3652 | if (c_bits == 128) { |
| | 3653 | try writer.print("(zig_bitcast_i{d}(", .{c_bits}); |
| | 3654 | } else { |
| | 3655 | try writer.print("((int{d}_t)", .{c_bits}); |
| | 3656 | } |
| | 3657 | try writer.print("zig_shl_u{d}(", .{c_bits}); |
| | 3658 | if (c_bits == 128) { |
| | 3659 | try writer.print("zig_bitcast_u{d}(", .{c_bits}); |
| | 3660 | } else { |
| | 3661 | try writer.print("(uint{d}_t)", .{c_bits}); |
| | 3662 | } |
| | 3663 | try f.writeCValue(writer, operand, .FunctionArgument); |
| | 3664 | if (c_bits == 128) try writer.writeByte(')'); |
| | 3665 | try writer.print(", {})", .{try f.fmtIntLiteral(Type.u8, shift_val)}); |
| | 3666 | if (c_bits == 128) try writer.writeByte(')'); |
| | 3667 | try writer.print(", {})", .{try f.fmtIntLiteral(Type.u8, shift_val)}); |
| 3386 | }, | 3668 | }, |
| 3387 | } | 3669 | } |
| | 3670 | |
| | 3671 | if (needs_lo) try writer.writeByte(')'); |
| | 3672 | try writer.writeAll(";\n"); |
| 3388 | return local; | 3673 | return local; |
| 3389 | } | 3674 | } |
| 3390 | | 3675 | |
| ... | @@ -3521,15 +3806,26 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3521,15 +3806,26 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3521 | try f.writeCValueDeref(writer, ptr_val); | 3806 | try f.writeCValueDeref(writer, ptr_val); |
| 3522 | try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)}); | 3807 | try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)}); |
| 3523 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); | 3808 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3524 | try writer.writeAll("(("); | 3809 | try writer.writeByte('('); |
| 3525 | try f.renderTypecast(writer, host_ty); | 3810 | const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64; |
| 3526 | try writer.writeByte(')'); | 3811 | if (cant_cast) { |
| | 3812 | if (src_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); |
| | 3813 | try writer.writeAll("zig_as_"); |
| | 3814 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| | 3815 | try writer.writeAll("(0, "); |
| | 3816 | } else { |
| | 3817 | try writer.writeByte('('); |
| | 3818 | try f.renderTypecast(writer, host_ty); |
| | 3819 | try writer.writeByte(')'); |
| | 3820 | } |
| | 3821 | |
| 3527 | if (src_ty.isPtrAtRuntime()) { | 3822 | if (src_ty.isPtrAtRuntime()) { |
| 3528 | try writer.writeByte('('); | 3823 | try writer.writeByte('('); |
| 3529 | try f.renderTypecast(writer, Type.usize); | 3824 | try f.renderTypecast(writer, Type.usize); |
| 3530 | try writer.writeByte(')'); | 3825 | try writer.writeByte(')'); |
| 3531 | } | 3826 | } |
| 3532 | try f.writeCValue(writer, src_val, .Other); | 3827 | try f.writeCValue(writer, src_val, .Other); |
| | 3828 | if (cant_cast) try writer.writeByte(')'); |
| 3533 | try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); | 3829 | try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); |
| 3534 | } else { | 3830 | } else { |
| 3535 | try f.writeCValueDeref(writer, ptr_val); | 3831 | try f.writeCValueDeref(writer, ptr_val); |
| ... | @@ -3610,12 +3906,12 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3610,12 +3906,12 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3610 | | 3906 | |
| 3611 | const writer = f.object.writer(); | 3907 | const writer = f.object.writer(); |
| 3612 | const local = try f.allocLocal(inst, inst_ty); | 3908 | const local = try f.allocLocal(inst, inst_ty); |
| | 3909 | |
| 3613 | try f.writeCValue(writer, local, .Other); | 3910 | try f.writeCValue(writer, local, .Other); |
| 3614 | try writer.writeAll(" = "); | 3911 | try writer.writeAll(" = "); |
| 3615 | try writer.writeByte('!'); | 3912 | try writer.writeByte('!'); |
| 3616 | try f.writeCValue(writer, op, .Other); | 3913 | try f.writeCValue(writer, op, .Other); |
| 3617 | try writer.writeAll(";\n"); | 3914 | try writer.writeAll(";\n"); |
| 3618 | | | |
| 3619 | return local; | 3915 | return local; |
| 3620 | } | 3916 | } |
| 3621 | | 3917 | |
| ... | @@ -4382,7 +4678,15 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4382,7 +4678,15 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4382 | try f.writeCValue(writer, cond, .Other); | 4678 | try f.writeCValue(writer, cond, .Other); |
| 4383 | try writer.writeAll(") "); | 4679 | try writer.writeAll(") "); |
| 4384 | try genBody(f, then_body); | 4680 | try genBody(f, then_body); |
| 4385 | try writer.writeAll(" else "); | 4681 | |
| | 4682 | // TODO: If body ends in goto, elide the else block? |
| | 4683 | const needs_else = then_body.len <= 0 or f.air.instructions.items(.tag)[then_body[then_body.len - 1]] != .br; |
| | 4684 | if (needs_else) { |
| | 4685 | try writer.writeAll(" else "); |
| | 4686 | } else { |
| | 4687 | try writer.writeByte('\n'); |
| | 4688 | } |
| | 4689 | |
| 4386 | f.value_map.deinit(); | 4690 | f.value_map.deinit(); |
| 4387 | f.value_map = cloned_map.move(); | 4691 | f.value_map = cloned_map.move(); |
| 4388 | const free_locals = f.getFreeLocals(); | 4692 | const free_locals = f.getFreeLocals(); |
| ... | @@ -4395,7 +4699,12 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4395,7 +4699,12 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4395 | | 4699 | |
| 4396 | try noticeBranchFrees(f, pre_locals_len, inst); | 4700 | try noticeBranchFrees(f, pre_locals_len, inst); |
| 4397 | | 4701 | |
| 4398 | try genBody(f, else_body); | 4702 | if (needs_else) { |
| | 4703 | try genBody(f, else_body); |
| | 4704 | } else { |
| | 4705 | try genBodyInner(f, else_body); |
| | 4706 | } |
| | 4707 | |
| 4399 | try f.object.indent_writer.insertNewline(); | 4708 | try f.object.indent_writer.insertNewline(); |
| 4400 | | 4709 | |
| 4401 | return CValue.none; | 4710 | return CValue.none; |
| ... | @@ -5218,13 +5527,22 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5218,13 +5527,22 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5218 | try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty); | 5527 | try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty); |
| 5219 | try writer.writeAll("(("); | 5528 | try writer.writeAll("(("); |
| 5220 | try f.renderTypecast(writer, field_int_ty); | 5529 | try f.renderTypecast(writer, field_int_ty); |
| 5221 | try writer.writeAll(")zig_shr_"); | 5530 | try writer.writeByte(')'); |
| | 5531 | const cant_cast = int_info.bits > 64; |
| | 5532 | if (cant_cast) { |
| | 5533 | if (field_int_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); |
| | 5534 | try writer.writeAll("zig_lo_"); |
| | 5535 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); |
| | 5536 | try writer.writeByte('('); |
| | 5537 | } |
| | 5538 | try writer.writeAll("zig_shr_"); |
| 5222 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); | 5539 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); |
| 5223 | try writer.writeByte('('); | 5540 | try writer.writeByte('('); |
| 5224 | try f.writeCValue(writer, struct_byval, .Other); | 5541 | try f.writeCValue(writer, struct_byval, .Other); |
| 5225 | try writer.writeAll(", "); | 5542 | try writer.writeAll(", "); |
| 5226 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | 5543 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 5227 | try writer.writeByte(')'); | 5544 | try writer.writeByte(')'); |
| | 5545 | if (cant_cast) try writer.writeByte(')'); |
| 5228 | try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .Bits); | 5546 | try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .Bits); |
| 5229 | try writer.writeAll(");\n"); | 5547 | try writer.writeAll(");\n"); |
| 5230 | if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local; | 5548 | if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local; |
| ... | @@ -5812,7 +6130,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -5812,7 +6130,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 5812 | try writer.writeAll(";\n"); | 6130 | try writer.writeAll(";\n"); |
| 5813 | try writer.writeAll("if ("); | 6131 | try writer.writeAll("if ("); |
| 5814 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); | 6132 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 5815 | try f.renderTypecast(writer, ptr_ty.elemType()); | 6133 | try f.renderTypecast(writer, ptr_ty.childType()); |
| 5816 | try writer.writeByte(')'); | 6134 | try writer.writeByte(')'); |
| 5817 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6135 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 5818 | try writer.writeAll(" *)"); | 6136 | try writer.writeAll(" *)"); |
| ... | @@ -5825,6 +6143,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -5825,6 +6143,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 5825 | try writeMemoryOrder(writer, extra.successOrder()); | 6143 | try writeMemoryOrder(writer, extra.successOrder()); |
| 5826 | try writer.writeAll(", "); | 6144 | try writer.writeAll(", "); |
| 5827 | try writeMemoryOrder(writer, extra.failureOrder()); | 6145 | try writeMemoryOrder(writer, extra.failureOrder()); |
| | 6146 | try writer.writeAll(", "); |
| | 6147 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); |
| 5828 | try writer.writeByte(')'); | 6148 | try writer.writeByte(')'); |
| 5829 | try writer.writeAll(") {\n"); | 6149 | try writer.writeAll(") {\n"); |
| 5830 | f.object.indent_writer.pushIndent(); | 6150 | f.object.indent_writer.pushIndent(); |
| ... | @@ -5839,7 +6159,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -5839,7 +6159,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 5839 | try writer.writeAll(";\n"); | 6159 | try writer.writeAll(";\n"); |
| 5840 | try f.writeCValue(writer, local, .Other); | 6160 | try f.writeCValue(writer, local, .Other); |
| 5841 | try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor}); | 6161 | try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 5842 | try f.renderTypecast(writer, ptr_ty.elemType()); | 6162 | try f.renderTypecast(writer, ptr_ty.childType()); |
| 5843 | try writer.writeByte(')'); | 6163 | try writer.writeByte(')'); |
| 5844 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6164 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 5845 | try writer.writeAll(" *)"); | 6165 | try writer.writeAll(" *)"); |
| ... | @@ -5852,6 +6172,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -5852,6 +6172,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 5852 | try writeMemoryOrder(writer, extra.successOrder()); | 6172 | try writeMemoryOrder(writer, extra.successOrder()); |
| 5853 | try writer.writeAll(", "); | 6173 | try writer.writeAll(", "); |
| 5854 | try writeMemoryOrder(writer, extra.failureOrder()); | 6174 | try writeMemoryOrder(writer, extra.failureOrder()); |
| | 6175 | try writer.writeAll(", "); |
| | 6176 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); |
| 5855 | try writer.writeByte(')'); | 6177 | try writer.writeByte(')'); |
| 5856 | try writer.writeAll(";\n"); | 6178 | try writer.writeAll(";\n"); |
| 5857 | } | 6179 | } |
| ... | @@ -5874,8 +6196,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5874,8 +6196,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5874 | try reap(f, inst, &.{ pl_op.operand, extra.operand }); | 6196 | try reap(f, inst, &.{ pl_op.operand, extra.operand }); |
| 5875 | const writer = f.object.writer(); | 6197 | const writer = f.object.writer(); |
| 5876 | const local = try f.allocLocal(inst, inst_ty); | 6198 | const local = try f.allocLocal(inst, inst_ty); |
| 5877 | try f.writeCValue(writer, local, .Other); | | |
| 5878 | | 6199 | |
| | 6200 | try f.writeCValue(writer, local, .Other); |
| 5879 | try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())}); | 6201 | try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())}); |
| 5880 | switch (extra.op()) { | 6202 | switch (extra.op()) { |
| 5881 | else => { | 6203 | else => { |
| ... | @@ -5895,6 +6217,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5895,6 +6217,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5895 | try f.writeCValue(writer, operand, .FunctionArgument); | 6217 | try f.writeCValue(writer, operand, .FunctionArgument); |
| 5896 | try writer.writeAll(", "); | 6218 | try writer.writeAll(", "); |
| 5897 | try writeMemoryOrder(writer, extra.ordering()); | 6219 | try writeMemoryOrder(writer, extra.ordering()); |
| | 6220 | try writer.writeAll(", "); |
| | 6221 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); |
| 5898 | try writer.writeAll(");\n"); | 6222 | try writer.writeAll(");\n"); |
| 5899 | | 6223 | |
| 5900 | if (f.liveness.isUnused(inst)) { | 6224 | if (f.liveness.isUnused(inst)) { |
| ... | @@ -5927,6 +6251,8 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5927,6 +6251,8 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5927 | try f.writeCValue(writer, ptr, .Other); | 6251 | try f.writeCValue(writer, ptr, .Other); |
| 5928 | try writer.writeAll(", "); | 6252 | try writer.writeAll(", "); |
| 5929 | try writeMemoryOrder(writer, atomic_load.order); | 6253 | try writeMemoryOrder(writer, atomic_load.order); |
| | 6254 | try writer.writeAll(", "); |
| | 6255 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); |
| 5930 | try writer.writeAll(");\n"); | 6256 | try writer.writeAll(");\n"); |
| 5931 | | 6257 | |
| 5932 | return local; | 6258 | return local; |
| ... | @@ -5948,7 +6274,9 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa | ... | @@ -5948,7 +6274,9 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa |
| 5948 | try f.writeCValue(writer, ptr, .Other); | 6274 | try f.writeCValue(writer, ptr, .Other); |
| 5949 | try writer.writeAll(", "); | 6275 | try writer.writeAll(", "); |
| 5950 | try f.writeCValue(writer, element, .FunctionArgument); | 6276 | try f.writeCValue(writer, element, .FunctionArgument); |
| 5951 | try writer.print(", {s});\n", .{order}); | 6277 | try writer.print(", {s}, ", .{order}); |
| | 6278 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); |
| | 6279 | try writer.writeAll(");\n"); |
| 5952 | | 6280 | |
| 5953 | return CValue.none; | 6281 | return CValue.none; |
| 5954 | } | 6282 | } |
| ... | @@ -6405,9 +6733,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6405,9 +6733,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6405 | }, | 6733 | }, |
| 6406 | .Packed => { | 6734 | .Packed => { |
| 6407 | try f.writeCValue(writer, local, .Other); | 6735 | try f.writeCValue(writer, local, .Other); |
| 6408 | try writer.writeAll(" = ("); | 6736 | try writer.writeAll(" = "); |
| 6409 | try f.renderTypecast(writer, inst_ty); | | |
| 6410 | try writer.writeAll(")"); | | |
| 6411 | const int_info = inst_ty.intInfo(target); | 6737 | const int_info = inst_ty.intInfo(target); |
| 6412 | | 6738 | |
| 6413 | var bit_offset_ty_pl = Type.Payload.Bits{ | 6739 | var bit_offset_ty_pl = Type.Payload.Bits{ |
| ... | @@ -6437,20 +6763,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6437,20 +6763,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6437 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 6763 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 6438 | | 6764 | |
| 6439 | if (!empty) try writer.writeAll(", "); | 6765 | if (!empty) try writer.writeAll(", "); |
| | 6766 | // TODO: Skip this entire shift if val is 0? |
| 6440 | try writer.writeAll("zig_shlw_"); | 6767 | try writer.writeAll("zig_shlw_"); |
| 6441 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); | 6768 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); |
| 6442 | try writer.writeAll("(("); | 6769 | try writer.writeByte('('); |
| 6443 | try f.renderTypecast(writer, inst_ty); | 6770 | |
| 6444 | try writer.writeByte(')'); | 6771 | if (inst_ty.isAbiInt() and (field_ty.isAbiInt() or field_ty.isPtrAtRuntime())) { |
| 6445 | if (field_ty.isPtrAtRuntime()) { | 6772 | try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument); |
| | 6773 | } else { |
| 6446 | try writer.writeByte('('); | 6774 | try writer.writeByte('('); |
| 6447 | try f.renderTypecast(writer, switch (int_info.signedness) { | 6775 | try f.renderTypecast(writer, inst_ty); |
| 6448 | .unsigned => Type.usize, | | |
| 6449 | .signed => Type.isize, | | |
| 6450 | }); | | |
| 6451 | try writer.writeByte(')'); | 6776 | try writer.writeByte(')'); |
| | 6777 | if (field_ty.isPtrAtRuntime()) { |
| | 6778 | try writer.writeByte('('); |
| | 6779 | try f.renderTypecast(writer, switch (int_info.signedness) { |
| | 6780 | .unsigned => Type.usize, |
| | 6781 | .signed => Type.isize, |
| | 6782 | }); |
| | 6783 | try writer.writeByte(')'); |
| | 6784 | } |
| | 6785 | try f.writeCValue(writer, element, .Other); |
| 6452 | } | 6786 | } |
| 6453 | try f.writeCValue(writer, element, .Other); | 6787 | |
| 6454 | try writer.writeAll(", "); | 6788 | try writer.writeAll(", "); |
| 6455 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | 6789 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 6456 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits); | 6790 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits); |
| ... | @@ -6460,7 +6794,14 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6460,7 +6794,14 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6460 | bit_offset_val_pl.data += field_ty.bitSize(target); | 6794 | bit_offset_val_pl.data += field_ty.bitSize(target); |
| 6461 | empty = false; | 6795 | empty = false; |
| 6462 | } | 6796 | } |
| 6463 | if (empty) try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer); | 6797 | |
| | 6798 | if (empty) { |
| | 6799 | try writer.writeByte('('); |
| | 6800 | try f.renderTypecast(writer, inst_ty); |
| | 6801 | try writer.writeByte(')'); |
| | 6802 | try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer); |
| | 6803 | } |
| | 6804 | |
| 6464 | try writer.writeAll(";\n"); | 6805 | try writer.writeAll(";\n"); |
| 6465 | }, | 6806 | }, |
| 6466 | }, | 6807 | }, |
| ... | @@ -6793,6 +7134,68 @@ fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 { | ... | @@ -6793,6 +7134,68 @@ fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 { |
| 6793 | } else unreachable; | 7134 | } else unreachable; |
| 6794 | } | 7135 | } |
| 6795 | | 7136 | |
| | 7137 | fn StringLiteral(comptime WriterType: type) type { |
| | 7138 | // MSVC has a length limit of 16380 per string literal (before concatenation) |
| | 7139 | const max_char_len = 4; |
| | 7140 | const max_len = 16380 - max_char_len; |
| | 7141 | |
| | 7142 | return struct { |
| | 7143 | cur_len: u64 = 0, |
| | 7144 | counting_writer: std.io.CountingWriter(WriterType), |
| | 7145 | |
| | 7146 | pub const Error = WriterType.Error; |
| | 7147 | |
| | 7148 | const Self = @This(); |
| | 7149 | |
| | 7150 | pub fn start(self: *Self) Error!void { |
| | 7151 | const writer = self.counting_writer.writer(); |
| | 7152 | try writer.writeByte('\"'); |
| | 7153 | } |
| | 7154 | |
| | 7155 | pub fn end(self: *Self) Error!void { |
| | 7156 | const writer = self.counting_writer.writer(); |
| | 7157 | try writer.writeByte('\"'); |
| | 7158 | } |
| | 7159 | |
| | 7160 | fn writeStringLiteralChar(writer: anytype, c: u8) !void { |
| | 7161 | switch (c) { |
| | 7162 | 7 => try writer.writeAll("\\a"), |
| | 7163 | 8 => try writer.writeAll("\\b"), |
| | 7164 | '\t' => try writer.writeAll("\\t"), |
| | 7165 | '\n' => try writer.writeAll("\\n"), |
| | 7166 | 11 => try writer.writeAll("\\v"), |
| | 7167 | 12 => try writer.writeAll("\\f"), |
| | 7168 | '\r' => try writer.writeAll("\\r"), |
| | 7169 | '"', '\'', '?', '\\' => try writer.print("\\{c}", .{c}), |
| | 7170 | else => switch (c) { |
| | 7171 | ' '...'~' => try writer.writeByte(c), |
| | 7172 | else => try writer.print("\\{o:0>3}", .{c}), |
| | 7173 | }, |
| | 7174 | } |
| | 7175 | } |
| | 7176 | |
| | 7177 | pub fn writeChar(self: *Self, c: u8) Error!void { |
| | 7178 | const writer = self.counting_writer.writer(); |
| | 7179 | |
| | 7180 | if (self.cur_len == 0 and self.counting_writer.bytes_written > 1) |
| | 7181 | try writer.writeAll("\"\""); |
| | 7182 | |
| | 7183 | const len = self.counting_writer.bytes_written; |
| | 7184 | try writeStringLiteralChar(writer, c); |
| | 7185 | |
| | 7186 | const char_length = self.counting_writer.bytes_written - len; |
| | 7187 | assert(char_length <= max_char_len); |
| | 7188 | self.cur_len += char_length; |
| | 7189 | |
| | 7190 | if (self.cur_len >= max_len) self.cur_len = 0; |
| | 7191 | } |
| | 7192 | }; |
| | 7193 | } |
| | 7194 | |
| | 7195 | fn stringLiteral(child_stream: anytype) StringLiteral(@TypeOf(child_stream)) { |
| | 7196 | return .{ .counting_writer = std.io.countingWriter(child_stream) }; |
| | 7197 | } |
| | 7198 | |
| 6796 | fn formatStringLiteral( | 7199 | fn formatStringLiteral( |
| 6797 | str: []const u8, | 7200 | str: []const u8, |
| 6798 | comptime fmt: []const u8, | 7201 | comptime fmt: []const u8, |
| ... | @@ -6800,44 +7203,25 @@ fn formatStringLiteral( | ... | @@ -6800,44 +7203,25 @@ fn formatStringLiteral( |
| 6800 | writer: anytype, | 7203 | writer: anytype, |
| 6801 | ) @TypeOf(writer).Error!void { | 7204 | ) @TypeOf(writer).Error!void { |
| 6802 | if (fmt.len != 1 or fmt[0] != 's') @compileError("Invalid fmt: " ++ fmt); | 7205 | if (fmt.len != 1 or fmt[0] != 's') @compileError("Invalid fmt: " ++ fmt); |
| 6803 | try writer.writeByte('\"'); | 7206 | |
| | 7207 | var literal = stringLiteral(writer); |
| | 7208 | try literal.start(); |
| 6804 | for (str) |c| | 7209 | for (str) |c| |
| 6805 | try writeStringLiteralChar(writer, c); | 7210 | try literal.writeChar(c); |
| 6806 | try writer.writeByte('\"'); | 7211 | try literal.end(); |
| 6807 | } | 7212 | } |
| 6808 | | 7213 | |
| 6809 | fn fmtStringLiteral(str: []const u8) std.fmt.Formatter(formatStringLiteral) { | 7214 | fn fmtStringLiteral(str: []const u8) std.fmt.Formatter(formatStringLiteral) { |
| 6810 | return .{ .data = str }; | 7215 | return .{ .data = str }; |
| 6811 | } | 7216 | } |
| 6812 | | 7217 | |
| 6813 | fn writeStringLiteralChar(writer: anytype, c: u8) !void { | | |
| 6814 | switch (c) { | | |
| 6815 | 7 => try writer.writeAll("\\a"), | | |
| 6816 | 8 => try writer.writeAll("\\b"), | | |
| 6817 | '\t' => try writer.writeAll("\\t"), | | |
| 6818 | '\n' => try writer.writeAll("\\n"), | | |
| 6819 | 11 => try writer.writeAll("\\v"), | | |
| 6820 | 12 => try writer.writeAll("\\f"), | | |
| 6821 | '\r' => try writer.writeAll("\\r"), | | |
| 6822 | '"', '\'', '?', '\\' => try writer.print("\\{c}", .{c}), | | |
| 6823 | else => switch (c) { | | |
| 6824 | ' '...'~' => try writer.writeByte(c), | | |
| 6825 | else => try writer.print("\\{o:0>3}", .{c}), | | |
| 6826 | }, | | |
| 6827 | } | | |
| 6828 | } | | |
| 6829 | | | |
| 6830 | fn undefPattern(comptime IntType: type) IntType { | 7218 | fn undefPattern(comptime IntType: type) IntType { |
| 6831 | const int_info = @typeInfo(IntType).Int; | 7219 | const int_info = @typeInfo(IntType).Int; |
| 6832 | const UnsignedType = std.meta.Int(.unsigned, int_info.bits); | 7220 | const UnsignedType = std.meta.Int(.unsigned, int_info.bits); |
| 6833 | return @bitCast(IntType, @as(UnsignedType, (1 << (int_info.bits | 1)) / 3)); | 7221 | return @bitCast(IntType, @as(UnsignedType, (1 << (int_info.bits | 1)) / 3)); |
| 6834 | } | 7222 | } |
| 6835 | | 7223 | |
| 6836 | const FormatIntLiteralContext = struct { | 7224 | const FormatIntLiteralContext = struct { ty: Type, val: Value, mod: *Module, location: ?ValueRenderLocation = null }; |
| 6837 | ty: Type, | | |
| 6838 | val: Value, | | |
| 6839 | mod: *Module, | | |
| 6840 | }; | | |
| 6841 | fn formatIntLiteral( | 7225 | fn formatIntLiteral( |
| 6842 | data: FormatIntLiteralContext, | 7226 | data: FormatIntLiteralContext, |
| 6843 | comptime fmt: []const u8, | 7227 | comptime fmt: []const u8, |
| ... | @@ -6905,10 +7289,31 @@ fn formatIntLiteral( | ... | @@ -6905,10 +7289,31 @@ fn formatIntLiteral( |
| 6905 | return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" }); | 7289 | return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" }); |
| 6906 | } | 7290 | } |
| 6907 | | 7291 | |
| 6908 | if (!int.positive) try writer.writeByte('-'); | 7292 | var use_twos_comp = false; |
| | 7293 | if (!int.positive) { |
| | 7294 | if (c_bits > 64) { |
| | 7295 | // TODO: Can this be done for decimal literals as well? |
| | 7296 | if (fmt.len == 1 and fmt[0] != 'd') { |
| | 7297 | use_twos_comp = true; |
| | 7298 | } else { |
| | 7299 | // TODO: Use fmtIntLiteral for 0? |
| | 7300 | try writer.print("zig_sub_{c}{d}(zig_as_{c}{d}(0, 0), ", .{ signAbbrev(int_info.signedness), c_bits, signAbbrev(int_info.signedness), c_bits }); |
| | 7301 | } |
| | 7302 | } else { |
| | 7303 | try writer.writeByte('-'); |
| | 7304 | } |
| | 7305 | } |
| | 7306 | |
| 6909 | switch (data.ty.tag()) { | 7307 | switch (data.ty.tag()) { |
| 6910 | .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {}, | 7308 | .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {}, |
| 6911 | else => try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }), | 7309 | else => { |
| | 7310 | if (int_info.bits > 64 and data.location != null and data.location.? == .StaticInitializer) { |
| | 7311 | // MSVC treats casting the struct initializer as not constant (C2099), so an alternate form is used in global initializers |
| | 7312 | try writer.print("zig_as_constant_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }); |
| | 7313 | } else { |
| | 7314 | try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }); |
| | 7315 | } |
| | 7316 | }, |
| 6912 | } | 7317 | } |
| 6913 | | 7318 | |
| 6914 | const limbs_count_64 = @divExact(64, @bitSizeOf(BigIntLimb)); | 7319 | const limbs_count_64 = @divExact(64, @bitSizeOf(BigIntLimb)); |
| ... | @@ -6948,16 +7353,34 @@ fn formatIntLiteral( | ... | @@ -6948,16 +7353,34 @@ fn formatIntLiteral( |
| 6948 | } else { | 7353 | } else { |
| 6949 | assert(c_bits == 128); | 7354 | assert(c_bits == 128); |
| 6950 | const split = std.math.min(int.limbs.len, limbs_count_64); | 7355 | const split = std.math.min(int.limbs.len, limbs_count_64); |
| | 7356 | var twos_comp_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined; |
| | 7357 | |
| | 7358 | // Adding a negation in the C code before the doesn't work in all cases: |
| | 7359 | // - struct versions would require an extra zig_sub_ call to negate, which wouldn't work in constant expressions |
| | 7360 | // - negating the f80 int representation (i128) doesn't make sense |
| | 7361 | // Instead we write out the literal as a negative number in twos complement |
| | 7362 | var limbs = int.limbs; |
| | 7363 | |
| | 7364 | if (use_twos_comp) { |
| | 7365 | var twos_comp = BigInt.Mutable{ |
| | 7366 | .limbs = &twos_comp_limbs, |
| | 7367 | .positive = undefined, |
| | 7368 | .len = undefined, |
| | 7369 | }; |
| | 7370 | |
| | 7371 | twos_comp.convertToTwosComplement(int, .signed, int_info.bits); |
| | 7372 | limbs = twos_comp.limbs; |
| | 7373 | } |
| 6951 | | 7374 | |
| 6952 | var upper_pl = Value.Payload.BigInt{ | 7375 | var upper_pl = Value.Payload.BigInt{ |
| 6953 | .base = .{ .tag = .int_big_positive }, | 7376 | .base = .{ .tag = .int_big_positive }, |
| 6954 | .data = int.limbs[split..], | 7377 | .data = limbs[split..], |
| 6955 | }; | 7378 | }; |
| 6956 | const upper_val = Value.initPayload(&upper_pl.base); | 7379 | const upper_val = Value.initPayload(&upper_pl.base); |
| 6957 | try formatIntLiteral(.{ | 7380 | try formatIntLiteral(.{ |
| 6958 | .ty = switch (int_info.signedness) { | 7381 | .ty = switch (int_info.signedness) { |
| 6959 | .unsigned => Type.u64, | 7382 | .unsigned => Type.u64, |
| 6960 | .signed => Type.i64, | 7383 | .signed => if (use_twos_comp) Type.u64 else Type.i64, |
| 6961 | }, | 7384 | }, |
| 6962 | .val = upper_val, | 7385 | .val = upper_val, |
| 6963 | .mod = data.mod, | 7386 | .mod = data.mod, |
| ... | @@ -6967,7 +7390,7 @@ fn formatIntLiteral( | ... | @@ -6967,7 +7390,7 @@ fn formatIntLiteral( |
| 6967 | | 7390 | |
| 6968 | var lower_pl = Value.Payload.BigInt{ | 7391 | var lower_pl = Value.Payload.BigInt{ |
| 6969 | .base = .{ .tag = .int_big_positive }, | 7392 | .base = .{ .tag = .int_big_positive }, |
| 6970 | .data = int.limbs[0..split], | 7393 | .data = limbs[0..split], |
| 6971 | }; | 7394 | }; |
| 6972 | const lower_val = Value.initPayload(&lower_pl.base); | 7395 | const lower_val = Value.initPayload(&lower_pl.base); |
| 6973 | try formatIntLiteral(.{ | 7396 | try formatIntLiteral(.{ |
| ... | @@ -6976,6 +7399,7 @@ fn formatIntLiteral( | ... | @@ -6976,6 +7399,7 @@ fn formatIntLiteral( |
| 6976 | .mod = data.mod, | 7399 | .mod = data.mod, |
| 6977 | }, fmt, options, writer); | 7400 | }, fmt, options, writer); |
| 6978 | | 7401 | |
| | 7402 | if (!int.positive and c_bits > 64 and !use_twos_comp) try writer.writeByte(')'); |
| 6979 | return writer.writeByte(')'); | 7403 | return writer.writeByte(')'); |
| 6980 | } | 7404 | } |
| 6981 | | 7405 | |