Merge pull request #5130 from ziglang/stage2-ir
beginnings of non-LLVM self-hosted backend
This commit is contained in:
commit
e8545db9d4
@ -1012,25 +1012,27 @@ pub const Dir = struct {
|
||||
/// On success, caller owns returned buffer.
|
||||
/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
|
||||
pub fn readFileAlloc(self: Dir, allocator: *mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 {
|
||||
return self.readFileAllocAligned(allocator, file_path, max_bytes, @alignOf(u8));
|
||||
return self.readFileAllocOptions(allocator, file_path, max_bytes, @alignOf(u8), null);
|
||||
}
|
||||
|
||||
/// On success, caller owns returned buffer.
|
||||
/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
|
||||
pub fn readFileAllocAligned(
|
||||
/// Allows specifying alignment and a sentinel value.
|
||||
pub fn readFileAllocOptions(
|
||||
self: Dir,
|
||||
allocator: *mem.Allocator,
|
||||
file_path: []const u8,
|
||||
max_bytes: usize,
|
||||
comptime A: u29,
|
||||
) ![]align(A) u8 {
|
||||
comptime alignment: u29,
|
||||
comptime optional_sentinel: ?u8,
|
||||
) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) {
|
||||
var file = try self.openFile(file_path, .{});
|
||||
defer file.close();
|
||||
|
||||
const size = math.cast(usize, try file.getEndPos()) catch math.maxInt(usize);
|
||||
if (size > max_bytes) return error.FileTooBig;
|
||||
|
||||
const buf = try allocator.alignedAlloc(u8, A, size);
|
||||
const buf = try allocator.allocWithOptions(u8, size, alignment, optional_sentinel);
|
||||
errdefer allocator.free(buf);
|
||||
|
||||
try file.inStream().readNoEof(buf);
|
||||
|
@ -143,12 +143,15 @@ pub const Int = struct {
|
||||
/// Clones an Int and returns a new Int with the same value. The new Int is a deep copy and
|
||||
/// can be modified separately from the original.
|
||||
pub fn clone(other: Int) !Int {
|
||||
other.assertWritable();
|
||||
return other.clone2(other.allocator.?);
|
||||
}
|
||||
|
||||
pub fn clone2(other: Int, allocator: *Allocator) !Int {
|
||||
return Int{
|
||||
.allocator = other.allocator,
|
||||
.allocator = allocator,
|
||||
.metadata = other.metadata,
|
||||
.limbs = block: {
|
||||
var limbs = try other.allocator.?.alloc(Limb, other.len());
|
||||
var limbs = try allocator.alloc(Limb, other.len());
|
||||
mem.copy(Limb, limbs[0..], other.limbs[0..other.len()]);
|
||||
break :block limbs;
|
||||
},
|
||||
@ -237,7 +240,7 @@ pub const Int = struct {
|
||||
return bits;
|
||||
}
|
||||
|
||||
fn fitsInTwosComp(self: Int, is_signed: bool, bit_count: usize) bool {
|
||||
pub fn fitsInTwosComp(self: Int, is_signed: bool, bit_count: usize) bool {
|
||||
if (self.eqZero()) {
|
||||
return true;
|
||||
}
|
||||
@ -470,8 +473,8 @@ pub const Int = struct {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // Non power-of-two: batch divisions per word size.
|
||||
else {
|
||||
} else {
|
||||
// Non power-of-two: batch divisions per word size.
|
||||
const digits_per_limb = math.log(Limb, base, maxInt(Limb));
|
||||
var limb_base: Limb = 1;
|
||||
var j: usize = 0;
|
||||
@ -479,7 +482,7 @@ pub const Int = struct {
|
||||
limb_base *= base;
|
||||
}
|
||||
|
||||
var q = try self.clone();
|
||||
var q = try self.clone2(allocator);
|
||||
defer q.deinit();
|
||||
q.abs();
|
||||
var r = try Int.init(allocator);
|
||||
@ -522,15 +525,13 @@ pub const Int = struct {
|
||||
|
||||
/// To allow `std.fmt.printf` to work with Int.
|
||||
/// TODO make this non-allocating
|
||||
/// TODO support read-only fixed integers
|
||||
pub fn format(
|
||||
self: Int,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
out_stream: var,
|
||||
) !void {
|
||||
self.assertWritable();
|
||||
// TODO support read-only fixed integers
|
||||
|
||||
comptime var radix = 10;
|
||||
comptime var uppercase = false;
|
||||
|
||||
@ -550,8 +551,9 @@ pub const Int = struct {
|
||||
@compileError("Unknown format string: '" ++ fmt ++ "'");
|
||||
}
|
||||
|
||||
const str = self.toString(self.allocator.?, radix, uppercase) catch @panic("TODO make this non allocating");
|
||||
defer self.allocator.?.free(str);
|
||||
var buf: [4096]u8 = undefined;
|
||||
var fba = std.heap.FixedBufferAllocator.init(&buf);
|
||||
const str = self.toString(&fba.allocator, radix, uppercase) catch @panic("TODO make this non allocating");
|
||||
return out_stream.writeAll(str);
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,31 @@ pub const Allocator = struct {
|
||||
return self.alignedAlloc(T, null, n);
|
||||
}
|
||||
|
||||
pub fn allocWithOptions(
|
||||
self: *Allocator,
|
||||
comptime Elem: type,
|
||||
n: usize,
|
||||
/// null means naturally aligned
|
||||
comptime optional_alignment: ?u29,
|
||||
comptime optional_sentinel: ?Elem,
|
||||
) Error!AllocWithOptionsPayload(Elem, optional_alignment, optional_sentinel) {
|
||||
if (optional_sentinel) |sentinel| {
|
||||
const ptr = try self.alignedAlloc(Elem, optional_alignment, n + 1);
|
||||
ptr[n] = sentinel;
|
||||
return ptr[0..n :sentinel];
|
||||
} else {
|
||||
return self.alignedAlloc(Elem, optional_alignment, n);
|
||||
}
|
||||
}
|
||||
|
||||
fn AllocWithOptionsPayload(comptime Elem: type, comptime alignment: ?u29, comptime sentinel: ?Elem) type {
|
||||
if (sentinel) |s| {
|
||||
return [:s]align(alignment orelse @alignOf(T)) Elem;
|
||||
} else {
|
||||
return []align(alignment orelse @alignOf(T)) Elem;
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates an array of `n + 1` items of type `T` and sets the first `n`
|
||||
/// items to `undefined` and the last item to `sentinel`. Depending on the
|
||||
/// Allocator implementation, it may be required to call `free` once the
|
||||
@ -113,10 +138,10 @@ pub const Allocator = struct {
|
||||
/// call `free` when done.
|
||||
///
|
||||
/// For allocating a single item, see `create`.
|
||||
///
|
||||
/// Deprecated; use `allocWithOptions`.
|
||||
pub fn allocSentinel(self: *Allocator, comptime Elem: type, n: usize, comptime sentinel: Elem) Error![:sentinel]Elem {
|
||||
var ptr = try self.alloc(Elem, n + 1);
|
||||
ptr[n] = sentinel;
|
||||
return ptr[0..n :sentinel];
|
||||
return self.allocWithOptions(Elem, n, null, sentinel);
|
||||
}
|
||||
|
||||
pub fn alignedAlloc(
|
||||
|
@ -761,7 +761,7 @@ pub const Target = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn ptrBitWidth(arch: Arch) u32 {
|
||||
pub fn ptrBitWidth(arch: Arch) u16 {
|
||||
switch (arch) {
|
||||
.avr,
|
||||
.msp430,
|
||||
|
@ -2,8 +2,9 @@ const tokenizer = @import("zig/tokenizer.zig");
|
||||
pub const Token = tokenizer.Token;
|
||||
pub const Tokenizer = tokenizer.Tokenizer;
|
||||
pub const parse = @import("zig/parse.zig").parse;
|
||||
pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStringLiteral;
|
||||
pub const parseStringLiteral = @import("zig/string_literal.zig").parse;
|
||||
pub const render = @import("zig/render.zig").render;
|
||||
pub const renderStringLiteral = @import("zig/string_literal.zig").render;
|
||||
pub const ast = @import("zig/ast.zig");
|
||||
pub const system = @import("zig/system.zig");
|
||||
pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
|
||||
|
@ -6,7 +6,7 @@ const State = enum {
|
||||
Backslash,
|
||||
};
|
||||
|
||||
pub const ParseStringLiteralError = error{
|
||||
pub const ParseError = error{
|
||||
OutOfMemory,
|
||||
|
||||
/// When this is returned, index will be the position of the character.
|
||||
@ -14,11 +14,11 @@ pub const ParseStringLiteralError = error{
|
||||
};
|
||||
|
||||
/// caller owns returned memory
|
||||
pub fn parseStringLiteral(
|
||||
pub fn parse(
|
||||
allocator: *std.mem.Allocator,
|
||||
bytes: []const u8,
|
||||
bad_index: *usize, // populated if error.InvalidCharacter is returned
|
||||
) ParseStringLiteralError![]u8 {
|
||||
) ParseError![]u8 {
|
||||
assert(bytes.len >= 2 and bytes[0] == '"' and bytes[bytes.len - 1] == '"');
|
||||
|
||||
var list = std.ArrayList(u8).init(allocator);
|
||||
@ -110,7 +110,7 @@ pub fn parseStringLiteral(
|
||||
unreachable;
|
||||
}
|
||||
|
||||
test "parseStringLiteral" {
|
||||
test "parse" {
|
||||
const expect = std.testing.expect;
|
||||
const eql = std.mem.eql;
|
||||
|
||||
@ -119,7 +119,37 @@ test "parseStringLiteral" {
|
||||
var alloc = &fixed_buf_alloc.allocator;
|
||||
var bad_index: usize = undefined;
|
||||
|
||||
expect(eql(u8, "foo", try parseStringLiteral(alloc, "\"foo\"", &bad_index)));
|
||||
expect(eql(u8, "foo", try parseStringLiteral(alloc, "\"f\x6f\x6f\"", &bad_index)));
|
||||
expect(eql(u8, "f💯", try parseStringLiteral(alloc, "\"f\u{1f4af}\"", &bad_index)));
|
||||
expect(eql(u8, "foo", try parse(alloc, "\"foo\"", &bad_index)));
|
||||
expect(eql(u8, "foo", try parse(alloc, "\"f\x6f\x6f\"", &bad_index)));
|
||||
expect(eql(u8, "f💯", try parse(alloc, "\"f\u{1f4af}\"", &bad_index)));
|
||||
}
|
||||
|
||||
/// Writes a Zig-syntax escaped string literal to the stream. Includes the double quotes.
|
||||
pub fn render(utf8: []const u8, out_stream: var) !void {
|
||||
try out_stream.writeByte('"');
|
||||
for (utf8) |byte| switch (byte) {
|
||||
'\n' => try out_stream.writeAll("\\n"),
|
||||
'\r' => try out_stream.writeAll("\\r"),
|
||||
'\t' => try out_stream.writeAll("\\t"),
|
||||
'\\' => try out_stream.writeAll("\\\\"),
|
||||
'"' => try out_stream.writeAll("\\\""),
|
||||
' ', '!', '#'...'[', ']'...'~' => try out_stream.writeByte(byte),
|
||||
else => try out_stream.print("\\x{x:0>2}", .{byte}),
|
||||
};
|
||||
try out_stream.writeByte('"');
|
||||
}
|
||||
|
||||
test "render" {
|
||||
const expect = std.testing.expect;
|
||||
const eql = std.mem.eql;
|
||||
|
||||
var fixed_buf_mem: [32]u8 = undefined;
|
||||
|
||||
{
|
||||
var fbs = std.io.fixedBufferStream(&fixed_buf_mem);
|
||||
try render(" \\ hi \x07 \x11 \" derp", fbs.outStream());
|
||||
expect(eql(u8,
|
||||
\\" \\ hi \x07 \x11 \" derp"
|
||||
, fbs.getWritten()));
|
||||
}
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
const Target = @import("std").Target;
|
||||
|
||||
pub const CInt = struct {
|
||||
id: Id,
|
||||
zig_name: []const u8,
|
||||
c_name: []const u8,
|
||||
is_signed: bool,
|
||||
|
||||
pub const Id = enum {
|
||||
Short,
|
||||
UShort,
|
||||
Int,
|
||||
UInt,
|
||||
Long,
|
||||
ULong,
|
||||
LongLong,
|
||||
ULongLong,
|
||||
};
|
||||
|
||||
pub const list = [_]CInt{
|
||||
CInt{
|
||||
.id = .Short,
|
||||
.zig_name = "c_short",
|
||||
.c_name = "short",
|
||||
.is_signed = true,
|
||||
},
|
||||
CInt{
|
||||
.id = .UShort,
|
||||
.zig_name = "c_ushort",
|
||||
.c_name = "unsigned short",
|
||||
.is_signed = false,
|
||||
},
|
||||
CInt{
|
||||
.id = .Int,
|
||||
.zig_name = "c_int",
|
||||
.c_name = "int",
|
||||
.is_signed = true,
|
||||
},
|
||||
CInt{
|
||||
.id = .UInt,
|
||||
.zig_name = "c_uint",
|
||||
.c_name = "unsigned int",
|
||||
.is_signed = false,
|
||||
},
|
||||
CInt{
|
||||
.id = .Long,
|
||||
.zig_name = "c_long",
|
||||
.c_name = "long",
|
||||
.is_signed = true,
|
||||
},
|
||||
CInt{
|
||||
.id = .ULong,
|
||||
.zig_name = "c_ulong",
|
||||
.c_name = "unsigned long",
|
||||
.is_signed = false,
|
||||
},
|
||||
CInt{
|
||||
.id = .LongLong,
|
||||
.zig_name = "c_longlong",
|
||||
.c_name = "long long",
|
||||
.is_signed = true,
|
||||
},
|
||||
CInt{
|
||||
.id = .ULongLong,
|
||||
.zig_name = "c_ulonglong",
|
||||
.c_name = "unsigned long long",
|
||||
.is_signed = false,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn sizeInBits(cint: CInt, self: Target) u32 {
|
||||
const arch = self.cpu.arch;
|
||||
switch (self.os.tag) {
|
||||
.freestanding, .other => switch (self.cpu.arch) {
|
||||
.msp430 => switch (cint.id) {
|
||||
.Short,
|
||||
.UShort,
|
||||
.Int,
|
||||
.UInt,
|
||||
=> return 16,
|
||||
.Long,
|
||||
.ULong,
|
||||
=> return 32,
|
||||
.LongLong,
|
||||
.ULongLong,
|
||||
=> return 64,
|
||||
},
|
||||
else => switch (cint.id) {
|
||||
.Short,
|
||||
.UShort,
|
||||
=> return 16,
|
||||
.Int,
|
||||
.UInt,
|
||||
=> return 32,
|
||||
.Long,
|
||||
.ULong,
|
||||
=> return self.cpu.arch.ptrBitWidth(),
|
||||
.LongLong,
|
||||
.ULongLong,
|
||||
=> return 64,
|
||||
},
|
||||
},
|
||||
|
||||
.linux,
|
||||
.macosx,
|
||||
.freebsd,
|
||||
.openbsd,
|
||||
=> switch (cint.id) {
|
||||
.Short,
|
||||
.UShort,
|
||||
=> return 16,
|
||||
.Int,
|
||||
.UInt,
|
||||
=> return 32,
|
||||
.Long,
|
||||
.ULong,
|
||||
=> return self.cpu.arch.ptrBitWidth(),
|
||||
.LongLong,
|
||||
.ULongLong,
|
||||
=> return 64,
|
||||
},
|
||||
|
||||
.windows, .uefi => switch (cint.id) {
|
||||
.Short,
|
||||
.UShort,
|
||||
=> return 16,
|
||||
.Int,
|
||||
.UInt,
|
||||
=> return 32,
|
||||
.Long,
|
||||
.ULong,
|
||||
.LongLong,
|
||||
.ULongLong,
|
||||
=> return 64,
|
||||
},
|
||||
|
||||
.ananas,
|
||||
.cloudabi,
|
||||
.dragonfly,
|
||||
.fuchsia,
|
||||
.ios,
|
||||
.kfreebsd,
|
||||
.lv2,
|
||||
.netbsd,
|
||||
.solaris,
|
||||
.haiku,
|
||||
.minix,
|
||||
.rtems,
|
||||
.nacl,
|
||||
.cnk,
|
||||
.aix,
|
||||
.cuda,
|
||||
.nvcl,
|
||||
.amdhsa,
|
||||
.ps4,
|
||||
.elfiamcu,
|
||||
.tvos,
|
||||
.watchos,
|
||||
.mesa3d,
|
||||
.contiki,
|
||||
.amdpal,
|
||||
.hermit,
|
||||
.hurd,
|
||||
.wasi,
|
||||
.emscripten,
|
||||
=> @panic("TODO specify the C integer type sizes for this OS"),
|
||||
}
|
||||
}
|
||||
};
|
File diff suppressed because it is too large
Load Diff
1065
src-self-hosted/ir/text.zig
Normal file
1065
src-self-hosted/ir/text.zig
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -11283,9 +11283,9 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstGen *instruction
|
||||
Buf *val_buf = buf_alloc();
|
||||
bigint_append_buf(val_buf, &const_val->data.x_bigint, 10);
|
||||
ir_add_error_node(ira, instruction->base.source_node,
|
||||
buf_sprintf("integer value %s has no representation in type '%s'",
|
||||
buf_ptr(val_buf),
|
||||
buf_ptr(&other_type->name)));
|
||||
buf_sprintf("type %s cannot represent integer value %s",
|
||||
buf_ptr(&other_type->name),
|
||||
buf_ptr(val_buf)));
|
||||
return false;
|
||||
}
|
||||
if (other_type->data.floating.bit_count >= const_val->type->data.floating.bit_count) {
|
||||
|
54
test/stage2/ir.zig
Normal file
54
test/stage2/ir.zig
Normal file
@ -0,0 +1,54 @@
|
||||
test "hello world IR" {
|
||||
exeCmp(
|
||||
\\@0 = str("Hello, world!\n")
|
||||
\\@1 = primitive(void)
|
||||
\\@2 = primitive(usize)
|
||||
\\@3 = fntype([], @1, cc=Naked)
|
||||
\\@4 = int(0)
|
||||
\\@5 = int(1)
|
||||
\\@6 = int(231)
|
||||
\\@7 = str("len")
|
||||
\\
|
||||
\\@8 = fn(@3, {
|
||||
\\ %0 = as(@2, @5) ; SYS_write
|
||||
\\ %1 = as(@2, @5) ; STDOUT_FILENO
|
||||
\\ %2 = ptrtoint(@0) ; msg ptr
|
||||
\\ %3 = fieldptr(@0, @7) ; msg len ptr
|
||||
\\ %4 = deref(%3) ; msg len
|
||||
\\ %sysoutreg = str("={rax}")
|
||||
\\ %rax = str("{rax}")
|
||||
\\ %rdi = str("{rdi}")
|
||||
\\ %rsi = str("{rsi}")
|
||||
\\ %rdx = str("{rdx}")
|
||||
\\ %rcx = str("rcx")
|
||||
\\ %r11 = str("r11")
|
||||
\\ %memory = str("memory")
|
||||
\\ %syscall = str("syscall")
|
||||
\\ %5 = asm(%syscall, @2,
|
||||
\\ volatile=1,
|
||||
\\ output=%sysoutreg,
|
||||
\\ inputs=[%rax, %rdi, %rsi, %rdx],
|
||||
\\ clobbers=[%rcx, %r11, %memory],
|
||||
\\ args=[%0, %1, %2, %4])
|
||||
\\
|
||||
\\ %6 = as(@2, @6) ;SYS_exit_group
|
||||
\\ %7 = as(@2, @4) ;exit code
|
||||
\\ %8 = asm(%syscall, @2,
|
||||
\\ volatile=1,
|
||||
\\ output=%sysoutreg,
|
||||
\\ inputs=[%rax, %rdi],
|
||||
\\ clobbers=[%rcx, %r11, %memory],
|
||||
\\ args=[%6, %7])
|
||||
\\
|
||||
\\ %9 = unreachable()
|
||||
\\})
|
||||
\\
|
||||
\\@9 = str("_start")
|
||||
\\@10 = export(@9, @8)
|
||||
,
|
||||
\\Hello, world!
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
fn exeCmp(src: []const u8, expected_stdout: []const u8) void {}
|
Loading…
x
Reference in New Issue
Block a user