authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-22 23:47:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-22 23:47:31-07:00
log715abe8ebeebb6d49db1e265748554404c3aab98
tree19c0fc7880bb3d9205877b31043a757de61f9cda
parent2d290d6f82b780fc5c1448bcc41fec602359dfec

AstGen: implement integers bigger than u64

also get rid of the `optional_type_from_ptr_elem` instruction.

4 files changed, 95 insertions(+), 66 deletions(-)

src/AstGen.zig+32-14
......@@ -1735,6 +1735,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
17351735 .func,
17361736 .func_inferred,
17371737 .int,
1738 .int_big,
17381739 .float,
17391740 .float128,
17401741 .intcast,
......@@ -1762,7 +1763,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
17621763 .typeof_elem,
17631764 .xor,
17641765 .optional_type,
1765 .optional_type_from_ptr_elem,
17661766 .optional_payload_safe,
17671767 .optional_payload_unsafe,
17681768 .optional_payload_safe_ptr,
......@@ -3874,18 +3874,9 @@ fn orelseCatchExpr(
38743874 block_scope.setBreakResultLoc(rl);
38753875 defer block_scope.instructions.deinit(astgen.gpa);
38763876
3877 // TODO get rid of optional_type_from_ptr_elem
38783877 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
38793878 .ref => .ref,
3880 .discard, .none, .none_or_ref, .block_ptr, .inferred_ptr => .none,
3881 .ty => |elem_ty| blk: {
3882 const wrapped_ty = try block_scope.addUnNode(.optional_type, elem_ty, node);
3883 break :blk .{ .ty = wrapped_ty };
3884 },
3885 .ptr => |ptr_ty| blk: {
3886 const wrapped_ty = try block_scope.addUnNode(.optional_type_from_ptr_elem, ptr_ty, node);
3887 break :blk .{ .ty = wrapped_ty };
3888 },
3879 else => .none,
38893880 };
38903881 block_scope.break_count += 1;
38913882 // This could be a pointer or value depending on the `operand_rl` parameter.
......@@ -5755,10 +5746,37 @@ fn integerLiteral(
57555746 else => try gz.addInt(small_int),
57565747 };
57575748 return rvalue(gz, scope, rl, result, node);
5758 } else |err| {
5759 assert(err != error.InvalidCharacter);
5760 return gz.astgen.failNode(node, "TODO implement int literals that don't fit in a u64", .{});
5749 } else |err| switch (err) {
5750 error.InvalidCharacter => unreachable, // Caught by the parser.
5751 error.Overflow => {},
5752 }
5753
5754 var base: u8 = 10;
5755 var non_prefixed: []const u8 = prefixed_bytes;
5756 if (mem.startsWith(u8, prefixed_bytes, "0x")) {
5757 base = 16;
5758 non_prefixed = prefixed_bytes[2..];
5759 } else if (mem.startsWith(u8, prefixed_bytes, "0o")) {
5760 base = 8;
5761 non_prefixed = prefixed_bytes[2..];
5762 } else if (mem.startsWith(u8, prefixed_bytes, "0b")) {
5763 base = 2;
5764 non_prefixed = prefixed_bytes[2..];
57615765 }
5766
5767 const gpa = astgen.gpa;
5768 var big_int = try std.math.big.int.Managed.init(gpa);
5769 defer big_int.deinit();
5770 big_int.setString(base, non_prefixed) catch |err| switch (err) {
5771 error.InvalidCharacter => unreachable, // caught by parser
5772 error.InvalidBase => unreachable, // we only pass 16, 8, 2, see above
5773 error.OutOfMemory => return error.OutOfMemory,
5774 };
5775
5776 const limbs = big_int.limbs[0..big_int.len()];
5777 assert(big_int.isPositive());
5778 const result = try gz.addIntBig(limbs);
5779 return rvalue(gz, scope, rl, result, node);
57625780}
57635781
57645782fn floatLiteral(
src/Module.zig+20-16
......@@ -1423,6 +1423,26 @@ pub const Scope = struct {
14231423 });
14241424 }
14251425
1426 pub fn addIntBig(gz: *GenZir, limbs: []const std.math.big.Limb) !Zir.Inst.Ref {
1427 const astgen = gz.astgen;
1428 const gpa = astgen.gpa;
1429 try gz.instructions.ensureUnusedCapacity(gpa, 1);
1430 try astgen.instructions.ensureUnusedCapacity(gpa, 1);
1431 try astgen.string_bytes.ensureUnusedCapacity(gpa, @sizeOf(std.math.big.Limb) * limbs.len);
1432
1433 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
1434 astgen.instructions.appendAssumeCapacity(.{
1435 .tag = .int_big,
1436 .data = .{ .str = .{
1437 .start = @intCast(u32, astgen.string_bytes.items.len),
1438 .len = @intCast(u32, limbs.len),
1439 } },
1440 });
1441 gz.instructions.appendAssumeCapacity(new_index);
1442 astgen.string_bytes.appendSliceAssumeCapacity(mem.sliceAsBytes(limbs));
1443 return gz.indexToRef(new_index);
1444 }
1445
14261446 pub fn addFloat(gz: *GenZir, number: f32, src_node: ast.Node.Index) !Zir.Inst.Ref {
14271447 return gz.add(.{
14281448 .tag = .float,
......@@ -1683,22 +1703,6 @@ pub const Scope = struct {
16831703 return gz.indexToRef(new_index);
16841704 }
16851705
1686 /// Asserts that `str` is 8 or fewer bytes.
1687 pub fn addSmallStr(
1688 gz: *GenZir,
1689 tag: Zir.Inst.Tag,
1690 str: []const u8,
1691 ) !Zir.Inst.Ref {
1692 var buf: [9]u8 = undefined;
1693 mem.copy(u8, &buf, str);
1694 buf[str.len] = 0;
1695
1696 return gz.add(.{
1697 .tag = tag,
1698 .data = .{ .small_str = .{ .bytes = buf[0..8].* } },
1699 });
1700 }
1701
17021706 /// Note that this returns a `Zir.Inst.Index` not a ref.
17031707 /// Does *not* append the block instruction to the scope.
17041708 /// Leaves the `payload_index` field undefined.
src/Sema.zig+18-13
......@@ -200,6 +200,7 @@ pub fn analyzeBody(
200200 .import => try sema.zirImport(block, inst),
201201 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
202202 .int => try sema.zirInt(block, inst),
203 .int_big => try sema.zirIntBig(block, inst),
203204 .float => try sema.zirFloat(block, inst),
204205 .float128 => try sema.zirFloat128(block, inst),
205206 .int_type => try sema.zirIntType(block, inst),
......@@ -219,7 +220,6 @@ pub fn analyzeBody(
219220 .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
220221 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
221222 .optional_type => try sema.zirOptionalType(block, inst),
222 .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, inst),
223223 .param_type => try sema.zirParamType(block, inst),
224224 .ptr_type => try sema.zirPtrType(block, inst),
225225 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
......@@ -1479,6 +1479,23 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*In
14791479 return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);
14801480}
14811481
1482fn zirIntBig(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
1483 const tracy = trace(@src());
1484 defer tracy.end();
1485
1486 const arena = sema.arena;
1487 const int = sema.code.instructions.items(.data)[inst].str;
1488 const byte_count = int.len * @sizeOf(std.math.big.Limb);
1489 const limb_bytes = sema.code.string_bytes[int.start..][0..byte_count];
1490 const limbs = try arena.alloc(std.math.big.Limb, int.len);
1491 mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes);
1492
1493 return sema.mod.constInst(arena, .unneeded, .{
1494 .ty = Type.initTag(.comptime_int),
1495 .val = try Value.Tag.int_big_positive.create(arena, limbs),
1496 });
1497}
1498
14821499fn zirFloat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
14831500 const arena = sema.arena;
14841501 const inst_data = sema.code.instructions.items(.data)[inst].float;
......@@ -2120,18 +2137,6 @@ fn zirOptionalType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner
21202137 return sema.mod.constType(sema.arena, src, opt_type);
21212138}
21222139
2123fn zirOptionalTypeFromPtrElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
2124 const tracy = trace(@src());
2125 defer tracy.end();
2126
2127 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2128 const ptr = try sema.resolveInst(inst_data.operand);
2129 const elem_ty = ptr.ty.elemType();
2130 const opt_ty = try sema.mod.optionalType(sema.arena, elem_ty);
2131
2132 return sema.mod.constType(sema.arena, inst_data.src(), opt_ty);
2133}
2134
21352140fn zirElemType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
21362141 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
21372142 const src = inst_data.src();
src/Zir.zig+25-23
......@@ -374,8 +374,10 @@ pub const Inst = struct {
374374 /// Implements the `@import` builtin.
375375 /// Uses the `str_tok` field.
376376 import,
377 /// Integer literal that fits in a u64. Uses the int union value.
377 /// Integer literal that fits in a u64. Uses the `int` union field.
378378 int,
379 /// Arbitrary sized integer literal. Uses the `str` union field.
380 int_big,
379381 /// A float literal that fits in a f32. Uses the float union value.
380382 float,
381383 /// A float literal that fits in a f128. Uses the `pl_node` union value.
......@@ -540,10 +542,6 @@ pub const Inst = struct {
540542 /// Create an optional type '?T'
541543 /// Uses the `un_node` field.
542544 optional_type,
543 /// Create an optional type '?T'. The operand is a pointer value. The optional type will
544 /// be the type of the pointer element, wrapped in an optional.
545 /// Uses the `un_node` field.
546 optional_type_from_ptr_elem,
547545 /// ?T => T with safety.
548546 /// Given an optional value, returns the payload value, with a safety check that
549547 /// the value is non-null. Used for `orelse`, `if` and `while`.
......@@ -1030,6 +1028,7 @@ pub const Inst = struct {
10301028 .func_inferred,
10311029 .has_decl,
10321030 .int,
1031 .int_big,
10331032 .float,
10341033 .float128,
10351034 .intcast,
......@@ -1061,7 +1060,6 @@ pub const Inst = struct {
10611060 .typeof_elem,
10621061 .xor,
10631062 .optional_type,
1064 .optional_type_from_ptr_elem,
10651063 .optional_payload_safe,
10661064 .optional_payload_unsafe,
10671065 .optional_payload_safe_ptr,
......@@ -1700,17 +1698,6 @@ pub const Inst = struct {
17001698 return code.string_bytes[self.start..][0..self.len];
17011699 }
17021700 },
1703 /// Strings 8 or fewer bytes which may not contain null bytes.
1704 small_str: struct {
1705 bytes: [8]u8,
1706
1707 pub fn get(self: @This()) []const u8 {
1708 const end = for (self.bytes) |byte, i| {
1709 if (byte == 0) break i;
1710 } else self.bytes.len;
1711 return self.bytes[0..end];
1712 }
1713 },
17141701 str_tok: struct {
17151702 /// Offset into `string_bytes`. Null-terminated.
17161703 start: u32,
......@@ -2324,7 +2311,6 @@ const Writer = struct {
23242311 .ret_node,
23252312 .resolve_inferred_alloc,
23262313 .optional_type,
2327 .optional_type_from_ptr_elem,
23282314 .optional_payload_safe,
23292315 .optional_payload_unsafe,
23302316 .optional_payload_safe_ptr,
......@@ -2405,6 +2391,7 @@ const Writer = struct {
24052391 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
24062392 .ptr_type => try self.writePtrType(stream, inst),
24072393 .int => try self.writeInt(stream, inst),
2394 .int_big => try self.writeIntBig(stream, inst),
24082395 .float => try self.writeFloat(stream, inst),
24092396 .float128 => try self.writeFloat128(stream, inst),
24102397 .str => try self.writeStr(stream, inst),
......@@ -2710,15 +2697,30 @@ const Writer = struct {
27102697 try stream.writeAll("TODO)");
27112698 }
27122699
2713 fn writeInt(
2714 self: *Writer,
2715 stream: anytype,
2716 inst: Inst.Index,
2717 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2700 fn writeInt(self: *Writer, stream: anytype, inst: Inst.Index) !void {
27182701 const inst_data = self.code.instructions.items(.data)[inst].int;
27192702 try stream.print("{d})", .{inst_data});
27202703 }
27212704
2705 fn writeIntBig(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2706 const inst_data = self.code.instructions.items(.data)[inst].str;
2707 const byte_count = inst_data.len * @sizeOf(std.math.big.Limb);
2708 const limb_bytes = self.code.string_bytes[inst_data.start..][0..byte_count];
2709 // limb_bytes is not aligned properly; we must allocate and copy the bytes
2710 // in order to accomplish this.
2711 const limbs = try self.gpa.alloc(std.math.big.Limb, inst_data.len);
2712 defer self.gpa.free(limbs);
2713
2714 mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes);
2715 const big_int: std.math.big.int.Const = .{
2716 .limbs = limbs,
2717 .positive = true,
2718 };
2719 const as_string = try big_int.toStringAlloc(self.gpa, 10, false);
2720 defer self.gpa.free(as_string);
2721 try stream.print("{s})", .{as_string});
2722 }
2723
27222724 fn writeFloat(self: *Writer, stream: anytype, inst: Inst.Index) !void {
27232725 const inst_data = self.code.instructions.items(.data)[inst].float;
27242726 const src = inst_data.src();