| ... | @@ -62,6 +62,7 @@ const FormatTypeAsCIdentContext = struct { | ... | @@ -62,6 +62,7 @@ const FormatTypeAsCIdentContext = struct { |
| 62 | }; | 62 | }; |
| 63 | | 63 | |
| 64 | const ValueRenderLocation = enum { | 64 | const 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 | }; |
| 334 | | 339 | |
| 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) orelse | 573 | .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"); |
| 1026 | | 1039 | |
| ... | @@ -1540,7 +1553,7 @@ pub const DeclGen = struct { | ... | @@ -1540,7 +1553,7 @@ pub const DeclGen = struct { |
| 1540 | } | 1553 | } |
| 1541 | } | 1554 | } |
| 1542 | | 1555 | |
| 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 | } |
| 1567 | | 1575 | |
| 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 | } |
| 1590 | | 1598 | |
| 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); |
| 1594 | | 1602 | |
| ... | @@ -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 | }; |
| 1607 | | 1628 | |
| 1608 | pub fn genErrDecls(o: *Object) !void { | 1629 | pub 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 | } |
| 2460 | | 2481 | |
| 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); |
| 2494 | | 2512 | 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(); |
| 2504 | | 2516 | |
| 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 | } |
| 2526 | | 2538 | |
| 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); |
| 2600 | | 2569 | 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(); |
| 2607 | | 2573 | |
| 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) orelse | 2592 | 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", .{}); |
| 2628 | | 2594 | |
| 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); |
| 2636 | | 2599 | |
| 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 | } |
| 4370 | | 4316 | |
| 4371 | fn intMax(ty: Type, target: std.Target, buf: []u8) []const u8 { | 4317 | const 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 | }; |
| | 4329 | const MaxInt = struct { |
| | 4330 | pub fn to(_: MaxInt, comptime T: type) error{}!T { |
| | 4331 | return std.math.maxInt(T); |
| | 4332 | } |
| | 4333 | }; |
| | 4334 | const MinInt = struct { |
| | 4335 | pub fn to(_: MinInt, comptime T: type) error{}!T { |
| | 4336 | return std.math.minInt(T); |
| | 4337 | } |
| | 4338 | }; |
| 4392 | | 4339 | |
| 4393 | fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 { | 4340 | fn 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 | } |
| 4413 | | 4460 | |
| 4414 | fn loweredFnRetTyHasBits(fn_ty: Type) bool { | 4461 | fn loweredFnRetTyHasBits(fn_ty: Type) bool { |