| ... | @@ -19,7 +19,7 @@ const Liveness = @import("../Liveness.zig"); | ... | @@ -19,7 +19,7 @@ const Liveness = @import("../Liveness.zig"); |
| 19 | const CType = @import("../type.zig").CType; | 19 | const CType = @import("../type.zig").CType; |
| 20 | | 20 | |
| 21 | const Mutability = enum { Const, Mut }; | 21 | const Mutability = enum { Const, Mut }; |
| 22 | const BigIntConst = std.math.big.int.Const; | 22 | const BigInt = std.math.big.int; |
| 23 | | 23 | |
| 24 | pub const CValue = union(enum) { | 24 | pub const CValue = union(enum) { |
| 25 | none: void, | 25 | none: void, |
| ... | @@ -35,7 +35,7 @@ pub const CValue = union(enum) { | ... | @@ -35,7 +35,7 @@ pub const CValue = union(enum) { |
| 35 | decl: Decl.Index, | 35 | decl: Decl.Index, |
| 36 | decl_ref: Decl.Index, | 36 | decl_ref: Decl.Index, |
| 37 | /// An undefined (void *) pointer (cannot be dereferenced) | 37 | /// An undefined (void *) pointer (cannot be dereferenced) |
| 38 | undefined_ptr: void, | 38 | undefined_ptr: Type, |
| 39 | /// Render the slice as an identifier (using fmtIdent) | 39 | /// Render the slice as an identifier (using fmtIdent) |
| 40 | identifier: []const u8, | 40 | identifier: []const u8, |
| 41 | /// Render these bytes literally. | 41 | /// Render these bytes literally. |
| ... | @@ -74,11 +74,11 @@ fn formatTypeAsCIdentifier( | ... | @@ -74,11 +74,11 @@ fn formatTypeAsCIdentifier( |
| 74 | options: std.fmt.FormatOptions, | 74 | options: std.fmt.FormatOptions, |
| 75 | writer: anytype, | 75 | writer: anytype, |
| 76 | ) !void { | 76 | ) !void { |
| 77 | _ = fmt; | 77 | var stack = std.heap.stackFallback(128, data.mod.gpa); |
| 78 | _ = options; | 78 | const allocator = stack.get(); |
| 79 | var buffer = [1]u8{0} ** 128; | 79 | const str = std.fmt.allocPrint(allocator, "{}", .{data.ty.fmt(data.mod)}) catch ""; |
| 80 | var buf = std.fmt.bufPrint(&buffer, "{}", .{data.ty.fmt(data.mod)}) catch &buffer; | 80 | defer allocator.free(str); |
| 81 | return formatIdent(buf, "", .{}, writer); | 81 | return formatIdent(str, fmt, options, writer); |
| 82 | } | 82 | } |
| 83 | | 83 | |
| 84 | pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsCIdentifier) { | 84 | pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsCIdentifier) { |
| ... | @@ -332,8 +332,8 @@ pub const Function = struct { | ... | @@ -332,8 +332,8 @@ pub const Function = struct { |
| 332 | return f.object.dg.renderTypecast(w, t); | 332 | return f.object.dg.renderTypecast(w, t); |
| 333 | } | 333 | } |
| 334 | | 334 | |
| 335 | fn fmtIntLiteral(f: *Function, ty: Type, int_val: anytype) !IntLiteralFormatter(@TypeOf(int_val)) { | 335 | fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) { |
| 336 | return f.object.dg.fmtIntLiteral(ty, int_val, .Other); | 336 | return f.object.dg.fmtIntLiteral(ty, val, .Other); |
| 337 | } | 337 | } |
| 338 | }; | 338 | }; |
| 339 | | 339 | |
| ... | @@ -423,51 +423,6 @@ pub const DeclGen = struct { | ... | @@ -423,51 +423,6 @@ pub const DeclGen = struct { |
| 423 | try dg.renderDeclName(writer, decl_index); | 423 | try dg.renderDeclName(writer, decl_index); |
| 424 | } | 424 | } |
| 425 | | 425 | |
| 426 | fn renderInt128( | | |
| 427 | writer: anytype, | | |
| 428 | int_val: anytype, | | |
| 429 | ) error{ OutOfMemory, AnalysisFail }!void { | | |
| 430 | const int_info = @typeInfo(@TypeOf(int_val)).Int; | | |
| 431 | const is_signed = int_info.signedness == .signed; | | |
| 432 | const is_neg = int_val < 0; | | |
| 433 | comptime assert(int_info.bits > 64 and int_info.bits <= 128); | | |
| 434 | | | |
| 435 | // Clang and GCC don't support 128-bit integer constants but will hopefully unfold them | | |
| 436 | // if we construct one manually. | | |
| 437 | const magnitude = std.math.absCast(int_val); | | |
| 438 | | | |
| 439 | const high = @truncate(u64, magnitude >> 64); | | |
| 440 | const low = @truncate(u64, magnitude); | | |
| 441 | | | |
| 442 | // (int128_t)/<->( ( (uint128_t)( val_high << 64 )u ) + (uint128_t)val_low/u ) | | |
| 443 | if (is_signed) try writer.writeAll("(int128_t)"); | | |
| 444 | if (is_neg) try writer.writeByte('-'); | | |
| 445 | | | |
| 446 | try writer.print("(((uint128_t)0x{x}u<<64)", .{high}); | | |
| 447 | | | |
| 448 | if (low > 0) | | |
| 449 | try writer.print("+(uint128_t)0x{x}u", .{low}); | | |
| 450 | | | |
| 451 | return writer.writeByte(')'); | | |
| 452 | } | | |
| 453 | | | |
| 454 | fn renderBigIntConst( | | |
| 455 | dg: *DeclGen, | | |
| 456 | writer: anytype, | | |
| 457 | val: BigIntConst, | | |
| 458 | signed: bool, | | |
| 459 | ) error{ OutOfMemory, AnalysisFail }!void { | | |
| 460 | if (signed) { | | |
| 461 | try renderInt128(writer, val.to(i128) catch { | | |
| 462 | return dg.fail("TODO implement integer constants larger than 128 bits", .{}); | | |
| 463 | }); | | |
| 464 | } else { | | |
| 465 | try renderInt128(writer, val.to(u128) catch { | | |
| 466 | return dg.fail("TODO implement integer constants larger than 128 bits", .{}); | | |
| 467 | }); | | |
| 468 | } | | |
| 469 | } | | |
| 470 | | | |
| 471 | // Renders a "parent" pointer by recursing to the root decl/variable | 426 | // Renders a "parent" pointer by recursing to the root decl/variable |
| 472 | // that its contents are defined with respect to. | 427 | // that its contents are defined with respect to. |
| 473 | // | 428 | // |
| ... | @@ -578,14 +533,14 @@ pub const DeclGen = struct { | ... | @@ -578,14 +533,14 @@ pub const DeclGen = struct { |
| 578 | .Enum, | 533 | .Enum, |
| 579 | .ErrorSet, | 534 | .ErrorSet, |
| 580 | => return writer.print("{x}", .{ | 535 | => return writer.print("{x}", .{ |
| 581 | try dg.fmtIntLiteral(ty, UndefInt{}, location), | 536 | try dg.fmtIntLiteral(ty, val, location), |
| 582 | }), | 537 | }), |
| 583 | .Float => switch (ty.tag()) { | 538 | .Float => switch (ty.tag()) { |
| 584 | .f32 => return writer.print("zig_bitcast_f32_u32({x})", .{ | 539 | .f32 => return writer.print("zig_bitcast_f32_u32({x})", .{ |
| 585 | try dg.fmtIntLiteral(Type.u32, UndefInt{}, location), | 540 | try dg.fmtIntLiteral(Type.u32, val, location), |
| 586 | }), | 541 | }), |
| 587 | .f64 => return writer.print("zig_bitcast_f64_u64({x})", .{ | 542 | .f64 => return writer.print("zig_bitcast_f64_u64({x})", .{ |
| 588 | try dg.fmtIntLiteral(Type.u64, UndefInt{}, location), | 543 | try dg.fmtIntLiteral(Type.u64, val, location), |
| 589 | }), | 544 | }), |
| 590 | else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}), | 545 | else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}), |
| 591 | }, | 546 | }, |
| ... | @@ -593,13 +548,19 @@ pub const DeclGen = struct { | ... | @@ -593,13 +548,19 @@ pub const DeclGen = struct { |
| 593 | .Slice => { | 548 | .Slice => { |
| 594 | try writer.writeByte('('); | 549 | try writer.writeByte('('); |
| 595 | try dg.renderTypecast(writer, ty); | 550 | try dg.renderTypecast(writer, ty); |
| 596 | return writer.print("){{(void *){x}, {0x}}}", .{ | 551 | try writer.writeAll("){("); |
| 597 | try dg.fmtIntLiteral(Type.usize, UndefInt{}, location), | 552 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| | 553 | const ptr_ty = ty.slicePtrFieldType(&buf); |
| | 554 | try dg.renderTypecast(writer, ptr_ty); |
| | 555 | return writer.print("){x}, {0x}}}", .{ |
| | 556 | try dg.fmtIntLiteral(Type.usize, val, location), |
| 598 | }); | 557 | }); |
| 599 | }, | 558 | }, |
| 600 | .Many, .C, .One => return writer.print("((void *){x})", .{ | 559 | .Many, .C, .One => { |
| 601 | try dg.fmtIntLiteral(Type.usize, UndefInt{}, location), | 560 | try writer.writeAll("(("); |
| 602 | }), | 561 | try dg.renderTypecast(writer, ty); |
| | 562 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, location)}); |
| | 563 | }, |
| 603 | }, | 564 | }, |
| 604 | .Optional => { | 565 | .Optional => { |
| 605 | var opt_buf: Type.Payload.ElemType = undefined; | 566 | var opt_buf: Type.Payload.ElemType = undefined; |
| ... | @@ -636,7 +597,7 @@ pub const DeclGen = struct { | ... | @@ -636,7 +597,7 @@ pub const DeclGen = struct { |
| 636 | empty = false; | 597 | empty = false; |
| 637 | } | 598 | } |
| 638 | if (empty) try writer.print("{x}", .{ | 599 | if (empty) try writer.print("{x}", .{ |
| 639 | try dg.fmtIntLiteral(Type.u8, UndefInt{}, location), | 600 | try dg.fmtIntLiteral(Type.u8, Value.undef, location), |
| 640 | }); | 601 | }); |
| 641 | | 602 | |
| 642 | return writer.writeByte('}'); | 603 | return writer.writeByte('}'); |
| ... | @@ -651,7 +612,7 @@ pub const DeclGen = struct { | ... | @@ -651,7 +612,7 @@ pub const DeclGen = struct { |
| 651 | try dg.renderValue(writer, field.ty, val, location); | 612 | try dg.renderValue(writer, field.ty, val, location); |
| 652 | break; | 613 | break; |
| 653 | } else try writer.print("{x}", .{ | 614 | } else try writer.print("{x}", .{ |
| 654 | try dg.fmtIntLiteral(Type.u8, UndefInt{}, location), | 615 | try dg.fmtIntLiteral(Type.u8, Value.undef, location), |
| 655 | }); | 616 | }); |
| 656 | | 617 | |
| 657 | return writer.writeByte('}'); | 618 | return writer.writeByte('}'); |
| ... | @@ -662,7 +623,7 @@ pub const DeclGen = struct { | ... | @@ -662,7 +623,7 @@ pub const DeclGen = struct { |
| 662 | try writer.writeAll("){ .payload = "); | 623 | try writer.writeAll("){ .payload = "); |
| 663 | try dg.renderValue(writer, ty.errorUnionPayload(), val, location); | 624 | try dg.renderValue(writer, ty.errorUnionPayload(), val, location); |
| 664 | return writer.print(", .error = {x} }}", .{ | 625 | return writer.print(", .error = {x} }}", .{ |
| 665 | try dg.fmtIntLiteral(ty.errorUnionSet(), UndefInt{}, location), | 626 | try dg.fmtIntLiteral(ty.errorUnionSet(), Value.undef, location), |
| 666 | }); | 627 | }); |
| 667 | }, | 628 | }, |
| 668 | .Array => { | 629 | .Array => { |
| ... | @@ -696,15 +657,10 @@ pub const DeclGen = struct { | ... | @@ -696,15 +657,10 @@ pub const DeclGen = struct { |
| 696 | @tagName(tag), | 657 | @tagName(tag), |
| 697 | }), | 658 | }), |
| 698 | } | 659 | } |
| | 660 | unreachable; |
| 699 | } | 661 | } |
| 700 | switch (ty.zigTypeTag()) { | 662 | switch (ty.zigTypeTag()) { |
| 701 | .Int => switch (val.tag()) { | 663 | .Int => switch (val.tag()) { |
| 702 | .int_big_positive => return writer.print("{x}", .{ | | |
| 703 | try dg.fmtIntLiteral(ty, val.castTag(.int_big_positive).?.asBigInt(), location), | | |
| 704 | }), | | |
| 705 | .int_big_negative => return writer.print("{x}", .{ | | |
| 706 | try dg.fmtIntLiteral(ty, val.castTag(.int_big_negative).?.asBigInt(), location), | | |
| 707 | }), | | |
| 708 | .field_ptr, | 664 | .field_ptr, |
| 709 | .elem_ptr, | 665 | .elem_ptr, |
| 710 | .opt_payload_ptr, | 666 | .opt_payload_ptr, |
| ... | @@ -712,32 +668,35 @@ pub const DeclGen = struct { | ... | @@ -712,32 +668,35 @@ pub const DeclGen = struct { |
| 712 | .decl_ref_mut, | 668 | .decl_ref_mut, |
| 713 | .decl_ref, | 669 | .decl_ref, |
| 714 | => try dg.renderParentPtr(writer, val, ty), | 670 | => try dg.renderParentPtr(writer, val, ty), |
| 715 | else => if (ty.isSignedInt()) | 671 | else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, location)}), |
| 716 | return writer.print("{d}", .{try dg.fmtIntLiteral(ty, val.toSignedInt(), location)}) | | |
| 717 | else | | |
| 718 | return writer.print("{d}", .{ | | |
| 719 | try dg.fmtIntLiteral(ty, val.toUnsignedInt(target), location), | | |
| 720 | }), | | |
| 721 | }, | 672 | }, |
| 722 | .Float => { | 673 | .Float => { |
| 723 | if (ty.floatBits(target) <= 64) { | 674 | if (ty.floatBits(target) <= 64) { |
| 724 | if (std.math.isNan(val.toFloat(f64)) or std.math.isInf(val.toFloat(f64))) { | 675 | if (std.math.isNan(val.toFloat(f64)) or std.math.isInf(val.toFloat(f64))) { |
| 725 | // just generate a bit cast (exactly like we do in airBitcast) | 676 | // just generate a bit cast (exactly like we do in airBitcast) |
| 726 | switch (ty.tag()) { | 677 | switch (ty.tag()) { |
| 727 | .f32 => return writer.print("zig_bitcast_f32_u32({x})", .{ | 678 | .f32 => { |
| 728 | try dg.fmtIntLiteral( | 679 | var bitcast_val_pl = Value.Payload.U64{ |
| | 680 | .base = .{ .tag = .int_u64 }, |
| | 681 | .data = @bitCast(u32, val.toFloat(f32)), |
| | 682 | }; |
| | 683 | return writer.print("zig_bitcast_f32_u32({x})", .{try dg.fmtIntLiteral( |
| 729 | Type.u32, | 684 | Type.u32, |
| 730 | @bitCast(u32, val.toFloat(f32)), | 685 | Value.initPayload(&bitcast_val_pl.base), |
| 731 | location, | 686 | location, |
| 732 | ), | 687 | )}); |
| 733 | }), | 688 | }, |
| 734 | .f64 => return writer.print("zig_bitcast_f64_u64({x})", .{ | 689 | .f64 => { |
| 735 | try dg.fmtIntLiteral( | 690 | var bitcast_val_pl = Value.Payload.U64{ |
| | 691 | .base = .{ .tag = .int_u64 }, |
| | 692 | .data = @bitCast(u64, val.toFloat(f64)), |
| | 693 | }; |
| | 694 | return writer.print("zig_bitcast_f32_u32({x})", .{try dg.fmtIntLiteral( |
| 736 | Type.u64, | 695 | Type.u64, |
| 737 | @bitCast(u64, val.toFloat(f64)), | 696 | Value.initPayload(&bitcast_val_pl.base), |
| 738 | location, | 697 | location, |
| 739 | ), | 698 | )}); |
| 740 | }), | 699 | }, |
| 741 | else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}), | 700 | else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}), |
| 742 | } | 701 | } |
| 743 | } else { | 702 | } else { |
| ... | @@ -779,9 +738,7 @@ pub const DeclGen = struct { | ... | @@ -779,9 +738,7 @@ pub const DeclGen = struct { |
| 779 | .int_u64, .one => { | 738 | .int_u64, .one => { |
| 780 | try writer.writeAll("(("); | 739 | try writer.writeAll("(("); |
| 781 | try dg.renderTypecast(writer, ty); | 740 | try dg.renderTypecast(writer, ty); |
| 782 | return writer.print("){x})", .{ | 741 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, location)}); |
| 783 | try dg.fmtIntLiteral(Type.usize, val.toUnsignedInt(target), location), | | |
| 784 | }); | | |
| 785 | }, | 742 | }, |
| 786 | .field_ptr, | 743 | .field_ptr, |
| 787 | .elem_ptr, | 744 | .elem_ptr, |
| ... | @@ -1069,7 +1026,7 @@ pub const DeclGen = struct { | ... | @@ -1069,7 +1026,7 @@ pub const DeclGen = struct { |
| 1069 | try bw.writeAll(" (*"); | 1026 | try bw.writeAll(" (*"); |
| 1070 | | 1027 | |
| 1071 | const name_start = buffer.items.len; | 1028 | const name_start = buffer.items.len; |
| 1072 | try bw.print("zig_F_{s})(", .{typeToCIdentifier(t, dg.module)}); | 1029 | try bw.print("zig_F_{})(", .{typeToCIdentifier(t, dg.module)}); |
| 1073 | const name_end = buffer.items.len - 2; | 1030 | const name_end = buffer.items.len - 2; |
| 1074 | | 1031 | |
| 1075 | const param_len = fn_info.param_types.len; | 1032 | const param_len = fn_info.param_types.len; |
| ... | @@ -1124,13 +1081,16 @@ pub const DeclGen = struct { | ... | @@ -1124,13 +1081,16 @@ pub const DeclGen = struct { |
| 1124 | try bw.writeAll("; size_t len; } "); | 1081 | try bw.writeAll("; size_t len; } "); |
| 1125 | const name_index = buffer.items.len; | 1082 | const name_index = buffer.items.len; |
| 1126 | if (t.isConstPtr()) { | 1083 | if (t.isConstPtr()) { |
| 1127 | try bw.print("zig_L_{s}", .{typeToCIdentifier(child_type, dg.module)}); | 1084 | try bw.print("zig_L_{}", .{typeToCIdentifier(child_type, dg.module)}); |
| 1128 | } else { | 1085 | } else { |
| 1129 | try bw.print("zig_M_{s}", .{typeToCIdentifier(child_type, dg.module)}); | 1086 | try bw.print("zig_M_{}", .{typeToCIdentifier(child_type, dg.module)}); |
| 1130 | } | 1087 | } |
| 1131 | if (ptr_sentinel) |s| { | 1088 | if (ptr_sentinel) |s| { |
| 1132 | try bw.writeAll("_s_"); | 1089 | var sentinel_buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1133 | try dg.renderValue(bw, child_type, s, .Identifier); | 1090 | defer sentinel_buffer.deinit(); |
| | 1091 | |
| | 1092 | try dg.renderValue(sentinel_buffer.writer(), child_type, s, .Identifier); |
| | 1093 | try bw.print("_s_{}", .{fmtIdent(sentinel_buffer.items)}); |
| 1134 | } | 1094 | } |
| 1135 | try bw.writeAll(";\n"); | 1095 | try bw.writeAll(";\n"); |
| 1136 | | 1096 | |
| ... | @@ -1327,7 +1287,7 @@ pub const DeclGen = struct { | ... | @@ -1327,7 +1287,7 @@ pub const DeclGen = struct { |
| 1327 | try dg.renderDeclName(bw, func.owner_decl); | 1287 | try dg.renderDeclName(bw, func.owner_decl); |
| 1328 | try bw.writeAll(";\n"); | 1288 | try bw.writeAll(";\n"); |
| 1329 | } else { | 1289 | } else { |
| 1330 | try bw.print("zig_E_{s}_{s};\n", .{ | 1290 | try bw.print("zig_E_{}_{};\n", .{ |
| 1331 | typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module), | 1291 | typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module), |
| 1332 | }); | 1292 | }); |
| 1333 | } | 1293 | } |
| ... | @@ -1356,10 +1316,13 @@ pub const DeclGen = struct { | ... | @@ -1356,10 +1316,13 @@ pub const DeclGen = struct { |
| 1356 | try dg.renderType(bw, elem_type); | 1316 | try dg.renderType(bw, elem_type); |
| 1357 | | 1317 | |
| 1358 | const name_start = buffer.items.len + 1; | 1318 | const name_start = buffer.items.len + 1; |
| 1359 | try bw.print(" zig_A_{s}_{d}", .{ typeToCIdentifier(elem_type, dg.module), t.arrayLen() }); | 1319 | try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(elem_type, dg.module), t.arrayLen() }); |
| 1360 | if (t.sentinel()) |s| { | 1320 | if (t.sentinel()) |s| { |
| 1361 | try bw.writeAll("_s_"); | 1321 | var sentinel_buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1362 | try dg.renderValue(bw, elem_type, s, .Identifier); | 1322 | defer sentinel_buffer.deinit(); |
| | 1323 | |
| | 1324 | try dg.renderValue(sentinel_buffer.writer(), elem_type, s, .Identifier); |
| | 1325 | try bw.print("_s_{}", .{fmtIdent(sentinel_buffer.items)}); |
| 1363 | } | 1326 | } |
| 1364 | const name_end = buffer.items.len; | 1327 | const name_end = buffer.items.len; |
| 1365 | | 1328 | |
| ... | @@ -1389,7 +1352,7 @@ pub const DeclGen = struct { | ... | @@ -1389,7 +1352,7 @@ pub const DeclGen = struct { |
| 1389 | try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); | 1352 | try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); |
| 1390 | try bw.writeAll("; bool is_null; } "); | 1353 | try bw.writeAll("; bool is_null; } "); |
| 1391 | const name_index = buffer.items.len; | 1354 | const name_index = buffer.items.len; |
| 1392 | try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type, dg.module)}); | 1355 | try bw.print("zig_Q_{};\n", .{typeToCIdentifier(child_type, dg.module)}); |
| 1393 | | 1356 | |
| 1394 | const rendered = buffer.toOwnedSlice(); | 1357 | const rendered = buffer.toOwnedSlice(); |
| 1395 | errdefer dg.typedefs.allocator.free(rendered); | 1358 | errdefer dg.typedefs.allocator.free(rendered); |
| ... | @@ -1413,7 +1376,7 @@ pub const DeclGen = struct { | ... | @@ -1413,7 +1376,7 @@ pub const DeclGen = struct { |
| 1413 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); | 1376 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1414 | defer buffer.deinit(); | 1377 | defer buffer.deinit(); |
| 1415 | | 1378 | |
| 1416 | try buffer.writer().print("typedef struct {} ", .{fmtIdent(std.mem.span(unqualified_name))}); | 1379 | try buffer.writer().print("typedef struct { } ", .{fmtIdent(std.mem.span(unqualified_name))}); |
| 1417 | | 1380 | |
| 1418 | const name_start = buffer.items.len; | 1381 | const name_start = buffer.items.len; |
| 1419 | try buffer.writer().print("zig_O_{};\n", .{fmtIdent(fqn)}); | 1382 | try buffer.writer().print("zig_O_{};\n", .{fmtIdent(fqn)}); |
| ... | @@ -1710,9 +1673,11 @@ pub const DeclGen = struct { | ... | @@ -1710,9 +1673,11 @@ pub const DeclGen = struct { |
| 1710 | try w.writeByte('&'); | 1673 | try w.writeByte('&'); |
| 1711 | return dg.renderDeclName(w, decl); | 1674 | return dg.renderDeclName(w, decl); |
| 1712 | }, | 1675 | }, |
| 1713 | .undefined_ptr => return w.print("((void *){x})", .{ | 1676 | .undefined_ptr => |ty| { |
| 1714 | try dg.fmtIntLiteral(Type.usize, UndefInt{}, .Other), | 1677 | try w.writeAll("(("); |
| 1715 | }), | 1678 | try dg.renderTypecast(w, ty); |
| | 1679 | return w.print("){x})", .{try dg.fmtIntLiteral(Type.usize, Value.undef, .Other)}); |
| | 1680 | }, |
| 1716 | .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), | 1681 | .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), |
| 1717 | .bytes => |bytes| return w.writeAll(bytes), | 1682 | .bytes => |bytes| return w.writeAll(bytes), |
| 1718 | } | 1683 | } |
| ... | @@ -1760,19 +1725,19 @@ pub const DeclGen = struct { | ... | @@ -1760,19 +1725,19 @@ pub const DeclGen = struct { |
| 1760 | fn fmtIntLiteral( | 1725 | fn fmtIntLiteral( |
| 1761 | dg: *DeclGen, | 1726 | dg: *DeclGen, |
| 1762 | ty: Type, | 1727 | ty: Type, |
| 1763 | int_val: anytype, | 1728 | val: Value, |
| 1764 | location: ValueRenderLocation, | 1729 | location: ValueRenderLocation, |
| 1765 | ) !IntLiteralFormatter(@TypeOf(int_val)) { | 1730 | ) !std.fmt.Formatter(formatIntLiteral) { |
| 1766 | const target = dg.module.getTarget(); | 1731 | const int_info = ty.intInfo(dg.module.getTarget()); |
| 1767 | const int_info = ty.intInfo(target); | 1732 | const c_bits = toCIntBits(int_info.bits); |
| 1768 | _ = toCIntBits(int_info.bits) orelse | 1733 | if (c_bits == null or c_bits.? > 128) |
| 1769 | return dg.fail("TODO implement integer constants larger than 128 bits", .{}); | 1734 | return dg.fail("TODO implement integer constants larger than 128 bits", .{}); |
| 1770 | return IntLiteralFormatter(@TypeOf(int_val)){ | 1735 | return std.fmt.Formatter(formatIntLiteral){ .data = .{ |
| 1771 | .ty = ty, | 1736 | .ty = ty, |
| 1772 | .target = target, | 1737 | .val = val, |
| 1773 | .int_val = int_val, | 1738 | .mod = dg.module, |
| 1774 | .location = location, | 1739 | .location = location, |
| 1775 | }; | 1740 | } }; |
| 1776 | } | 1741 | } |
| 1777 | }; | 1742 | }; |
| 1778 | | 1743 | |
| ... | @@ -1785,8 +1750,8 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -1785,8 +1750,8 @@ pub fn genErrDecls(o: *Object) !void { |
| 1785 | var max_name_len: usize = 0; | 1750 | var max_name_len: usize = 0; |
| 1786 | for (o.dg.module.error_name_list.items) |name, value| { | 1751 | for (o.dg.module.error_name_list.items) |name, value| { |
| 1787 | max_name_len = std.math.max(name.len, max_name_len); | 1752 | max_name_len = std.math.max(name.len, max_name_len); |
| 1788 | var err_val_payload = Value.Payload.Error{ .data = .{ .name = name } }; | 1753 | var err_val_pl = Value.Payload.Error{ .data = .{ .name = name } }; |
| 1789 | try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_val_payload.base), .Other); | 1754 | try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_val_pl.base), .Other); |
| 1790 | try writer.print(" = {d}u,\n", .{value}); | 1755 | try writer.print(" = {d}u,\n", .{value}); |
| 1791 | } | 1756 | } |
| 1792 | o.indent_writer.popIndent(); | 1757 | o.indent_writer.popIndent(); |
| ... | @@ -1804,14 +1769,14 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -1804,14 +1769,14 @@ pub fn genErrDecls(o: *Object) !void { |
| 1804 | const identifier = name_buf[0 .. name_prefix.len + name.len :0]; | 1769 | const identifier = name_buf[0 .. name_prefix.len + name.len :0]; |
| 1805 | const nameZ = identifier[name_prefix.len..]; | 1770 | const nameZ = identifier[name_prefix.len..]; |
| 1806 | | 1771 | |
| 1807 | var name_ty_payload = Type.Payload.Len{ | 1772 | var name_ty_pl = Type.Payload.Len{ |
| 1808 | .base = .{ .tag = .array_u8_sentinel_0 }, | 1773 | .base = .{ .tag = .array_u8_sentinel_0 }, |
| 1809 | .data = name.len, | 1774 | .data = name.len, |
| 1810 | }; | 1775 | }; |
| 1811 | const name_ty = Type.initPayload(&name_ty_payload.base); | 1776 | const name_ty = Type.initPayload(&name_ty_pl.base); |
| 1812 | | 1777 | |
| 1813 | var name_val_payload = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = nameZ }; | 1778 | var name_val_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = nameZ }; |
| 1814 | const name_val = Value.initPayload(&name_val_payload.base); | 1779 | const name_val = Value.initPayload(&name_val_pl.base); |
| 1815 | | 1780 | |
| 1816 | try writer.writeAll("static "); | 1781 | try writer.writeAll("static "); |
| 1817 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0); | 1782 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0); |
| ... | @@ -1820,11 +1785,11 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -1820,11 +1785,11 @@ pub fn genErrDecls(o: *Object) !void { |
| 1820 | try writer.writeAll(";\n"); | 1785 | try writer.writeAll(";\n"); |
| 1821 | } | 1786 | } |
| 1822 | | 1787 | |
| 1823 | var name_array_ty_payload = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{ | 1788 | var name_array_ty_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{ |
| 1824 | .len = o.dg.module.error_name_list.items.len, | 1789 | .len = o.dg.module.error_name_list.items.len, |
| 1825 | .elem_type = Type.initTag(.const_slice_u8_sentinel_0), | 1790 | .elem_type = Type.initTag(.const_slice_u8_sentinel_0), |
| 1826 | } }; | 1791 | } }; |
| 1827 | const name_array_ty = Type.initPayload(&name_array_ty_payload.base); | 1792 | const name_array_ty = Type.initPayload(&name_array_ty_pl.base); |
| 1828 | | 1793 | |
| 1829 | try writer.writeAll("static "); | 1794 | try writer.writeAll("static "); |
| 1830 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = "zig_errorName" }, .Const, 0); | 1795 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = "zig_errorName" }, .Const, 0); |
| ... | @@ -2363,7 +2328,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2363,7 +2328,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2363 | const elem_type = inst_ty.elemType(); | 2328 | const elem_type = inst_ty.elemType(); |
| 2364 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; | 2329 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; |
| 2365 | if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) { | 2330 | if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 2366 | return CValue.undefined_ptr; | 2331 | return CValue{ .undefined_ptr = inst_ty }; |
| 2367 | } | 2332 | } |
| 2368 | | 2333 | |
| 2369 | const target = f.object.dg.module.getTarget(); | 2334 | const target = f.object.dg.module.getTarget(); |
| ... | @@ -2540,7 +2505,7 @@ fn airStoreUndefined(f: *Function, dest_ptr: CValue) !CValue { | ... | @@ -2540,7 +2505,7 @@ fn airStoreUndefined(f: *Function, dest_ptr: CValue) !CValue { |
| 2540 | const writer = f.object.writer(); | 2505 | const writer = f.object.writer(); |
| 2541 | try writer.writeAll("memset("); | 2506 | try writer.writeAll("memset("); |
| 2542 | try f.writeCValue(writer, dest_ptr); | 2507 | try f.writeCValue(writer, dest_ptr); |
| 2543 | try writer.print(", {x}, sizeof(", .{try f.fmtIntLiteral(Type.u8, UndefInt{})}); | 2508 | try writer.print(", {x}, sizeof(", .{try f.fmtIntLiteral(Type.u8, Value.undef)}); |
| 2544 | try f.writeCValueDeref(writer, dest_ptr); | 2509 | try f.writeCValueDeref(writer, dest_ptr); |
| 2545 | try writer.writeAll("));\n"); | 2510 | try writer.writeAll("));\n"); |
| 2546 | }, | 2511 | }, |
| ... | @@ -2659,9 +2624,22 @@ fn airWrapOp( | ... | @@ -2659,9 +2624,22 @@ fn airWrapOp( |
| 2659 | try f.writeCValue(w, lhs); | 2624 | try f.writeCValue(w, lhs); |
| 2660 | try w.writeAll(", "); | 2625 | try w.writeAll(", "); |
| 2661 | try f.writeCValue(w, rhs); | 2626 | try f.writeCValue(w, rhs); |
| 2662 | if (int_info.signedness == .signed) | 2627 | { |
| 2663 | try w.print(", {}", .{try f.fmtIntLiteral(inst_ty, MinInt{})}); | 2628 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); |
| 2664 | try w.print(", {});", .{try f.fmtIntLiteral(inst_ty, MaxInt{})}); | 2629 | defer arena.deinit(); |
| | 2630 | |
| | 2631 | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| | 2632 | var stack align(@alignOf(expected_contents)) = |
| | 2633 | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); |
| | 2634 | |
| | 2635 | if (int_info.signedness == .signed) { |
| | 2636 | const min_val = try inst_ty.minInt(stack.get(), target); |
| | 2637 | try w.print(", {}", .{try f.fmtIntLiteral(inst_ty, min_val)}); |
| | 2638 | } |
| | 2639 | |
| | 2640 | const max_val = try inst_ty.maxInt(stack.get(), target); |
| | 2641 | try w.print(", {});", .{try f.fmtIntLiteral(inst_ty, max_val)}); |
| | 2642 | } |
| 2665 | try f.object.indent_writer.insertNewline(); | 2643 | try f.object.indent_writer.insertNewline(); |
| 2666 | | 2644 | |
| 2667 | return ret; | 2645 | return ret; |
| ... | @@ -2673,7 +2651,8 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue { | ... | @@ -2673,7 +2651,8 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue { |
| 2673 | | 2651 | |
| 2674 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2652 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2675 | const inst_ty = f.air.typeOfIndex(inst); | 2653 | const inst_ty = f.air.typeOfIndex(inst); |
| 2676 | const int_info = inst_ty.intInfo(f.object.dg.module.getTarget()); | 2654 | const target = f.object.dg.module.getTarget(); |
| | 2655 | const int_info = inst_ty.intInfo(target); |
| 2677 | const bits = int_info.bits; | 2656 | const bits = int_info.bits; |
| 2678 | | 2657 | |
| 2679 | switch (bits) { | 2658 | switch (bits) { |
| ... | @@ -2716,9 +2695,22 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue { | ... | @@ -2716,9 +2695,22 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue { |
| 2716 | try f.writeCValue(w, lhs); | 2695 | try f.writeCValue(w, lhs); |
| 2717 | try w.writeAll(", "); | 2696 | try w.writeAll(", "); |
| 2718 | try f.writeCValue(w, rhs); | 2697 | try f.writeCValue(w, rhs); |
| 2719 | if (int_info.signedness == .signed) | 2698 | { |
| 2720 | try w.print(", {}", .{try f.fmtIntLiteral(inst_ty, MinInt{})}); | 2699 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); |
| 2721 | try w.print(", {});", .{try f.fmtIntLiteral(inst_ty, MaxInt{})}); | 2700 | defer arena.deinit(); |
| | 2701 | |
| | 2702 | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| | 2703 | var stack align(@alignOf(expected_contents)) = |
| | 2704 | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); |
| | 2705 | |
| | 2706 | if (int_info.signedness == .signed) { |
| | 2707 | const min_val = try inst_ty.minInt(stack.get(), target); |
| | 2708 | try w.print(", {}", .{try f.fmtIntLiteral(inst_ty, min_val)}); |
| | 2709 | } |
| | 2710 | |
| | 2711 | const max_val = try inst_ty.maxInt(stack.get(), target); |
| | 2712 | try w.print(", {});", .{try f.fmtIntLiteral(inst_ty, max_val)}); |
| | 2713 | } |
| 2722 | try f.object.indent_writer.insertNewline(); | 2714 | try f.object.indent_writer.insertNewline(); |
| 2723 | | 2715 | |
| 2724 | return ret; | 2716 | return ret; |
| ... | @@ -2756,9 +2748,22 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CV | ... | @@ -2756,9 +2748,22 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CV |
| 2756 | try w.writeAll(", &"); | 2748 | try w.writeAll(", &"); |
| 2757 | try f.writeCValue(w, ret); | 2749 | try f.writeCValue(w, ret); |
| 2758 | try w.writeAll(".field_0, "); | 2750 | try w.writeAll(".field_0, "); |
| 2759 | if (int_info.signedness == .signed) | 2751 | { |
| 2760 | try w.print("{}, ", .{try f.fmtIntLiteral(scalar_ty, MinInt{})}); | 2752 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); |
| 2761 | try w.print("{});", .{try f.fmtIntLiteral(scalar_ty, MaxInt{})}); | 2753 | defer arena.deinit(); |
| | 2754 | |
| | 2755 | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| | 2756 | var stack align(@alignOf(expected_contents)) = |
| | 2757 | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); |
| | 2758 | |
| | 2759 | if (int_info.signedness == .signed) { |
| | 2760 | const min_val = try scalar_ty.minInt(stack.get(), target); |
| | 2761 | try w.print("{}, ", .{try f.fmtIntLiteral(scalar_ty, min_val)}); |
| | 2762 | } |
| | 2763 | |
| | 2764 | const max_val = try scalar_ty.maxInt(stack.get(), target); |
| | 2765 | try w.print("{});", .{try f.fmtIntLiteral(scalar_ty, max_val)}); |
| | 2766 | } |
| 2762 | try f.object.indent_writer.insertNewline(); | 2767 | try f.object.indent_writer.insertNewline(); |
| 2763 | return ret; | 2768 | return ret; |
| 2764 | } | 2769 | } |
| ... | @@ -3360,9 +3365,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3360,9 +3365,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3360 | | 3365 | |
| 3361 | const inputs_extra_begin = extra_i; | 3366 | const inputs_extra_begin = extra_i; |
| 3362 | for (inputs) |input, i| { | 3367 | for (inputs) |input, i| { |
| 3363 | const input_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); | 3368 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); |
| 3364 | const constraint = std.mem.sliceTo(input_bytes, 0); | 3369 | const constraint = std.mem.sliceTo(extra_bytes, 0); |
| 3365 | const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); | 3370 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 3366 | // This equation accounts for the fact that even if we have exactly 4 bytes | 3371 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 3367 | // for the string, we still use the next u32 for the null terminator. | 3372 | // for the string, we still use the next u32 for the null terminator. |
| 3368 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; | 3373 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| ... | @@ -3411,10 +3416,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3411,10 +3416,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3411 | try writer.writeAll(": "); | 3416 | try writer.writeAll(": "); |
| 3412 | extra_i = inputs_extra_begin; | 3417 | extra_i = inputs_extra_begin; |
| 3413 | for (inputs) |_, index| { | 3418 | for (inputs) |_, index| { |
| 3414 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0); | 3419 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); |
| | 3420 | const constraint = std.mem.sliceTo(extra_bytes, 0); |
| | 3421 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 3415 | // This equation accounts for the fact that even if we have exactly 4 bytes | 3422 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 3416 | // for the string, we still use the next u32 for the null terminator. | 3423 | // for the string, we still use the next u32 for the null terminator. |
| 3417 | extra_i += constraint.len / 4 + 1; | 3424 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 3418 | | 3425 | |
| 3419 | if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') { | 3426 | if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') { |
| 3420 | const reg = constraint[1 .. constraint.len - 1]; | 3427 | const reg = constraint[1 .. constraint.len - 1]; |
| ... | @@ -3511,11 +3518,10 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3511,11 +3518,10 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3511 | const operand = try f.resolveInst(ty_op.operand); | 3518 | const operand = try f.resolveInst(ty_op.operand); |
| 3512 | const ptr_ty = f.air.typeOf(ty_op.operand); | 3519 | const ptr_ty = f.air.typeOf(ty_op.operand); |
| 3513 | const opt_ty = ptr_ty.childType(); | 3520 | const opt_ty = ptr_ty.childType(); |
| 3514 | var buf: Type.Payload.ElemType = undefined; | 3521 | const inst_ty = f.air.typeOfIndex(inst); |
| 3515 | const payload_ty = opt_ty.optionalChild(&buf); | | |
| 3516 | | 3522 | |
| 3517 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3523 | if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) { |
| 3518 | return CValue.undefined_ptr; | 3524 | return CValue{ .undefined_ptr = inst_ty }; |
| 3519 | } | 3525 | } |
| 3520 | | 3526 | |
| 3521 | if (opt_ty.optionalReprIsPayload()) { | 3527 | if (opt_ty.optionalReprIsPayload()) { |
| ... | @@ -3524,7 +3530,6 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3524,7 +3530,6 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3524 | return operand; | 3530 | return operand; |
| 3525 | } | 3531 | } |
| 3526 | | 3532 | |
| 3527 | const inst_ty = f.air.typeOfIndex(inst); | | |
| 3528 | const local = try f.allocLocal(inst_ty, .Const); | 3533 | const local = try f.allocLocal(inst_ty, .Const); |
| 3529 | try writer.writeAll(" = &("); | 3534 | try writer.writeAll(" = &("); |
| 3530 | try f.writeCValue(writer, operand); | 3535 | try f.writeCValue(writer, operand); |
| ... | @@ -3892,7 +3897,8 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3892,7 +3897,8 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3892 | if (operand == .undefined_ptr) { | 3897 | if (operand == .undefined_ptr) { |
| 3893 | // Unfortunately, C does not support any equivalent to | 3898 | // Unfortunately, C does not support any equivalent to |
| 3894 | // &(*(void *)p)[0], although LLVM does via GetElementPtr | 3899 | // &(*(void *)p)[0], although LLVM does via GetElementPtr |
| 3895 | try f.writeCValue(writer, CValue.undefined_ptr); | 3900 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| | 3901 | try f.writeCValue(writer, CValue{ .undefined_ptr = inst_ty.slicePtrFieldType(&buf) }); |
| 3896 | } else { | 3902 | } else { |
| 3897 | try writer.writeAll("&("); | 3903 | try writer.writeAll("&("); |
| 3898 | try f.writeCValueDeref(writer, operand); | 3904 | try f.writeCValueDeref(writer, operand); |
| ... | @@ -4478,148 +4484,186 @@ fn signAbbrev(signedness: std.builtin.Signedness) u8 { | ... | @@ -4478,148 +4484,186 @@ fn signAbbrev(signedness: std.builtin.Signedness) u8 { |
| 4478 | }; | 4484 | }; |
| 4479 | } | 4485 | } |
| 4480 | | 4486 | |
| 4481 | const UndefInt = struct { | 4487 | const FormatIntLiteralContext = struct { |
| 4482 | pub fn to(_: UndefInt, comptime T: type) error{}!T { | 4488 | ty: Type, |
| 4483 | comptime { | 4489 | val: Value, |
| 4484 | if (@bitSizeOf(T) < 2) return 0; | 4490 | mod: *Module, |
| 4485 | var value: T = 2; | 4491 | location: ValueRenderLocation, |
| 4486 | var shift = 2; | | |
| 4487 | while (shift < @bitSizeOf(T)) : (shift <<= 1) | | |
| 4488 | value |= value << shift; | | |
| 4489 | return value; | | |
| 4490 | } | | |
| 4491 | } | | |
| 4492 | }; | | |
| 4493 | const MaxInt = struct { | | |
| 4494 | pub fn to(_: MaxInt, comptime T: type) error{}!T { | | |
| 4495 | return std.math.maxInt(T); | | |
| 4496 | } | | |
| 4497 | }; | | |
| 4498 | const MinInt = struct { | | |
| 4499 | pub fn to(_: MinInt, comptime T: type) error{}!T { | | |
| 4500 | return std.math.minInt(T); | | |
| 4501 | } | | |
| 4502 | }; | 4492 | }; |
| | 4493 | fn formatIntLiteral( |
| | 4494 | data: FormatIntLiteralContext, |
| | 4495 | comptime fmt: []const u8, |
| | 4496 | options: std.fmt.FormatOptions, |
| | 4497 | writer: anytype, |
| | 4498 | ) @TypeOf(writer).Error!void { |
| | 4499 | const target = data.mod.getTarget(); |
| | 4500 | const int_info = data.ty.intInfo(target); |
| | 4501 | |
| | 4502 | const Limb = std.math.big.Limb; |
| | 4503 | const expected_contents = struct { |
| | 4504 | const base = 10; |
| | 4505 | const limbs_count_128 = BigInt.calcTwosCompLimbCount(128); |
| | 4506 | const expected_needed_limbs_count = BigInt.calcToStringLimbsBufferLen(limbs_count_128, base); |
| | 4507 | const worst_case_int = BigInt.Const{ |
| | 4508 | .limbs = &([1]Limb{std.math.maxInt(Limb)} ** expected_needed_limbs_count), |
| | 4509 | .positive = false, |
| | 4510 | }; |
| 4503 | | 4511 | |
| 4504 | fn IntLiteralFormatter(comptime IntType: type) type { | 4512 | undef_limbs: [limbs_count_128]Limb, |
| 4505 | return struct { | 4513 | str: [worst_case_int.sizeInBaseUpperBound(base)]u8, |
| 4506 | ty: Type, | 4514 | limbs_limbs: [expected_needed_limbs_count]Limb, |
| 4507 | target: std.Target, | 4515 | }; |
| 4508 | int_val: IntType, | 4516 | var stack align(@alignOf(expected_contents)) = |
| 4509 | location: ValueRenderLocation, | 4517 | std.heap.stackFallback(@sizeOf(expected_contents), data.mod.gpa); |
| | 4518 | const allocator = stack.get(); |
| 4510 | | 4519 | |
| 4511 | fn formatHelper( | 4520 | var undef_limbs: []Limb = &.{}; |
| 4512 | self: @This(), | 4521 | defer allocator.free(undef_limbs); |
| 4513 | comptime CIntType: type, | | |
| 4514 | comptime fmt: []const u8, | | |
| 4515 | options: std.fmt.FormatOptions, | | |
| 4516 | writer: anytype, | | |
| 4517 | ) !void { | | |
| 4518 | const c_int_info = @typeInfo(CIntType).Int; | | |
| 4519 | const c_int_val = switch (@typeInfo(IntType)) { | | |
| 4520 | .Int => @intCast(CIntType, self.int_val), | | |
| 4521 | .Struct, .Pointer => self.int_val.to(CIntType) catch unreachable, | | |
| 4522 | else => unreachable, | | |
| 4523 | }; | | |
| 4524 | const c_abs_val = std.math.absCast(c_int_val); | | |
| 4525 | if (self.location == .Identifier) { | | |
| 4526 | if (c_int_val < 0) try writer.writeAll("_N"); | | |
| 4527 | try writer.print("{d}", .{c_abs_val}); | | |
| 4528 | } else if (c_int_info.bits == 128) { | | |
| 4529 | // Clang and GCC don't support 128-bit integer constants but | | |
| 4530 | // will hopefully unfold them if we construct one manually. | | |
| 4531 | //std.debug.todo("128-bit is unimplemented"); | | |
| 4532 | try writer.writeByte('('); | | |
| 4533 | if (c_int_info.signedness == .signed) { | | |
| 4534 | try writer.writeAll("(int128_t)"); | | |
| 4535 | if (c_int_val < 0) try writer.writeByte('-'); | | |
| 4536 | } | | |
| 4537 | | 4522 | |
| 4538 | const upper = @intCast(u64, c_abs_val >> 64); | 4523 | var int_buf: Value.BigIntSpace = undefined; |
| 4539 | if (upper != 0) try writer.writeByte('('); | 4524 | const int = if (data.val.isUndefDeep()) blk: { |
| 4540 | if (upper != 0 or c_int_val < 0) try writer.writeAll("(uint128_t)"); | 4525 | undef_limbs = try allocator.alloc(Limb, BigInt.calcTwosCompLimbCount(int_info.bits)); |
| 4541 | if (upper != 0) { | | |
| 4542 | try (IntLiteralFormatter(u64){ | | |
| 4543 | .ty = Type.u64, | | |
| 4544 | .target = self.target, | | |
| 4545 | .int_val = upper, | | |
| 4546 | .location = self.location, | | |
| 4547 | }).formatHelper(u64, fmt, options, writer); | | |
| 4548 | try writer.writeAll("<<64|"); | | |
| 4549 | } | | |
| 4550 | | 4526 | |
| 4551 | const lower = @truncate(u64, c_abs_val); | 4527 | const undef_pattern: Limb = (1 << (@bitSizeOf(Limb) | 1)) / 3; |
| 4552 | try (IntLiteralFormatter(u64){ | 4528 | std.mem.set(Limb, undef_limbs, undef_pattern); |
| 4553 | .ty = Type.u64, | | |
| 4554 | .target = self.target, | | |
| 4555 | .int_val = lower, | | |
| 4556 | .location = self.location, | | |
| 4557 | }).formatHelper(u64, fmt, options, writer); | | |
| 4558 | | 4529 | |
| 4559 | if (upper != 0) try writer.writeByte(')'); | 4530 | var undef_int = BigInt.Mutable{ |
| 4560 | try writer.writeByte(')'); | 4531 | .limbs = undef_limbs, |
| 4561 | } else if (c_int_val == std.math.maxInt(CIntType) or | 4532 | .len = undef_limbs.len, |
| 4562 | c_int_info.signedness == .signed and c_int_val == std.math.minInt(CIntType)) | 4533 | .positive = true, |
| 4563 | { | 4534 | }; |
| 4564 | if (c_int_info.signedness == .unsigned) try writer.writeByte('U'); | 4535 | undef_int.truncate(undef_int.toConst(), int_info.signedness, int_info.bits); |
| 4565 | try writer.writeAll(switch (self.ty.tag()) { | 4536 | break :blk undef_int.toConst(); |
| 4566 | .c_short, .c_ushort => "SHRT", | 4537 | } else data.val.toBigInt(&int_buf, target); |
| 4567 | .c_int, .c_uint => "INT", | 4538 | assert(int.fitsInTwosComp(int_info.signedness, int_info.bits)); |
| 4568 | .c_long, .c_ulong => "LONG", | 4539 | |
| 4569 | .c_longlong, .c_ulonglong => "LLONG", | 4540 | if (data.location == .Identifier) { |
| 4570 | .isize, .usize => "INTPTR", | 4541 | const str = try int.toStringAlloc(allocator, 10, undefined); |
| 4571 | else => std.fmt.comptimePrint("INT{d}", .{c_int_info.bits}), | 4542 | defer allocator.free(str); |
| 4572 | }); | 4543 | |
| 4573 | try writer.writeAll(if (c_int_val < 0) "_MIN" else "_MAX"); | 4544 | return writer.writeAll(str); |
| 4574 | } else { | 4545 | } |
| 4575 | if (c_int_val < 0) try writer.writeByte('-'); | 4546 | |
| 4576 | if (c_int_info.signedness == .unsigned) try writer.writeByte('U'); | 4547 | const limbs_count_64 = @divExact(64, @bitSizeOf(Limb)); |
| 4577 | try writer.print("INT{d}_C(" ++ switch (fmt.len) { | 4548 | const c_bits = toCIntBits(int_info.bits) orelse unreachable; |
| 4578 | 0 => "{d}", | 4549 | if (c_bits == 128) { |
| 4579 | 1 => switch (fmt[0]) { | 4550 | // Clang and GCC don't support 128-bit integer constants but |
| 4580 | 'o' => "0{o}", | 4551 | // will hopefully unfold them if we construct one manually. |
| 4581 | 'd' => "{d}", | 4552 | //std.debug.todo("128-bit is unimplemented"); |
| 4582 | 'x' => "0x{x}", | 4553 | try writer.writeByte('('); |
| 4583 | 'X' => "0x{X}", | 4554 | if (int_info.signedness == .signed) { |
| 4584 | else => @compileError("Invalid fmt: " ++ fmt), | 4555 | try writer.writeAll("(int128_t)"); |
| 4585 | }, | 4556 | if (!int.positive) try writer.writeByte('-'); |
| 4586 | else => @compileError("Invalid fmt: " ++ fmt), | | |
| 4587 | } ++ ")", .{ c_int_info.bits, c_abs_val }); | | |
| 4588 | } | | |
| 4589 | } | 4557 | } |
| 4590 | | 4558 | |
| 4591 | pub fn format( | 4559 | const split = std.math.min(int.limbs.len, limbs_count_64); |
| 4592 | self: @This(), | 4560 | var upper_val_pl = Value.Payload.BigInt{ |
| 4593 | comptime fmt: []const u8, | 4561 | .base = .{ .tag = .int_big_positive }, |
| 4594 | options: std.fmt.FormatOptions, | 4562 | .data = int.limbs[split..], |
| 4595 | writer: anytype, | 4563 | }; |
| 4596 | ) !void { | 4564 | const have_upper = !upper_val_pl.asBigInt().eqZero(); |
| 4597 | const int_info = self.ty.intInfo(self.target); | 4565 | if (have_upper) try writer.writeByte('('); |
| 4598 | switch (toCIntBits(int_info.bits).?) { | 4566 | if (have_upper or !int.positive) try writer.writeAll("(uint128_t)"); |
| 4599 | 8 => switch (int_info.signedness) { | 4567 | if (have_upper) { |
| 4600 | .signed => try self.formatHelper(i8, fmt, options, writer), | 4568 | const upper_val = Value.initPayload(&upper_val_pl.base); |
| 4601 | .unsigned => try self.formatHelper(u8, fmt, options, writer), | 4569 | try formatIntLiteral(.{ |
| 4602 | }, | 4570 | .ty = Type.u64, |
| 4603 | 16 => switch (int_info.signedness) { | 4571 | .val = upper_val, |
| 4604 | .signed => try self.formatHelper(i16, fmt, options, writer), | 4572 | .mod = data.mod, |
| 4605 | .unsigned => try self.formatHelper(u16, fmt, options, writer), | 4573 | .location = data.location, |
| 4606 | }, | 4574 | }, fmt, options, writer); |
| 4607 | 32 => switch (int_info.signedness) { | 4575 | try writer.writeAll("<<64|"); |
| 4608 | .signed => try self.formatHelper(i32, fmt, options, writer), | | |
| 4609 | .unsigned => try self.formatHelper(u32, fmt, options, writer), | | |
| 4610 | }, | | |
| 4611 | 64 => switch (int_info.signedness) { | | |
| 4612 | .signed => try self.formatHelper(i64, fmt, options, writer), | | |
| 4613 | .unsigned => try self.formatHelper(u64, fmt, options, writer), | | |
| 4614 | }, | | |
| 4615 | 128 => switch (int_info.signedness) { | | |
| 4616 | .signed => try self.formatHelper(i128, fmt, options, writer), | | |
| 4617 | .unsigned => try self.formatHelper(u128, fmt, options, writer), | | |
| 4618 | }, | | |
| 4619 | else => unreachable, | | |
| 4620 | } | | |
| 4621 | } | 4576 | } |
| 4622 | }; | 4577 | |
| | 4578 | var lower_val_pl = Value.Payload.BigInt{ |
| | 4579 | .base = .{ .tag = .int_big_positive }, |
| | 4580 | .data = int.limbs[0..split], |
| | 4581 | }; |
| | 4582 | const lower_val = Value.initPayload(&lower_val_pl.base); |
| | 4583 | try formatIntLiteral(.{ |
| | 4584 | .ty = Type.u64, |
| | 4585 | .val = lower_val, |
| | 4586 | .mod = data.mod, |
| | 4587 | .location = data.location, |
| | 4588 | }, fmt, options, writer); |
| | 4589 | |
| | 4590 | if (have_upper) try writer.writeByte(')'); |
| | 4591 | return writer.writeByte(')'); |
| | 4592 | } |
| | 4593 | |
| | 4594 | assert(c_bits <= 64); |
| | 4595 | var one_limbs: [BigInt.calcLimbLen(1)]Limb = undefined; |
| | 4596 | const one = BigInt.Mutable.init(&one_limbs, 1).toConst(); |
| | 4597 | |
| | 4598 | var wrap_limbs: [BigInt.calcTwosCompLimbCount(64)]Limb = undefined; |
| | 4599 | var wrap = BigInt.Mutable{ .limbs = &wrap_limbs, .len = undefined, .positive = undefined }; |
| | 4600 | if (wrap.addWrap(int, one, int_info.signedness, c_bits) or |
| | 4601 | int_info.signedness == .signed and wrap.subWrap(int, one, int_info.signedness, c_bits)) |
| | 4602 | { |
| | 4603 | if (int_info.signedness == .unsigned) try writer.writeByte('U'); |
| | 4604 | switch (data.ty.tag()) { |
| | 4605 | .c_short, .c_ushort => try writer.writeAll("SHRT"), |
| | 4606 | .c_int, .c_uint => try writer.writeAll("INT"), |
| | 4607 | .c_long, .c_ulong => try writer.writeAll("LONG"), |
| | 4608 | .c_longlong, .c_ulonglong => try writer.writeAll("LLONG"), |
| | 4609 | .isize, .usize => try writer.writeAll("INTPTR"), |
| | 4610 | else => try writer.print("INT{d}", .{c_bits}), |
| | 4611 | } |
| | 4612 | try writer.writeAll(if (int.positive) "_MAX" else "_MIN"); |
| | 4613 | return; |
| | 4614 | } |
| | 4615 | |
| | 4616 | if (!int.positive) try writer.writeByte('-'); |
| | 4617 | switch (data.ty.tag()) { |
| | 4618 | .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {}, |
| | 4619 | else => { |
| | 4620 | if (int_info.signedness == .unsigned) try writer.writeByte('U'); |
| | 4621 | try writer.print("INT{d}_C(", .{c_bits}); |
| | 4622 | }, |
| | 4623 | } |
| | 4624 | |
| | 4625 | var base: u8 = undefined; |
| | 4626 | var case: std.fmt.Case = undefined; |
| | 4627 | switch (fmt.len) { |
| | 4628 | 0 => base = 10, |
| | 4629 | 1 => switch (fmt[0]) { |
| | 4630 | 'b' => { |
| | 4631 | base = 2; |
| | 4632 | try writer.writeAll("0b"); |
| | 4633 | }, |
| | 4634 | 'o' => { |
| | 4635 | base = 8; |
| | 4636 | try writer.writeByte('0'); |
| | 4637 | }, |
| | 4638 | 'd' => base = 10, |
| | 4639 | 'x' => { |
| | 4640 | base = 16; |
| | 4641 | case = .lower; |
| | 4642 | try writer.writeAll("0x"); |
| | 4643 | }, |
| | 4644 | 'X' => { |
| | 4645 | base = 16; |
| | 4646 | case = .upper; |
| | 4647 | try writer.writeAll("0x"); |
| | 4648 | }, |
| | 4649 | else => @compileError("Invalid fmt: " ++ fmt), |
| | 4650 | }, |
| | 4651 | else => @compileError("Invalid fmt: " ++ fmt), |
| | 4652 | } |
| | 4653 | |
| | 4654 | var str: [64]u8 = undefined; |
| | 4655 | var limbs_buf: [BigInt.calcToStringLimbsBufferLen(limbs_count_64, 10)]Limb = undefined; |
| | 4656 | try writer.writeAll(str[0..int.abs().toString(&str, base, case, &limbs_buf)]); |
| | 4657 | |
| | 4658 | switch (data.ty.tag()) { |
| | 4659 | .c_short, .c_ushort, .c_int => {}, |
| | 4660 | .c_uint => try writer.writeAll("u"), |
| | 4661 | .c_long => try writer.writeAll("l"), |
| | 4662 | .c_ulong => try writer.writeAll("ul"), |
| | 4663 | .c_longlong => try writer.writeAll("ll"), |
| | 4664 | .c_ulonglong => try writer.writeAll("ull"), |
| | 4665 | else => try writer.writeByte(')'), |
| | 4666 | } |
| 4623 | } | 4667 | } |
| 4624 | | 4668 | |
| 4625 | fn loweredFnRetTyHasBits(fn_ty: Type) bool { | 4669 | fn loweredFnRetTyHasBits(fn_ty: Type) bool { |