| ... | ... | @@ -19,7 +19,7 @@ const Liveness = @import("../Liveness.zig"); |
| 19 | 19 | const CType = @import("../type.zig").CType; |
| 20 | 20 | |
| 21 | 21 | const Mutability = enum { Const, Mut }; |
| 22 | | const BigIntConst = std.math.big.int.Const; |
| 22 | const BigInt = std.math.big.int; |
| 23 | 23 | |
| 24 | 24 | pub const CValue = union(enum) { |
| 25 | 25 | none: void, |
| ... | ... | @@ -35,7 +35,7 @@ pub const CValue = union(enum) { |
| 35 | 35 | decl: Decl.Index, |
| 36 | 36 | decl_ref: Decl.Index, |
| 37 | 37 | /// An undefined (void *) pointer (cannot be dereferenced) |
| 38 | | undefined_ptr: void, |
| 38 | undefined_ptr: Type, |
| 39 | 39 | /// Render the slice as an identifier (using fmtIdent) |
| 40 | 40 | identifier: []const u8, |
| 41 | 41 | /// Render these bytes literally. |
| ... | ... | @@ -74,11 +74,11 @@ fn formatTypeAsCIdentifier( |
| 74 | 74 | options: std.fmt.FormatOptions, |
| 75 | 75 | writer: anytype, |
| 76 | 76 | ) !void { |
| 77 | | _ = fmt; |
| 78 | | _ = options; |
| 79 | | var buffer = [1]u8{0} ** 128; |
| 80 | | var buf = std.fmt.bufPrint(&buffer, "{}", .{data.ty.fmt(data.mod)}) catch &buffer; |
| 81 | | return formatIdent(buf, "", .{}, writer); |
| 77 | var stack = std.heap.stackFallback(128, data.mod.gpa); |
| 78 | const allocator = stack.get(); |
| 79 | const str = std.fmt.allocPrint(allocator, "{}", .{data.ty.fmt(data.mod)}) catch ""; |
| 80 | defer allocator.free(str); |
| 81 | return formatIdent(str, fmt, options, writer); |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsCIdentifier) { |
| ... | ... | @@ -332,8 +332,8 @@ pub const Function = struct { |
| 332 | 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)) { |
| 336 | | return f.object.dg.fmtIntLiteral(ty, int_val, .Other); |
| 335 | fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) { |
| 336 | return f.object.dg.fmtIntLiteral(ty, val, .Other); |
| 337 | 337 | } |
| 338 | 338 | }; |
| 339 | 339 | |
| ... | ... | @@ -423,51 +423,6 @@ pub const DeclGen = struct { |
| 423 | 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 | 426 | // Renders a "parent" pointer by recursing to the root decl/variable |
| 472 | 427 | // that its contents are defined with respect to. |
| 473 | 428 | // |
| ... | ... | @@ -578,14 +533,14 @@ pub const DeclGen = struct { |
| 578 | 533 | .Enum, |
| 579 | 534 | .ErrorSet, |
| 580 | 535 | => return writer.print("{x}", .{ |
| 581 | | try dg.fmtIntLiteral(ty, UndefInt{}, location), |
| 536 | try dg.fmtIntLiteral(ty, val, location), |
| 582 | 537 | }), |
| 583 | 538 | .Float => switch (ty.tag()) { |
| 584 | 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 | 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 | 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 | 548 | .Slice => { |
| 594 | 549 | try writer.writeByte('('); |
| 595 | 550 | try dg.renderTypecast(writer, ty); |
| 596 | | return writer.print("){{(void *){x}, {0x}}}", .{ |
| 597 | | try dg.fmtIntLiteral(Type.usize, UndefInt{}, location), |
| 551 | try writer.writeAll("){("); |
| 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})", .{ |
| 601 | | try dg.fmtIntLiteral(Type.usize, UndefInt{}, location), |
| 602 | | }), |
| 559 | .Many, .C, .One => { |
| 560 | try writer.writeAll("(("); |
| 561 | try dg.renderTypecast(writer, ty); |
| 562 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, location)}); |
| 563 | }, |
| 603 | 564 | }, |
| 604 | 565 | .Optional => { |
| 605 | 566 | var opt_buf: Type.Payload.ElemType = undefined; |
| ... | ... | @@ -636,7 +597,7 @@ pub const DeclGen = struct { |
| 636 | 597 | empty = false; |
| 637 | 598 | } |
| 638 | 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 | 603 | return writer.writeByte('}'); |
| ... | ... | @@ -651,7 +612,7 @@ pub const DeclGen = struct { |
| 651 | 612 | try dg.renderValue(writer, field.ty, val, location); |
| 652 | 613 | break; |
| 653 | 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 | 618 | return writer.writeByte('}'); |
| ... | ... | @@ -662,7 +623,7 @@ pub const DeclGen = struct { |
| 662 | 623 | try writer.writeAll("){ .payload = "); |
| 663 | 624 | try dg.renderValue(writer, ty.errorUnionPayload(), val, location); |
| 664 | 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 | 629 | .Array => { |
| ... | ... | @@ -696,15 +657,10 @@ pub const DeclGen = struct { |
| 696 | 657 | @tagName(tag), |
| 697 | 658 | }), |
| 698 | 659 | } |
| 660 | unreachable; |
| 699 | 661 | } |
| 700 | 662 | switch (ty.zigTypeTag()) { |
| 701 | 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 | 664 | .field_ptr, |
| 709 | 665 | .elem_ptr, |
| 710 | 666 | .opt_payload_ptr, |
| ... | ... | @@ -712,32 +668,35 @@ pub const DeclGen = struct { |
| 712 | 668 | .decl_ref_mut, |
| 713 | 669 | .decl_ref, |
| 714 | 670 | => try dg.renderParentPtr(writer, val, ty), |
| 715 | | else => if (ty.isSignedInt()) |
| 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 | | }), |
| 671 | else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, location)}), |
| 721 | 672 | }, |
| 722 | 673 | .Float => { |
| 723 | 674 | if (ty.floatBits(target) <= 64) { |
| 724 | 675 | if (std.math.isNan(val.toFloat(f64)) or std.math.isInf(val.toFloat(f64))) { |
| 725 | 676 | // just generate a bit cast (exactly like we do in airBitcast) |
| 726 | 677 | switch (ty.tag()) { |
| 727 | | .f32 => return writer.print("zig_bitcast_f32_u32({x})", .{ |
| 728 | | try dg.fmtIntLiteral( |
| 678 | .f32 => { |
| 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 | 684 | Type.u32, |
| 730 | | @bitCast(u32, val.toFloat(f32)), |
| 685 | Value.initPayload(&bitcast_val_pl.base), |
| 731 | 686 | location, |
| 732 | | ), |
| 733 | | }), |
| 734 | | .f64 => return writer.print("zig_bitcast_f64_u64({x})", .{ |
| 735 | | try dg.fmtIntLiteral( |
| 687 | )}); |
| 688 | }, |
| 689 | .f64 => { |
| 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 | 695 | Type.u64, |
| 737 | | @bitCast(u64, val.toFloat(f64)), |
| 696 | Value.initPayload(&bitcast_val_pl.base), |
| 738 | 697 | location, |
| 739 | | ), |
| 740 | | }), |
| 698 | )}); |
| 699 | }, |
| 741 | 700 | else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}), |
| 742 | 701 | } |
| 743 | 702 | } else { |
| ... | ... | @@ -779,9 +738,7 @@ pub const DeclGen = struct { |
| 779 | 738 | .int_u64, .one => { |
| 780 | 739 | try writer.writeAll("(("); |
| 781 | 740 | try dg.renderTypecast(writer, ty); |
| 782 | | return writer.print("){x})", .{ |
| 783 | | try dg.fmtIntLiteral(Type.usize, val.toUnsignedInt(target), location), |
| 784 | | }); |
| 741 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, location)}); |
| 785 | 742 | }, |
| 786 | 743 | .field_ptr, |
| 787 | 744 | .elem_ptr, |
| ... | ... | @@ -1069,7 +1026,7 @@ pub const DeclGen = struct { |
| 1069 | 1026 | try bw.writeAll(" (*"); |
| 1070 | 1027 | |
| 1071 | 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 | 1030 | const name_end = buffer.items.len - 2; |
| 1074 | 1031 | |
| 1075 | 1032 | const param_len = fn_info.param_types.len; |
| ... | ... | @@ -1124,13 +1081,16 @@ pub const DeclGen = struct { |
| 1124 | 1081 | try bw.writeAll("; size_t len; } "); |
| 1125 | 1082 | const name_index = buffer.items.len; |
| 1126 | 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 | 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 | 1088 | if (ptr_sentinel) |s| { |
| 1132 | | try bw.writeAll("_s_"); |
| 1133 | | try dg.renderValue(bw, child_type, s, .Identifier); |
| 1089 | var sentinel_buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 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 | 1095 | try bw.writeAll(";\n"); |
| 1136 | 1096 | |
| ... | ... | @@ -1327,7 +1287,7 @@ pub const DeclGen = struct { |
| 1327 | 1287 | try dg.renderDeclName(bw, func.owner_decl); |
| 1328 | 1288 | try bw.writeAll(";\n"); |
| 1329 | 1289 | } else { |
| 1330 | | try bw.print("zig_E_{s}_{s};\n", .{ |
| 1290 | try bw.print("zig_E_{}_{};\n", .{ |
| 1331 | 1291 | typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module), |
| 1332 | 1292 | }); |
| 1333 | 1293 | } |
| ... | ... | @@ -1356,10 +1316,13 @@ pub const DeclGen = struct { |
| 1356 | 1316 | try dg.renderType(bw, elem_type); |
| 1357 | 1317 | |
| 1358 | 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 | 1320 | if (t.sentinel()) |s| { |
| 1361 | | try bw.writeAll("_s_"); |
| 1362 | | try dg.renderValue(bw, elem_type, s, .Identifier); |
| 1321 | var sentinel_buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 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 | 1327 | const name_end = buffer.items.len; |
| 1365 | 1328 | |
| ... | ... | @@ -1389,7 +1352,7 @@ pub const DeclGen = struct { |
| 1389 | 1352 | try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); |
| 1390 | 1353 | try bw.writeAll("; bool is_null; } "); |
| 1391 | 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 | 1357 | const rendered = buffer.toOwnedSlice(); |
| 1395 | 1358 | errdefer dg.typedefs.allocator.free(rendered); |
| ... | ... | @@ -1413,7 +1376,7 @@ pub const DeclGen = struct { |
| 1413 | 1376 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1414 | 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 | 1381 | const name_start = buffer.items.len; |
| 1419 | 1382 | try buffer.writer().print("zig_O_{};\n", .{fmtIdent(fqn)}); |
| ... | ... | @@ -1710,9 +1673,11 @@ pub const DeclGen = struct { |
| 1710 | 1673 | try w.writeByte('&'); |
| 1711 | 1674 | return dg.renderDeclName(w, decl); |
| 1712 | 1675 | }, |
| 1713 | | .undefined_ptr => return w.print("((void *){x})", .{ |
| 1714 | | try dg.fmtIntLiteral(Type.usize, UndefInt{}, .Other), |
| 1715 | | }), |
| 1676 | .undefined_ptr => |ty| { |
| 1677 | try w.writeAll("(("); |
| 1678 | try dg.renderTypecast(w, ty); |
| 1679 | return w.print("){x})", .{try dg.fmtIntLiteral(Type.usize, Value.undef, .Other)}); |
| 1680 | }, |
| 1716 | 1681 | .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), |
| 1717 | 1682 | .bytes => |bytes| return w.writeAll(bytes), |
| 1718 | 1683 | } |
| ... | ... | @@ -1760,19 +1725,19 @@ pub const DeclGen = struct { |
| 1760 | 1725 | fn fmtIntLiteral( |
| 1761 | 1726 | dg: *DeclGen, |
| 1762 | 1727 | ty: Type, |
| 1763 | | int_val: anytype, |
| 1728 | val: Value, |
| 1764 | 1729 | location: ValueRenderLocation, |
| 1765 | | ) !IntLiteralFormatter(@TypeOf(int_val)) { |
| 1766 | | const target = dg.module.getTarget(); |
| 1767 | | const int_info = ty.intInfo(target); |
| 1768 | | _ = toCIntBits(int_info.bits) orelse |
| 1730 | ) !std.fmt.Formatter(formatIntLiteral) { |
| 1731 | const int_info = ty.intInfo(dg.module.getTarget()); |
| 1732 | const c_bits = toCIntBits(int_info.bits); |
| 1733 | if (c_bits == null or c_bits.? > 128) |
| 1769 | 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 | 1736 | .ty = ty, |
| 1772 | | .target = target, |
| 1773 | | .int_val = int_val, |
| 1737 | .val = val, |
| 1738 | .mod = dg.module, |
| 1774 | 1739 | .location = location, |
| 1775 | | }; |
| 1740 | } }; |
| 1776 | 1741 | } |
| 1777 | 1742 | }; |
| 1778 | 1743 | |
| ... | ... | @@ -1785,8 +1750,8 @@ pub fn genErrDecls(o: *Object) !void { |
| 1785 | 1750 | var max_name_len: usize = 0; |
| 1786 | 1751 | for (o.dg.module.error_name_list.items) |name, value| { |
| 1787 | 1752 | max_name_len = std.math.max(name.len, max_name_len); |
| 1788 | | var err_val_payload = Value.Payload.Error{ .data = .{ .name = name } }; |
| 1789 | | try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_val_payload.base), .Other); |
| 1753 | var err_val_pl = Value.Payload.Error{ .data = .{ .name = name } }; |
| 1754 | try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_val_pl.base), .Other); |
| 1790 | 1755 | try writer.print(" = {d}u,\n", .{value}); |
| 1791 | 1756 | } |
| 1792 | 1757 | o.indent_writer.popIndent(); |
| ... | ... | @@ -1804,14 +1769,14 @@ pub fn genErrDecls(o: *Object) !void { |
| 1804 | 1769 | const identifier = name_buf[0 .. name_prefix.len + name.len :0]; |
| 1805 | 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 | 1773 | .base = .{ .tag = .array_u8_sentinel_0 }, |
| 1809 | 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 }; |
| 1814 | | const name_val = Value.initPayload(&name_val_payload.base); |
| 1778 | var name_val_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = nameZ }; |
| 1779 | const name_val = Value.initPayload(&name_val_pl.base); |
| 1815 | 1780 | |
| 1816 | 1781 | try writer.writeAll("static "); |
| 1817 | 1782 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0); |
| ... | ... | @@ -1820,11 +1785,11 @@ pub fn genErrDecls(o: *Object) !void { |
| 1820 | 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 | 1789 | .len = o.dg.module.error_name_list.items.len, |
| 1825 | 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 | 1794 | try writer.writeAll("static "); |
| 1830 | 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 | 2328 | const elem_type = inst_ty.elemType(); |
| 2364 | 2329 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; |
| 2365 | 2330 | if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 2366 | | return CValue.undefined_ptr; |
| 2331 | return CValue{ .undefined_ptr = inst_ty }; |
| 2367 | 2332 | } |
| 2368 | 2333 | |
| 2369 | 2334 | const target = f.object.dg.module.getTarget(); |
| ... | ... | @@ -2540,7 +2505,7 @@ fn airStoreUndefined(f: *Function, dest_ptr: CValue) !CValue { |
| 2540 | 2505 | const writer = f.object.writer(); |
| 2541 | 2506 | try writer.writeAll("memset("); |
| 2542 | 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 | 2509 | try f.writeCValueDeref(writer, dest_ptr); |
| 2545 | 2510 | try writer.writeAll("));\n"); |
| 2546 | 2511 | }, |
| ... | ... | @@ -2659,9 +2624,22 @@ fn airWrapOp( |
| 2659 | 2624 | try f.writeCValue(w, lhs); |
| 2660 | 2625 | try w.writeAll(", "); |
| 2661 | 2626 | try f.writeCValue(w, rhs); |
| 2662 | | if (int_info.signedness == .signed) |
| 2663 | | try w.print(", {}", .{try f.fmtIntLiteral(inst_ty, MinInt{})}); |
| 2664 | | try w.print(", {});", .{try f.fmtIntLiteral(inst_ty, MaxInt{})}); |
| 2627 | { |
| 2628 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); |
| 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 | 2643 | try f.object.indent_writer.insertNewline(); |
| 2666 | 2644 | |
| 2667 | 2645 | return ret; |
| ... | ... | @@ -2673,7 +2651,8 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue { |
| 2673 | 2651 | |
| 2674 | 2652 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2675 | 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 | 2656 | const bits = int_info.bits; |
| 2678 | 2657 | |
| 2679 | 2658 | switch (bits) { |
| ... | ... | @@ -2716,9 +2695,22 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue { |
| 2716 | 2695 | try f.writeCValue(w, lhs); |
| 2717 | 2696 | try w.writeAll(", "); |
| 2718 | 2697 | try f.writeCValue(w, rhs); |
| 2719 | | if (int_info.signedness == .signed) |
| 2720 | | try w.print(", {}", .{try f.fmtIntLiteral(inst_ty, MinInt{})}); |
| 2721 | | try w.print(", {});", .{try f.fmtIntLiteral(inst_ty, MaxInt{})}); |
| 2698 | { |
| 2699 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); |
| 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 | 2714 | try f.object.indent_writer.insertNewline(); |
| 2723 | 2715 | |
| 2724 | 2716 | return ret; |
| ... | ... | @@ -2756,9 +2748,22 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CV |
| 2756 | 2748 | try w.writeAll(", &"); |
| 2757 | 2749 | try f.writeCValue(w, ret); |
| 2758 | 2750 | try w.writeAll(".field_0, "); |
| 2759 | | if (int_info.signedness == .signed) |
| 2760 | | try w.print("{}, ", .{try f.fmtIntLiteral(scalar_ty, MinInt{})}); |
| 2761 | | try w.print("{});", .{try f.fmtIntLiteral(scalar_ty, MaxInt{})}); |
| 2751 | { |
| 2752 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); |
| 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 | 2767 | try f.object.indent_writer.insertNewline(); |
| 2763 | 2768 | return ret; |
| 2764 | 2769 | } |
| ... | ... | @@ -3360,9 +3365,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3360 | 3365 | |
| 3361 | 3366 | const inputs_extra_begin = extra_i; |
| 3362 | 3367 | for (inputs) |input, i| { |
| 3363 | | const input_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); |
| 3364 | | const constraint = std.mem.sliceTo(input_bytes, 0); |
| 3365 | | const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); |
| 3368 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); |
| 3369 | const constraint = std.mem.sliceTo(extra_bytes, 0); |
| 3370 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 3366 | 3371 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 3367 | 3372 | // for the string, we still use the next u32 for the null terminator. |
| 3368 | 3373 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| ... | ... | @@ -3411,10 +3416,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3411 | 3416 | try writer.writeAll(": "); |
| 3412 | 3417 | extra_i = inputs_extra_begin; |
| 3413 | 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 | 3422 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 3416 | 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 | 3426 | if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') { |
| 3420 | 3427 | const reg = constraint[1 .. constraint.len - 1]; |
| ... | ... | @@ -3511,11 +3518,10 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3511 | 3518 | const operand = try f.resolveInst(ty_op.operand); |
| 3512 | 3519 | const ptr_ty = f.air.typeOf(ty_op.operand); |
| 3513 | 3520 | const opt_ty = ptr_ty.childType(); |
| 3514 | | var buf: Type.Payload.ElemType = undefined; |
| 3515 | | const payload_ty = opt_ty.optionalChild(&buf); |
| 3521 | const inst_ty = f.air.typeOfIndex(inst); |
| 3516 | 3522 | |
| 3517 | | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3518 | | return CValue.undefined_ptr; |
| 3523 | if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) { |
| 3524 | return CValue{ .undefined_ptr = inst_ty }; |
| 3519 | 3525 | } |
| 3520 | 3526 | |
| 3521 | 3527 | if (opt_ty.optionalReprIsPayload()) { |
| ... | ... | @@ -3524,7 +3530,6 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3524 | 3530 | return operand; |
| 3525 | 3531 | } |
| 3526 | 3532 | |
| 3527 | | const inst_ty = f.air.typeOfIndex(inst); |
| 3528 | 3533 | const local = try f.allocLocal(inst_ty, .Const); |
| 3529 | 3534 | try writer.writeAll(" = &("); |
| 3530 | 3535 | try f.writeCValue(writer, operand); |
| ... | ... | @@ -3892,7 +3897,8 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3892 | 3897 | if (operand == .undefined_ptr) { |
| 3893 | 3898 | // Unfortunately, C does not support any equivalent to |
| 3894 | 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 | 3902 | } else { |
| 3897 | 3903 | try writer.writeAll("&("); |
| 3898 | 3904 | try f.writeCValueDeref(writer, operand); |
| ... | ... | @@ -4478,148 +4484,186 @@ fn signAbbrev(signedness: std.builtin.Signedness) u8 { |
| 4478 | 4484 | }; |
| 4479 | 4485 | } |
| 4480 | 4486 | |
| 4481 | | const UndefInt = struct { |
| 4482 | | pub fn to(_: UndefInt, comptime T: type) error{}!T { |
| 4483 | | comptime { |
| 4484 | | if (@bitSizeOf(T) < 2) return 0; |
| 4485 | | var value: T = 2; |
| 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 | | } |
| 4487 | const FormatIntLiteralContext = struct { |
| 4488 | ty: Type, |
| 4489 | val: Value, |
| 4490 | mod: *Module, |
| 4491 | location: ValueRenderLocation, |
| 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 { |
| 4505 | | return struct { |
| 4506 | | ty: Type, |
| 4507 | | target: std.Target, |
| 4508 | | int_val: IntType, |
| 4509 | | location: ValueRenderLocation, |
| 4512 | undef_limbs: [limbs_count_128]Limb, |
| 4513 | str: [worst_case_int.sizeInBaseUpperBound(base)]u8, |
| 4514 | limbs_limbs: [expected_needed_limbs_count]Limb, |
| 4515 | }; |
| 4516 | var stack align(@alignOf(expected_contents)) = |
| 4517 | std.heap.stackFallback(@sizeOf(expected_contents), data.mod.gpa); |
| 4518 | const allocator = stack.get(); |
| 4510 | 4519 | |
| 4511 | | fn formatHelper( |
| 4512 | | self: @This(), |
| 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 | | } |
| 4520 | var undef_limbs: []Limb = &.{}; |
| 4521 | defer allocator.free(undef_limbs); |
| 4537 | 4522 | |
| 4538 | | const upper = @intCast(u64, c_abs_val >> 64); |
| 4539 | | if (upper != 0) try writer.writeByte('('); |
| 4540 | | if (upper != 0 or c_int_val < 0) try writer.writeAll("(uint128_t)"); |
| 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 | | } |
| 4523 | var int_buf: Value.BigIntSpace = undefined; |
| 4524 | const int = if (data.val.isUndefDeep()) blk: { |
| 4525 | undef_limbs = try allocator.alloc(Limb, BigInt.calcTwosCompLimbCount(int_info.bits)); |
| 4550 | 4526 | |
| 4551 | | const lower = @truncate(u64, c_abs_val); |
| 4552 | | try (IntLiteralFormatter(u64){ |
| 4553 | | .ty = Type.u64, |
| 4554 | | .target = self.target, |
| 4555 | | .int_val = lower, |
| 4556 | | .location = self.location, |
| 4557 | | }).formatHelper(u64, fmt, options, writer); |
| 4527 | const undef_pattern: Limb = (1 << (@bitSizeOf(Limb) | 1)) / 3; |
| 4528 | std.mem.set(Limb, undef_limbs, undef_pattern); |
| 4558 | 4529 | |
| 4559 | | if (upper != 0) try writer.writeByte(')'); |
| 4560 | | try writer.writeByte(')'); |
| 4561 | | } else if (c_int_val == std.math.maxInt(CIntType) or |
| 4562 | | c_int_info.signedness == .signed and c_int_val == std.math.minInt(CIntType)) |
| 4563 | | { |
| 4564 | | if (c_int_info.signedness == .unsigned) try writer.writeByte('U'); |
| 4565 | | try writer.writeAll(switch (self.ty.tag()) { |
| 4566 | | .c_short, .c_ushort => "SHRT", |
| 4567 | | .c_int, .c_uint => "INT", |
| 4568 | | .c_long, .c_ulong => "LONG", |
| 4569 | | .c_longlong, .c_ulonglong => "LLONG", |
| 4570 | | .isize, .usize => "INTPTR", |
| 4571 | | else => std.fmt.comptimePrint("INT{d}", .{c_int_info.bits}), |
| 4572 | | }); |
| 4573 | | try writer.writeAll(if (c_int_val < 0) "_MIN" else "_MAX"); |
| 4574 | | } else { |
| 4575 | | if (c_int_val < 0) try writer.writeByte('-'); |
| 4576 | | if (c_int_info.signedness == .unsigned) try writer.writeByte('U'); |
| 4577 | | try writer.print("INT{d}_C(" ++ switch (fmt.len) { |
| 4578 | | 0 => "{d}", |
| 4579 | | 1 => switch (fmt[0]) { |
| 4580 | | 'o' => "0{o}", |
| 4581 | | 'd' => "{d}", |
| 4582 | | 'x' => "0x{x}", |
| 4583 | | 'X' => "0x{X}", |
| 4584 | | else => @compileError("Invalid fmt: " ++ fmt), |
| 4585 | | }, |
| 4586 | | else => @compileError("Invalid fmt: " ++ fmt), |
| 4587 | | } ++ ")", .{ c_int_info.bits, c_abs_val }); |
| 4588 | | } |
| 4530 | var undef_int = BigInt.Mutable{ |
| 4531 | .limbs = undef_limbs, |
| 4532 | .len = undef_limbs.len, |
| 4533 | .positive = true, |
| 4534 | }; |
| 4535 | undef_int.truncate(undef_int.toConst(), int_info.signedness, int_info.bits); |
| 4536 | break :blk undef_int.toConst(); |
| 4537 | } else data.val.toBigInt(&int_buf, target); |
| 4538 | assert(int.fitsInTwosComp(int_info.signedness, int_info.bits)); |
| 4539 | |
| 4540 | if (data.location == .Identifier) { |
| 4541 | const str = try int.toStringAlloc(allocator, 10, undefined); |
| 4542 | defer allocator.free(str); |
| 4543 | |
| 4544 | return writer.writeAll(str); |
| 4545 | } |
| 4546 | |
| 4547 | const limbs_count_64 = @divExact(64, @bitSizeOf(Limb)); |
| 4548 | const c_bits = toCIntBits(int_info.bits) orelse unreachable; |
| 4549 | if (c_bits == 128) { |
| 4550 | // Clang and GCC don't support 128-bit integer constants but |
| 4551 | // will hopefully unfold them if we construct one manually. |
| 4552 | //std.debug.todo("128-bit is unimplemented"); |
| 4553 | try writer.writeByte('('); |
| 4554 | if (int_info.signedness == .signed) { |
| 4555 | try writer.writeAll("(int128_t)"); |
| 4556 | if (!int.positive) try writer.writeByte('-'); |
| 4589 | 4557 | } |
| 4590 | 4558 | |
| 4591 | | pub fn format( |
| 4592 | | self: @This(), |
| 4593 | | comptime fmt: []const u8, |
| 4594 | | options: std.fmt.FormatOptions, |
| 4595 | | writer: anytype, |
| 4596 | | ) !void { |
| 4597 | | const int_info = self.ty.intInfo(self.target); |
| 4598 | | switch (toCIntBits(int_info.bits).?) { |
| 4599 | | 8 => switch (int_info.signedness) { |
| 4600 | | .signed => try self.formatHelper(i8, fmt, options, writer), |
| 4601 | | .unsigned => try self.formatHelper(u8, fmt, options, writer), |
| 4602 | | }, |
| 4603 | | 16 => switch (int_info.signedness) { |
| 4604 | | .signed => try self.formatHelper(i16, fmt, options, writer), |
| 4605 | | .unsigned => try self.formatHelper(u16, fmt, options, writer), |
| 4606 | | }, |
| 4607 | | 32 => switch (int_info.signedness) { |
| 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 | | } |
| 4559 | const split = std.math.min(int.limbs.len, limbs_count_64); |
| 4560 | var upper_val_pl = Value.Payload.BigInt{ |
| 4561 | .base = .{ .tag = .int_big_positive }, |
| 4562 | .data = int.limbs[split..], |
| 4563 | }; |
| 4564 | const have_upper = !upper_val_pl.asBigInt().eqZero(); |
| 4565 | if (have_upper) try writer.writeByte('('); |
| 4566 | if (have_upper or !int.positive) try writer.writeAll("(uint128_t)"); |
| 4567 | if (have_upper) { |
| 4568 | const upper_val = Value.initPayload(&upper_val_pl.base); |
| 4569 | try formatIntLiteral(.{ |
| 4570 | .ty = Type.u64, |
| 4571 | .val = upper_val, |
| 4572 | .mod = data.mod, |
| 4573 | .location = data.location, |
| 4574 | }, fmt, options, writer); |
| 4575 | try writer.writeAll("<<64|"); |
| 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 | 4669 | fn loweredFnRetTyHasBits(fn_ty: Type) bool { |