authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-05 15:03:24-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-25 05:11:28-04:00
log0092f6ed88f02a7930d9c27732a888c2e6c5e2dc
tree849e460339f8adee6b172c8dd663f236af6862ab
parent61bf43d790d0f56f9c030afd8ec761a0f043a8a5

c: fix int literal warnings


1 files changed, 225 insertions(+), 178 deletions(-)

src/codegen/c.zig+225-178
...@@ -62,6 +62,7 @@ const FormatTypeAsCIdentContext = struct {...@@ -62,6 +62,7 @@ const FormatTypeAsCIdentContext = struct {
62};62};
6363
64const ValueRenderLocation = enum {64const ValueRenderLocation = enum {
65 Identifier,
65 FunctionArgument,66 FunctionArgument,
66 Other,67 Other,
67};68};
...@@ -330,6 +331,10 @@ pub const Function = struct {...@@ -330,6 +331,10 @@ pub const Function = struct {
330 fn renderTypecast(f: *Function, w: anytype, t: Type) !void {331 fn renderTypecast(f: *Function, w: anytype, t: Type) !void {
331 return f.object.dg.renderTypecast(w, t);332 return f.object.dg.renderTypecast(w, t);
332 }333 }
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);
337 }
333};338};
334339
335/// This data is available when outputting .c code for a `Module`.340/// This data is available when outputting .c code for a `Module`.
...@@ -564,30 +569,19 @@ pub const DeclGen = struct {...@@ -564,30 +569,19 @@ pub const DeclGen = struct {
564 // Using '{}' for integer and floats seemed to error C compilers (both GCC and Clang)569 // Using '{}' for integer and floats seemed to error C compilers (both GCC and Clang)
565 // with 'error: expected expression' (including when built with 'zig cc')570 // with 'error: expected expression' (including when built with 'zig cc')
566 .Bool => return writer.writeAll("false"),571 .Bool => return writer.writeAll("false"),
567 .Int => {572 .Int => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, UndefInt{}, location)}),
568 const c_bits = toCIntBits(ty.intInfo(dg.module.getTarget()).bits) orelse573 .Float => switch (ty.tag()) {
569 return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{});574 .f32 => return writer.print("zig_bitcast_f32_u32({x})", .{
570 switch (c_bits) {575 try dg.fmtIntLiteral(Type.u32, UndefInt{}, location),
571 8 => return writer.writeAll("0xaau"),576 }),
572 16 => return writer.writeAll("0xaaaau"),577 .f64 => return writer.print("zig_bitcast_f64_u64({x})", .{
573 32 => return writer.writeAll("0xaaaaaaaau"),578 try dg.fmtIntLiteral(Type.u64, UndefInt{}, location),
574 64 => return writer.writeAll("0xaaaaaaaaaaaaaaaau"),579 }),
575 128 => return renderInt128(writer, @as(u128, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)),580 else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}),
576 else => unreachable,
577 }
578 },
579 .Float => {
580 switch (ty.floatBits(dg.module.getTarget())) {
581 32 => return writer.writeAll("zig_bitcast_f32_u32(0xaaaaaaaau)"),
582 64 => return writer.writeAll("zig_bitcast_f64_u64(0xaaaaaaaaaaaaaaaau)"),
583 else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}),
584 }
585 },
586 .Pointer => switch (dg.module.getTarget().cpu.arch.ptrBitWidth()) {
587 32 => return writer.writeAll("(void *)0xaaaaaaaau"),
588 64 => return writer.writeAll("(void *)0xaaaaaaaaaaaaaaaau"),
589 else => unreachable,
590 },581 },
582 .Pointer => return writer.print("((void *){x})", .{
583 try dg.fmtIntLiteral(Type.usize, UndefInt{}, location),
584 }),
591 .Struct, .ErrorUnion => {585 .Struct, .ErrorUnion => {
592 try writer.writeByte('(');586 try writer.writeByte('(');
593 try dg.renderTypecast(writer, ty);587 try dg.renderTypecast(writer, ty);
...@@ -608,8 +602,12 @@ pub const DeclGen = struct {...@@ -608,8 +602,12 @@ pub const DeclGen = struct {
608 }602 }
609 switch (ty.zigTypeTag()) {603 switch (ty.zigTypeTag()) {
610 .Int => switch (val.tag()) {604 .Int => switch (val.tag()) {
611 .int_big_positive => try dg.renderBigIntConst(writer, val.castTag(.int_big_positive).?.asBigInt(), ty.isSignedInt()),605 .int_big_positive => return writer.print("{x}", .{
612 .int_big_negative => try dg.renderBigIntConst(writer, val.castTag(.int_big_negative).?.asBigInt(), true),606 try dg.fmtIntLiteral(ty, val.castTag(.int_big_positive).?.asBigInt(), location),
607 }),
608 .int_big_negative => return writer.print("{x}", .{
609 try dg.fmtIntLiteral(ty, val.castTag(.int_big_negative).?.asBigInt(), location),
610 }),
613 .field_ptr,611 .field_ptr,
614 .elem_ptr,612 .elem_ptr,
615 .opt_payload_ptr,613 .opt_payload_ptr,
...@@ -617,19 +615,32 @@ pub const DeclGen = struct {...@@ -617,19 +615,32 @@ pub const DeclGen = struct {
617 .decl_ref_mut,615 .decl_ref_mut,
618 .decl_ref,616 .decl_ref,
619 => try dg.renderParentPtr(writer, val, ty),617 => try dg.renderParentPtr(writer, val, ty),
620 else => {618 else => if (ty.isSignedInt())
621 if (ty.isSignedInt())619 return writer.print("{d}", .{try dg.fmtIntLiteral(ty, val.toSignedInt(), location)})
622 return writer.print("{d}", .{val.toSignedInt()});620 else
623 return writer.print("{d}u", .{val.toUnsignedInt(target)});621 return writer.print("{d}", .{
624 },622 try dg.fmtIntLiteral(ty, val.toUnsignedInt(target), location),
623 }),
625 },624 },
626 .Float => {625 .Float => {
627 if (ty.floatBits(dg.module.getTarget()) <= 64) {626 if (ty.floatBits(target) <= 64) {
628 if (std.math.isNan(val.toFloat(f64)) or std.math.isInf(val.toFloat(f64))) {627 if (std.math.isNan(val.toFloat(f64)) or std.math.isInf(val.toFloat(f64))) {
629 // just generate a bit cast (exactly like we do in airBitcast)628 // just generate a bit cast (exactly like we do in airBitcast)
630 switch (ty.tag()) {629 switch (ty.tag()) {
631 .f32 => return writer.print("zig_bitcast_f32_u32(0x{x})", .{@bitCast(u32, val.toFloat(f32))}),630 .f32 => return writer.print("zig_bitcast_f32_u32({x})", .{
632 .f64 => return writer.print("zig_bitcast_f64_u64(0x{x})", .{@bitCast(u64, val.toFloat(f64))}),631 try dg.fmtIntLiteral(
632 Type.u32,
633 @bitCast(u32, val.toFloat(f32)),
634 location,
635 ),
636 }),
637 .f64 => return writer.print("zig_bitcast_f64_u64({x})", .{
638 try dg.fmtIntLiteral(
639 Type.u64,
640 @bitCast(u64, val.toFloat(f64)),
641 location,
642 ),
643 }),
633 else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}),644 else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}),
634 }645 }
635 } else {646 } else {
...@@ -671,7 +682,9 @@ pub const DeclGen = struct {...@@ -671,7 +682,9 @@ pub const DeclGen = struct {
671 .int_u64, .one => {682 .int_u64, .one => {
672 try writer.writeAll("((");683 try writer.writeAll("((");
673 try dg.renderTypecast(writer, ty);684 try dg.renderTypecast(writer, ty);
674 try writer.print(")0x{x}u)", .{val.toUnsignedInt(target)});685 return writer.print("){x})", .{
686 try dg.fmtIntLiteral(Type.usize, val.toUnsignedInt(target), location),
687 });
675 },688 },
676 .field_ptr,689 .field_ptr,
677 .elem_ptr,690 .elem_ptr,
...@@ -1020,7 +1033,7 @@ pub const DeclGen = struct {...@@ -1020,7 +1033,7 @@ pub const DeclGen = struct {
1020 }1033 }
1021 if (ptr_sentinel) |s| {1034 if (ptr_sentinel) |s| {
1022 try bw.writeAll("_s_");1035 try bw.writeAll("_s_");
1023 try dg.renderValue(bw, child_type, s, .Other);1036 try dg.renderValue(bw, child_type, s, .Identifier);
1024 }1037 }
1025 try bw.writeAll(";\n");1038 try bw.writeAll(";\n");
10261039
...@@ -1540,7 +1553,7 @@ pub const DeclGen = struct {...@@ -1540,7 +1553,7 @@ pub const DeclGen = struct {
1540 }1553 }
1541 }1554 }
15421555
1543 fn writeCValue(dg: DeclGen, w: anytype, c_value: CValue) !void {1556 fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void {
1544 switch (c_value) {1557 switch (c_value) {
1545 .none => unreachable,1558 .none => unreachable,
1546 .local => |i| return w.print("t{d}", .{i}),1559 .local => |i| return w.print("t{d}", .{i}),
...@@ -1552,20 +1565,15 @@ pub const DeclGen = struct {...@@ -1552,20 +1565,15 @@ pub const DeclGen = struct {
1552 try w.writeByte('&');1565 try w.writeByte('&');
1553 return dg.renderDeclName(w, decl);1566 return dg.renderDeclName(w, decl);
1554 },1567 },
1555 .undefined_ptr => {1568 .undefined_ptr => return w.print("((void *){x})", .{
1556 const target = dg.module.getTarget();1569 try dg.fmtIntLiteral(Type.usize, UndefInt{}, .Other),
1557 switch (target.cpu.arch.ptrBitWidth()) {1570 }),
1558 32 => try w.writeAll("(void *)0xaaaaaaaa"),
1559 64 => try w.writeAll("(void *)0xaaaaaaaaaaaaaaaa"),
1560 else => unreachable,
1561 }
1562 },
1563 .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}),1571 .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}),
1564 .bytes => |bytes| return w.writeAll(bytes),1572 .bytes => |bytes| return w.writeAll(bytes),
1565 }1573 }
1566 }1574 }
15671575
1568 fn writeCValueDeref(dg: DeclGen, w: anytype, c_value: CValue) !void {1576 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {
1569 switch (c_value) {1577 switch (c_value) {
1570 .none => unreachable,1578 .none => unreachable,
1571 .local => |i| return w.print("(*t{d})", .{i}),1579 .local => |i| return w.print("(*t{d})", .{i}),
...@@ -1588,7 +1596,7 @@ pub const DeclGen = struct {...@@ -1588,7 +1596,7 @@ pub const DeclGen = struct {
1588 }1596 }
1589 }1597 }
15901598
1591 fn renderDeclName(dg: DeclGen, writer: anytype, decl_index: Decl.Index) !void {1599 fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index) !void {
1592 const decl = dg.module.declPtr(decl_index);1600 const decl = dg.module.declPtr(decl_index);
1593 dg.module.markDeclAlive(decl);1601 dg.module.markDeclAlive(decl);
15941602
...@@ -1603,6 +1611,19 @@ pub const DeclGen = struct {...@@ -1603,6 +1611,19 @@ pub const DeclGen = struct {
1603 return writer.print("{ }", .{fmtIdent(name)});1611 return writer.print("{ }", .{fmtIdent(name)});
1604 }1612 }
1605 }1613 }
1614
1615 fn fmtIntLiteral(
1616 dg: *DeclGen,
1617 ty: Type,
1618 int_val: anytype,
1619 location: ValueRenderLocation,
1620 ) !IntLiteralFormatter(@TypeOf(int_val)) {
1621 const target = dg.module.getTarget();
1622 const int_info = ty.intInfo(target);
1623 _ = toCIntBits(int_info.bits) orelse
1624 return dg.fail("TODO implement integer constants larger than 128 bits", .{});
1625 return .{ .ty = ty, .target = target, .int_val = int_val, .location = location };
1626 }
1606};1627};
16071628
1608pub fn genErrDecls(o: *Object) !void {1629pub fn genErrDecls(o: *Object) !void {
...@@ -2369,7 +2390,7 @@ fn airStoreUndefined(f: *Function, dest_ptr: CValue) !CValue {...@@ -2369,7 +2390,7 @@ fn airStoreUndefined(f: *Function, dest_ptr: CValue) !CValue {
2369 const writer = f.object.writer();2390 const writer = f.object.writer();
2370 try writer.writeAll("memset(");2391 try writer.writeAll("memset(");
2371 try f.writeCValue(writer, dest_ptr);2392 try f.writeCValue(writer, dest_ptr);
2372 try writer.writeAll(", 0xaa, sizeof(");2393 try writer.print(", {x}, sizeof(", .{try f.fmtIntLiteral(Type.u8, UndefInt{})});
2373 try f.writeCValueDeref(writer, dest_ptr);2394 try f.writeCValueDeref(writer, dest_ptr);
2374 try writer.writeAll("));\n");2395 try writer.writeAll("));\n");
2375 },2396 },
...@@ -2458,9 +2479,6 @@ fn airWrapOp(...@@ -2458,9 +2479,6 @@ fn airWrapOp(
2458 return f.fail("TODO: C backend: airWrapOp for large integers", .{});2479 return f.fail("TODO: C backend: airWrapOp for large integers", .{});
2459 }2480 }
24602481
2461 var max_buf: [80]u8 = undefined;
2462 const max = intMax(inst_ty, target, &max_buf);
2463
2464 const lhs = try f.resolveInst(bin_op.lhs);2482 const lhs = try f.resolveInst(bin_op.lhs);
2465 const rhs = try f.resolveInst(bin_op.rhs);2483 const rhs = try f.resolveInst(bin_op.rhs);
2466 const w = f.object.writer();2484 const w = f.object.writer();
...@@ -2491,15 +2509,9 @@ fn airWrapOp(...@@ -2491,15 +2509,9 @@ fn airWrapOp(
2491 try f.writeCValue(w, lhs);2509 try f.writeCValue(w, lhs);
2492 try w.writeAll(", ");2510 try w.writeAll(", ");
2493 try f.writeCValue(w, rhs);2511 try f.writeCValue(w, rhs);
24942512 if (int_info.signedness == .signed)
2495 if (int_info.signedness == .signed) {2513 try w.print(", {}", .{try f.fmtIntLiteral(inst_ty, MinInt{})});
2496 var min_buf: [80]u8 = undefined;2514 try w.print(", {});", .{try f.fmtIntLiteral(inst_ty, MaxInt{})});
2497 const min = intMin(inst_ty, target, &min_buf);
2498
2499 try w.print(", {s}", .{min});
2500 }
2501
2502 try w.print(", {s});", .{max});
2503 try f.object.indent_writer.insertNewline();2515 try f.object.indent_writer.insertNewline();
25042516
2505 return ret;2517 return ret;
...@@ -2524,49 +2536,6 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {...@@ -2524,49 +2536,6 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
2524 return f.object.dg.fail("TODO: C backend: airSatOp for large integers", .{});2536 return f.object.dg.fail("TODO: C backend: airSatOp for large integers", .{});
2525 }2537 }
25262538
2527 var min_buf: [80]u8 = undefined;
2528 const min = switch (int_info.signedness) {
2529 .unsigned => "0",
2530 else => switch (inst_ty.tag()) {
2531 .c_short => "SHRT_MIN",
2532 .c_int => "INT_MIN",
2533 .c_long => "LONG_MIN",
2534 .c_longlong => "LLONG_MIN",
2535 .isize => "INTPTR_MIN",
2536 else => blk: {
2537 // compute the type minimum based on the bitcount (bits)
2538 const val = -1 * std.math.pow(i65, 2, @intCast(i65, bits - 1));
2539 break :blk std.fmt.bufPrint(&min_buf, "{d}", .{val}) catch |err| switch (err) {
2540 error.NoSpaceLeft => unreachable,
2541 };
2542 },
2543 },
2544 };
2545
2546 var max_buf: [80]u8 = undefined;
2547 const max = switch (inst_ty.tag()) {
2548 .c_short => "SHRT_MAX",
2549 .c_ushort => "USHRT_MAX",
2550 .c_int => "INT_MAX",
2551 .c_uint => "UINT_MAX",
2552 .c_long => "LONG_MAX",
2553 .c_ulong => "ULONG_MAX",
2554 .c_longlong => "LLONG_MAX",
2555 .c_ulonglong => "ULLONG_MAX",
2556 .isize => "INTPTR_MAX",
2557 .usize => "UINTPTR_MAX",
2558 else => blk: {
2559 const pow_bits = switch (int_info.signedness) {
2560 .signed => bits - 1,
2561 .unsigned => bits,
2562 };
2563 const val = std.math.pow(u65, 2, pow_bits) - 1;
2564 break :blk std.fmt.bufPrint(&max_buf, "{}", .{val}) catch |err| switch (err) {
2565 error.NoSpaceLeft => unreachable,
2566 };
2567 },
2568 };
2569
2570 const lhs = try f.resolveInst(bin_op.lhs);2539 const lhs = try f.resolveInst(bin_op.lhs);
2571 const rhs = try f.resolveInst(bin_op.rhs);2540 const rhs = try f.resolveInst(bin_op.rhs);
2572 const w = f.object.writer();2541 const w = f.object.writer();
...@@ -2597,12 +2566,9 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {...@@ -2597,12 +2566,9 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
2597 try f.writeCValue(w, lhs);2566 try f.writeCValue(w, lhs);
2598 try w.writeAll(", ");2567 try w.writeAll(", ");
2599 try f.writeCValue(w, rhs);2568 try f.writeCValue(w, rhs);
26002569 if (int_info.signedness == .signed)
2601 if (int_info.signedness == .signed) {2570 try w.print(", {}", .{try f.fmtIntLiteral(inst_ty, MinInt{})});
2602 try w.print(", {s}", .{min});2571 try w.print(", {});", .{try f.fmtIntLiteral(inst_ty, MaxInt{})});
2603 }
2604
2605 try w.print(", {s});", .{max});
2606 try f.object.indent_writer.insertNewline();2572 try f.object.indent_writer.insertNewline();
26072573
2608 return ret;2574 return ret;
...@@ -2626,43 +2592,23 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CV...@@ -2626,43 +2592,23 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CV
2626 const c_bits = toCIntBits(int_info.bits) orelse2592 const c_bits = toCIntBits(int_info.bits) orelse
2627 return f.fail("TODO: C backend: implement integer arithmetic larger than 128 bits", .{});2593 return f.fail("TODO: C backend: implement integer arithmetic larger than 128 bits", .{});
26282594
2629 var max_buf: [80]u8 = undefined;
2630 const max = intMax(scalar_ty, target, &max_buf);
2631
2632 const ret = try f.allocLocal(inst_ty, .Mut);2595 const ret = try f.allocLocal(inst_ty, .Mut);
2633 try w.writeByte(';');2596 try w.writeByte(';');
2634 try f.object.indent_writer.insertNewline();2597 try f.object.indent_writer.insertNewline();
2635 try f.writeCValue(w, ret);2598 try f.writeCValue(w, ret);
26362599
2637 switch (int_info.signedness) {2600 try w.print(".field_1 = zig_{s}{c}{d}(", .{
2638 .unsigned => {2601 op_abbrev, signAbbrev(int_info.signedness), c_bits,
2639 try w.print(".field_1 = zig_{s}u{d}(", .{2602 });
2640 op_abbrev, c_bits,2603 try f.writeCValue(w, lhs);
2641 });2604 try w.writeAll(", ");
2642 try f.writeCValue(w, lhs);2605 try f.writeCValue(w, rhs);
2643 try w.writeAll(", ");2606 try w.writeAll(", &");
2644 try f.writeCValue(w, rhs);2607 try f.writeCValue(w, ret);
2645 try w.writeAll(", &");2608 try w.writeAll(".field_0, ");
2646 try f.writeCValue(w, ret);2609 if (int_info.signedness == .signed)
2647 try w.print(".field_0, {s}", .{max});2610 try w.print("{}, ", .{try f.fmtIntLiteral(scalar_ty, MinInt{})});
2648 },2611 try w.print("{});", .{try f.fmtIntLiteral(scalar_ty, MaxInt{})});
2649 .signed => {
2650 var min_buf: [80]u8 = undefined;
2651 const min = intMin(scalar_ty, target, &min_buf);
2652
2653 try w.print(".field_1 = zig_{s}i{d}(", .{
2654 op_abbrev, c_bits,
2655 });
2656 try f.writeCValue(w, lhs);
2657 try w.writeAll(", ");
2658 try f.writeCValue(w, rhs);
2659 try w.writeAll(", &");
2660 try f.writeCValue(w, ret);
2661 try w.print(".field_0, {s}, {s}", .{ min, max });
2662 },
2663 }
2664
2665 try w.writeAll(");");
2666 try f.object.indent_writer.insertNewline();2612 try f.object.indent_writer.insertNewline();
2667 return ret;2613 return ret;
2668}2614}
...@@ -4368,47 +4314,148 @@ fn signAbbrev(signedness: std.builtin.Signedness) u8 {...@@ -4368,47 +4314,148 @@ fn signAbbrev(signedness: std.builtin.Signedness) u8 {
4368 };4314 };
4369}4315}
43704316
4371fn intMax(ty: Type, target: std.Target, buf: []u8) []const u8 {4317const UndefInt = struct {
4372 switch (ty.tag()) {4318 pub fn to(_: UndefInt, comptime T: type) error{}!T {
4373 .c_short => return "SHRT_MAX",4319 comptime {
4374 .c_ushort => return "USHRT_MAX",4320 if (@bitSizeOf(T) < 2) return 0;
4375 .c_int => return "INT_MAX",4321 var value: T = 2;
4376 .c_uint => return "UINT_MAX",4322 var shift = 2;
4377 .c_long => return "LONG_MAX",4323 while (shift < @bitSizeOf(T)) : (shift <<= 1)
4378 .c_ulong => return "ULONG_MAX",4324 value |= value << shift;
4379 .c_longlong => return "LLONG_MAX",4325 return value;
4380 .c_ulonglong => return "ULLONG_MAX",4326 }
4381 else => {
4382 const int_info = ty.intInfo(target);
4383 const rhs = @intCast(u7, int_info.bits - @boolToInt(int_info.signedness == .signed));
4384 const val = (@as(u128, 1) << rhs) - 1;
4385 // TODO make this integer literal have a suffix if necessary (such as "ull")
4386 return std.fmt.bufPrint(buf, "{}", .{val}) catch |err| switch (err) {
4387 error.NoSpaceLeft => unreachable,
4388 };
4389 },
4390 }4327 }
4391}4328};
4329const MaxInt = struct {
4330 pub fn to(_: MaxInt, comptime T: type) error{}!T {
4331 return std.math.maxInt(T);
4332 }
4333};
4334const MinInt = struct {
4335 pub fn to(_: MinInt, comptime T: type) error{}!T {
4336 return std.math.minInt(T);
4337 }
4338};
43924339
4393fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 {4340fn IntLiteralFormatter(comptime IntType: type) type {
4394 switch (ty.tag()) {4341 return struct {
4395 .c_short => return "SHRT_MIN",4342 ty: Type,
4396 .c_int => return "INT_MIN",4343 target: std.Target,
4397 .c_long => return "LONG_MIN",4344 int_val: IntType,
4398 .c_longlong => return "LLONG_MIN",4345 location: ValueRenderLocation,
4399 else => {4346
4400 const int_info = ty.intInfo(target);4347 fn formatHelper(
4401 assert(int_info.signedness == .signed);4348 self: @This(),
4402 const val = v: {4349 comptime CIntType: type,
4403 if (int_info.bits == 0) break :v 0;4350 comptime fmt: []const u8,
4404 const rhs = @intCast(u7, (int_info.bits - 1));4351 options: std.fmt.FormatOptions,
4405 break :v -(@as(i128, 1) << rhs);4352 writer: anytype,
4406 };4353 ) !void {
4407 return std.fmt.bufPrint(buf, "{d}", .{val}) catch |err| switch (err) {4354 const c_int_info = @typeInfo(CIntType).Int;
4408 error.NoSpaceLeft => unreachable,4355 const c_int_val = switch (@typeInfo(IntType)) {
4356 .Int => @intCast(CIntType, self.int_val),
4357 .Struct, .Pointer => self.int_val.to(CIntType) catch unreachable,
4358 else => unreachable,
4409 };4359 };
4410 },4360 const c_abs_val = std.math.absCast(c_int_val);
4411 }4361 if (self.location == .Identifier) {
4362 if (c_int_val < 0) try writer.writeAll("_N");
4363 try writer.print("{d}", .{c_abs_val});
4364 } else if (c_int_info.bits == 128) {
4365 // Clang and GCC don't support 128-bit integer constants but
4366 // will hopefully unfold them if we construct one manually.
4367 //std.debug.todo("128-bit is unimplemented");
4368 try writer.writeByte('(');
4369 if (c_int_info.signedness == .signed) {
4370 try writer.writeAll("(int128_t)");
4371 if (c_int_val < 0) try writer.writeByte('-');
4372 }
4373
4374 const upper = @intCast(u64, c_abs_val >> 64);
4375 if (upper != 0) try writer.writeByte('(');
4376 if (upper != 0 or c_int_val < 0) try writer.writeAll("(uint128_t)");
4377 if (upper != 0) {
4378 try (IntLiteralFormatter(u64){
4379 .ty = Type.u64,
4380 .target = self.target,
4381 .int_val = upper,
4382 .location = self.location,
4383 }).formatHelper(u64, fmt, options, writer);
4384 try writer.writeAll("<<64|");
4385 }
4386
4387 const lower = @truncate(u64, c_abs_val);
4388 try (IntLiteralFormatter(u64){
4389 .ty = Type.u64,
4390 .target = self.target,
4391 .int_val = lower,
4392 .location = self.location,
4393 }).formatHelper(u64, fmt, options, writer);
4394
4395 if (upper != 0) try writer.writeByte(')');
4396 try writer.writeByte(')');
4397 } else if (c_int_val == std.math.maxInt(CIntType) or
4398 c_int_info.signedness == .signed and c_int_val == std.math.minInt(CIntType))
4399 {
4400 if (c_int_info.signedness == .unsigned) try writer.writeByte('U');
4401 try writer.writeAll(switch (self.ty.tag()) {
4402 .c_short, .c_ushort => "SHRT",
4403 .c_int, .c_uint => "INT",
4404 .c_long, .c_ulong => "LONG",
4405 .c_longlong, .c_ulonglong => "LLONG",
4406 .isize, .usize => "INTPTR",
4407 else => std.fmt.comptimePrint("INT{d}", .{c_int_info.bits}),
4408 });
4409 try writer.writeAll(if (c_int_val < 0) "_MIN" else "_MAX");
4410 } else {
4411 if (c_int_val < 0) try writer.writeByte('-');
4412 if (c_int_info.signedness == .unsigned) try writer.writeByte('U');
4413 try writer.print("INT{d}_C(" ++ switch (fmt.len) {
4414 0 => "{d}",
4415 1 => switch (fmt[0]) {
4416 'o' => "0{o}",
4417 'd' => "{d}",
4418 'x' => "0x{x}",
4419 'X' => "0x{X}",
4420 else => @compileError("Invalid fmt: " ++ fmt),
4421 },
4422 else => @compileError("Invalid fmt: " ++ fmt),
4423 } ++ ")", .{ c_int_info.bits, c_abs_val });
4424 }
4425 }
4426
4427 pub fn format(
4428 self: @This(),
4429 comptime fmt: []const u8,
4430 options: std.fmt.FormatOptions,
4431 writer: anytype,
4432 ) !void {
4433 const int_info = self.ty.intInfo(self.target);
4434 switch (toCIntBits(int_info.bits).?) {
4435 8 => switch (int_info.signedness) {
4436 .signed => try self.formatHelper(i8, fmt, options, writer),
4437 .unsigned => try self.formatHelper(u8, fmt, options, writer),
4438 },
4439 16 => switch (int_info.signedness) {
4440 .signed => try self.formatHelper(i16, fmt, options, writer),
4441 .unsigned => try self.formatHelper(u16, fmt, options, writer),
4442 },
4443 32 => switch (int_info.signedness) {
4444 .signed => try self.formatHelper(i32, fmt, options, writer),
4445 .unsigned => try self.formatHelper(u32, fmt, options, writer),
4446 },
4447 64 => switch (int_info.signedness) {
4448 .signed => try self.formatHelper(i64, fmt, options, writer),
4449 .unsigned => try self.formatHelper(u64, fmt, options, writer),
4450 },
4451 128 => switch (int_info.signedness) {
4452 .signed => try self.formatHelper(i128, fmt, options, writer),
4453 .unsigned => try self.formatHelper(u128, fmt, options, writer),
4454 },
4455 else => unreachable,
4456 }
4457 }
4458 };
4412}4459}
44134460
4414fn loweredFnRetTyHasBits(fn_ty: Type) bool {4461fn loweredFnRetTyHasBits(fn_ty: Type) bool {