sync Aro dependency

ref: 0c8c251e336148413ceca7b345c0b6f7255b009b
This commit is contained in:
Veikka Tuominen 2023-11-15 11:26:49 +02:00
parent c327489d21
commit 145ddb8104
61 changed files with 9225 additions and 19652 deletions

File diff suppressed because it is too large Load Diff

487
deps/aro/CharInfo.zig vendored
View File

@ -1,487 +0,0 @@
//! This module provides functions for classifying characters according to
//! various C standards. All classification routines *do not* consider
//! characters from the basic character set; it is assumed those will be
//! checked separately
const assert = @import("std").debug.assert;
/// C11 Standard Annex D
pub fn isC11IdChar(codepoint: u21) bool {
assert(codepoint > 0x7F);
return switch (codepoint) {
// 1
0x00A8,
0x00AA,
0x00AD,
0x00AF,
0x00B2...0x00B5,
0x00B7...0x00BA,
0x00BC...0x00BE,
0x00C0...0x00D6,
0x00D8...0x00F6,
0x00F8...0x00FF,
// 2
0x0100...0x167F,
0x1681...0x180D,
0x180F...0x1FFF,
// 3
0x200B...0x200D,
0x202A...0x202E,
0x203F...0x2040,
0x2054,
0x2060...0x206F,
// 4
0x2070...0x218F,
0x2460...0x24FF,
0x2776...0x2793,
0x2C00...0x2DFF,
0x2E80...0x2FFF,
// 5
0x3004...0x3007,
0x3021...0x302F,
0x3031...0x303F,
// 6
0x3040...0xD7FF,
// 7
0xF900...0xFD3D,
0xFD40...0xFDCF,
0xFDF0...0xFE44,
0xFE47...0xFFFD,
// 8
0x10000...0x1FFFD,
0x20000...0x2FFFD,
0x30000...0x3FFFD,
0x40000...0x4FFFD,
0x50000...0x5FFFD,
0x60000...0x6FFFD,
0x70000...0x7FFFD,
0x80000...0x8FFFD,
0x90000...0x9FFFD,
0xA0000...0xAFFFD,
0xB0000...0xBFFFD,
0xC0000...0xCFFFD,
0xD0000...0xDFFFD,
0xE0000...0xEFFFD,
=> true,
else => false,
};
}
/// C99 Standard Annex D
pub fn isC99IdChar(codepoint: u21) bool {
assert(codepoint > 0x7F);
return switch (codepoint) {
// Latin
0x00AA,
0x00BA,
0x00C0...0x00D6,
0x00D8...0x00F6,
0x00F8...0x01F5,
0x01FA...0x0217,
0x0250...0x02A8,
0x1E00...0x1E9B,
0x1EA0...0x1EF9,
0x207F,
// Greek
0x0386,
0x0388...0x038A,
0x038C,
0x038E...0x03A1,
0x03A3...0x03CE,
0x03D0...0x03D6,
0x03DA,
0x03DC,
0x03DE,
0x03E0,
0x03E2...0x03F3,
0x1F00...0x1F15,
0x1F18...0x1F1D,
0x1F20...0x1F45,
0x1F48...0x1F4D,
0x1F50...0x1F57,
0x1F59,
0x1F5B,
0x1F5D,
0x1F5F...0x1F7D,
0x1F80...0x1FB4,
0x1FB6...0x1FBC,
0x1FC2...0x1FC4,
0x1FC6...0x1FCC,
0x1FD0...0x1FD3,
0x1FD6...0x1FDB,
0x1FE0...0x1FEC,
0x1FF2...0x1FF4,
0x1FF6...0x1FFC,
// Cyrillic
0x0401...0x040C,
0x040E...0x044F,
0x0451...0x045C,
0x045E...0x0481,
0x0490...0x04C4,
0x04C7...0x04C8,
0x04CB...0x04CC,
0x04D0...0x04EB,
0x04EE...0x04F5,
0x04F8...0x04F9,
// Armenian
0x0531...0x0556,
0x0561...0x0587,
// Hebrew
0x05B0...0x05B9,
0x05BB...0x05BD,
0x05BF,
0x05C1...0x05C2,
0x05D0...0x05EA,
0x05F0...0x05F2,
// Arabic
0x0621...0x063A,
0x0640...0x0652,
0x0670...0x06B7,
0x06BA...0x06BE,
0x06C0...0x06CE,
0x06D0...0x06DC,
0x06E5...0x06E8,
0x06EA...0x06ED,
// Devanagari
0x0901...0x0903,
0x0905...0x0939,
0x093E...0x094D,
0x0950...0x0952,
0x0958...0x0963,
// Bengali
0x0981...0x0983,
0x0985...0x098C,
0x098F...0x0990,
0x0993...0x09A8,
0x09AA...0x09B0,
0x09B2,
0x09B6...0x09B9,
0x09BE...0x09C4,
0x09C7...0x09C8,
0x09CB...0x09CD,
0x09DC...0x09DD,
0x09DF...0x09E3,
0x09F0...0x09F1,
// Gurmukhi
0x0A02,
0x0A05...0x0A0A,
0x0A0F...0x0A10,
0x0A13...0x0A28,
0x0A2A...0x0A30,
0x0A32...0x0A33,
0x0A35...0x0A36,
0x0A38...0x0A39,
0x0A3E...0x0A42,
0x0A47...0x0A48,
0x0A4B...0x0A4D,
0x0A59...0x0A5C,
0x0A5E,
0x0A74,
// Gujarati
0x0A81...0x0A83,
0x0A85...0x0A8B,
0x0A8D,
0x0A8F...0x0A91,
0x0A93...0x0AA8,
0x0AAA...0x0AB0,
0x0AB2...0x0AB3,
0x0AB5...0x0AB9,
0x0ABD...0x0AC5,
0x0AC7...0x0AC9,
0x0ACB...0x0ACD,
0x0AD0,
0x0AE0,
// Oriya
0x0B01...0x0B03,
0x0B05...0x0B0C,
0x0B0F...0x0B10,
0x0B13...0x0B28,
0x0B2A...0x0B30,
0x0B32...0x0B33,
0x0B36...0x0B39,
0x0B3E...0x0B43,
0x0B47...0x0B48,
0x0B4B...0x0B4D,
0x0B5C...0x0B5D,
0x0B5F...0x0B61,
// Tamil
0x0B82...0x0B83,
0x0B85...0x0B8A,
0x0B8E...0x0B90,
0x0B92...0x0B95,
0x0B99...0x0B9A,
0x0B9C,
0x0B9E...0x0B9F,
0x0BA3...0x0BA4,
0x0BA8...0x0BAA,
0x0BAE...0x0BB5,
0x0BB7...0x0BB9,
0x0BBE...0x0BC2,
0x0BC6...0x0BC8,
0x0BCA...0x0BCD,
// Telugu
0x0C01...0x0C03,
0x0C05...0x0C0C,
0x0C0E...0x0C10,
0x0C12...0x0C28,
0x0C2A...0x0C33,
0x0C35...0x0C39,
0x0C3E...0x0C44,
0x0C46...0x0C48,
0x0C4A...0x0C4D,
0x0C60...0x0C61,
// Kannada
0x0C82...0x0C83,
0x0C85...0x0C8C,
0x0C8E...0x0C90,
0x0C92...0x0CA8,
0x0CAA...0x0CB3,
0x0CB5...0x0CB9,
0x0CBE...0x0CC4,
0x0CC6...0x0CC8,
0x0CCA...0x0CCD,
0x0CDE,
0x0CE0...0x0CE1,
// Malayalam
0x0D02...0x0D03,
0x0D05...0x0D0C,
0x0D0E...0x0D10,
0x0D12...0x0D28,
0x0D2A...0x0D39,
0x0D3E...0x0D43,
0x0D46...0x0D48,
0x0D4A...0x0D4D,
0x0D60...0x0D61,
// Thai (excluding digits 0x0E50...0x0E59; originally 0x0E01...0x0E3A and 0x0E40...0x0E5B
0x0E01...0x0E3A,
0x0E40...0x0E4F,
0x0E5A...0x0E5B,
// Lao
0x0E81...0x0E82,
0x0E84,
0x0E87...0x0E88,
0x0E8A,
0x0E8D,
0x0E94...0x0E97,
0x0E99...0x0E9F,
0x0EA1...0x0EA3,
0x0EA5,
0x0EA7,
0x0EAA...0x0EAB,
0x0EAD...0x0EAE,
0x0EB0...0x0EB9,
0x0EBB...0x0EBD,
0x0EC0...0x0EC4,
0x0EC6,
0x0EC8...0x0ECD,
0x0EDC...0x0EDD,
// Tibetan
0x0F00,
0x0F18...0x0F19,
0x0F35,
0x0F37,
0x0F39,
0x0F3E...0x0F47,
0x0F49...0x0F69,
0x0F71...0x0F84,
0x0F86...0x0F8B,
0x0F90...0x0F95,
0x0F97,
0x0F99...0x0FAD,
0x0FB1...0x0FB7,
0x0FB9,
// Georgian
0x10A0...0x10C5,
0x10D0...0x10F6,
// Hiragana
0x3041...0x3093,
0x309B...0x309C,
// Katakana
0x30A1...0x30F6,
0x30FB...0x30FC,
// Bopomofo
0x3105...0x312C,
// CJK Unified Ideographs
0x4E00...0x9FA5,
// Hangul
0xAC00...0xD7A3,
// Digits
0x0660...0x0669,
0x06F0...0x06F9,
0x0966...0x096F,
0x09E6...0x09EF,
0x0A66...0x0A6F,
0x0AE6...0x0AEF,
0x0B66...0x0B6F,
0x0BE7...0x0BEF,
0x0C66...0x0C6F,
0x0CE6...0x0CEF,
0x0D66...0x0D6F,
0x0E50...0x0E59,
0x0ED0...0x0ED9,
0x0F20...0x0F33,
// Special characters
0x00B5,
0x00B7,
0x02B0...0x02B8,
0x02BB,
0x02BD...0x02C1,
0x02D0...0x02D1,
0x02E0...0x02E4,
0x037A,
0x0559,
0x093D,
0x0B3D,
0x1FBE,
0x203F...0x2040,
0x2102,
0x2107,
0x210A...0x2113,
0x2115,
0x2118...0x211D,
0x2124,
0x2126,
0x2128,
0x212A...0x2131,
0x2133...0x2138,
0x2160...0x2182,
0x3005...0x3007,
0x3021...0x3029,
=> true,
else => false,
};
}
/// C11 standard Annex D
pub fn isC11DisallowedInitialIdChar(codepoint: u21) bool {
assert(codepoint > 0x7F);
return switch (codepoint) {
0x0300...0x036F,
0x1DC0...0x1DFF,
0x20D0...0x20FF,
0xFE20...0xFE2F,
=> true,
else => false,
};
}
/// These are "digit" characters; C99 disallows them as the first
/// character of an identifier
pub fn isC99DisallowedInitialIDChar(codepoint: u21) bool {
assert(codepoint > 0x7F);
return switch (codepoint) {
0x0660...0x0669,
0x06F0...0x06F9,
0x0966...0x096F,
0x09E6...0x09EF,
0x0A66...0x0A6F,
0x0AE6...0x0AEF,
0x0B66...0x0B6F,
0x0BE7...0x0BEF,
0x0C66...0x0C6F,
0x0CE6...0x0CEF,
0x0D66...0x0D6F,
0x0E50...0x0E59,
0x0ED0...0x0ED9,
0x0F20...0x0F33,
=> true,
else => false,
};
}
pub fn isInvisible(codepoint: u21) bool {
assert(codepoint > 0x7F);
return switch (codepoint) {
0x00ad, // SOFT HYPHEN
0x200b, // ZERO WIDTH SPACE
0x200c, // ZERO WIDTH NON-JOINER
0x200d, // ZERO WIDTH JOINER
0x2060, // WORD JOINER
0x2061, // FUNCTION APPLICATION
0x2062, // INVISIBLE TIMES
0x2063, // INVISIBLE SEPARATOR
0x2064, // INVISIBLE PLUS
0xfeff, // ZERO WIDTH NO-BREAK SPACE
=> true,
else => false,
};
}
/// Checks for identifier characters which resemble non-identifier characters
pub fn homoglyph(codepoint: u21) ?u21 {
assert(codepoint > 0x7F);
return switch (codepoint) {
0x01c3 => '!', // LATIN LETTER RETROFLEX CLICK
0x037e => ';', // GREEK QUESTION MARK
0x2212 => '-', // MINUS SIGN
0x2215 => '/', // DIVISION SLASH
0x2216 => '\\', // SET MINUS
0x2217 => '*', // ASTERISK OPERATOR
0x2223 => '|', // DIVIDES
0x2227 => '^', // LOGICAL AND
0x2236 => ':', // RATIO
0x223c => '~', // TILDE OPERATOR
0xa789 => ':', // MODIFIER LETTER COLON
0xff01 => '!', // FULLWIDTH EXCLAMATION MARK
0xff03 => '#', // FULLWIDTH NUMBER SIGN
0xff04 => '$', // FULLWIDTH DOLLAR SIGN
0xff05 => '%', // FULLWIDTH PERCENT SIGN
0xff06 => '&', // FULLWIDTH AMPERSAND
0xff08 => '(', // FULLWIDTH LEFT PARENTHESIS
0xff09 => ')', // FULLWIDTH RIGHT PARENTHESIS
0xff0a => '*', // FULLWIDTH ASTERISK
0xff0b => '+', // FULLWIDTH ASTERISK
0xff0c => ',', // FULLWIDTH COMMA
0xff0d => '-', // FULLWIDTH HYPHEN-MINUS
0xff0e => '.', // FULLWIDTH FULL STOP
0xff0f => '/', // FULLWIDTH SOLIDUS
0xff1a => ':', // FULLWIDTH COLON
0xff1b => ';', // FULLWIDTH SEMICOLON
0xff1c => '<', // FULLWIDTH LESS-THAN SIGN
0xff1d => '=', // FULLWIDTH EQUALS SIGN
0xff1e => '>', // FULLWIDTH GREATER-THAN SIGN
0xff1f => '?', // FULLWIDTH QUESTION MARK
0xff20 => '@', // FULLWIDTH COMMERCIAL AT
0xff3b => '[', // FULLWIDTH LEFT SQUARE BRACKET
0xff3c => '\\', // FULLWIDTH REVERSE SOLIDUS
0xff3d => ']', // FULLWIDTH RIGHT SQUARE BRACKET
0xff3e => '^', // FULLWIDTH CIRCUMFLEX ACCENT
0xff5b => '{', // FULLWIDTH LEFT CURLY BRACKET
0xff5c => '|', // FULLWIDTH VERTICAL LINE
0xff5d => '}', // FULLWIDTH RIGHT CURLY BRACKET
0xff5e => '~', // FULLWIDTH TILDE
else => null,
};
}

View File

@ -1,298 +0,0 @@
const std = @import("std");
const Compilation = @import("Compilation.zig");
const Type = @import("Type.zig");
const Diagnostics = @import("Diagnostics.zig");
const Tokenizer = @import("Tokenizer.zig");
const mem = std.mem;
pub const Item = union(enum) {
/// decoded escape
value: u32,
/// Char literal in the source text is not utf8 encoded
improperly_encoded: []const u8,
/// 1 or more unescaped bytes
utf8_text: std.unicode.Utf8View,
};
const CharDiagnostic = struct {
tag: Diagnostics.Tag,
extra: Diagnostics.Message.Extra,
};
pub const Kind = enum {
char,
wide,
utf_8,
utf_16,
utf_32,
pub fn classify(id: Tokenizer.Token.Id) Kind {
return switch (id) {
.char_literal,
.string_literal,
=> .char,
.char_literal_utf_8,
.string_literal_utf_8,
=> .utf_8,
.char_literal_wide,
.string_literal_wide,
=> .wide,
.char_literal_utf_16,
.string_literal_utf_16,
=> .utf_16,
.char_literal_utf_32,
.string_literal_utf_32,
=> .utf_32,
else => unreachable,
};
}
/// Largest unicode codepoint that can be represented by this character kind
/// May be smaller than the largest value that can be represented.
/// For example u8 char literals may only specify 0-127 via literals or
/// character escapes, but may specify up to \xFF via hex escapes.
pub fn maxCodepoint(kind: Kind, comp: *const Compilation) u21 {
return @intCast(switch (kind) {
.char => std.math.maxInt(u7),
.wide => @min(0x10FFFF, comp.types.wchar.maxInt(comp)),
.utf_8 => std.math.maxInt(u7),
.utf_16 => std.math.maxInt(u16),
.utf_32 => 0x10FFFF,
});
}
/// Largest integer that can be represented by this character kind
pub fn maxInt(kind: Kind, comp: *const Compilation) u32 {
return @intCast(switch (kind) {
.char, .utf_8 => std.math.maxInt(u8),
.wide => comp.types.wchar.maxInt(comp),
.utf_16 => std.math.maxInt(u16),
.utf_32 => std.math.maxInt(u32),
});
}
pub fn charLiteralType(kind: Kind, comp: *const Compilation) Type {
return switch (kind) {
.char => Type.int,
.wide => comp.types.wchar,
.utf_8 => .{ .specifier = .uchar },
.utf_16 => comp.types.uint_least16_t,
.utf_32 => comp.types.uint_least32_t,
};
}
/// Return the actual contents of the string literal with leading / trailing quotes and
/// specifiers removed
pub fn contentSlice(kind: Kind, delimited: []const u8) []const u8 {
const end = delimited.len - 1; // remove trailing quote
return switch (kind) {
.char => delimited[1..end],
.wide => delimited[2..end],
.utf_8 => delimited[3..end],
.utf_16 => delimited[2..end],
.utf_32 => delimited[2..end],
};
}
};
pub const Parser = struct {
literal: []const u8,
i: usize = 0,
kind: Kind,
/// We only want to issue a max of 1 error per char literal
errored: bool = false,
errors: std.BoundedArray(CharDiagnostic, 4) = .{},
comp: *const Compilation,
pub fn init(literal: []const u8, kind: Kind, comp: *const Compilation) Parser {
return .{
.literal = literal,
.comp = comp,
.kind = kind,
};
}
pub fn err(self: *Parser, tag: Diagnostics.Tag, extra: Diagnostics.Message.Extra) void {
if (self.errored) return;
self.errored = true;
self.errors.append(.{ .tag = tag, .extra = extra }) catch {};
}
pub fn warn(self: *Parser, tag: Diagnostics.Tag, extra: Diagnostics.Message.Extra) void {
if (self.errored) return;
self.errors.append(.{ .tag = tag, .extra = extra }) catch {};
}
pub fn next(self: *Parser) ?Item {
if (self.i >= self.literal.len) return null;
const start = self.i;
if (self.literal[start] != '\\') {
self.i = mem.indexOfScalarPos(u8, self.literal, start + 1, '\\') orelse self.literal.len;
const unescaped_slice = self.literal[start..self.i];
const view = std.unicode.Utf8View.init(unescaped_slice) catch {
if (self.kind != .char) {
self.err(.illegal_char_encoding_error, .{ .none = {} });
} else {
self.warn(.illegal_char_encoding_warning, .{ .none = {} });
}
return .{ .improperly_encoded = self.literal[start..self.i] };
};
return .{ .utf8_text = view };
}
switch (self.literal[start + 1]) {
'u', 'U' => return self.parseUnicodeEscape(),
else => return self.parseEscapedChar(),
}
}
fn parseUnicodeEscape(self: *Parser) ?Item {
const start = self.i;
std.debug.assert(self.literal[self.i] == '\\');
const kind = self.literal[self.i + 1];
std.debug.assert(kind == 'u' or kind == 'U');
self.i += 2;
if (self.i >= self.literal.len or !std.ascii.isHex(self.literal[self.i])) {
self.err(.missing_hex_escape, .{ .ascii = @intCast(kind) });
return null;
}
const expected_len: usize = if (kind == 'u') 4 else 8;
var overflowed = false;
var count: usize = 0;
var val: u32 = 0;
for (self.literal[self.i..], 0..) |c, i| {
if (i == expected_len) break;
const char = std.fmt.charToDigit(c, 16) catch {
break;
};
val, const overflow = @shlWithOverflow(val, 4);
overflowed = overflowed or overflow != 0;
val |= char;
count += 1;
}
self.i += expected_len;
if (overflowed) {
self.err(.escape_sequence_overflow, .{ .unsigned = start });
return null;
}
if (count != expected_len) {
self.err(.incomplete_universal_character, .{ .none = {} });
return null;
}
if (val > std.math.maxInt(u21) or !std.unicode.utf8ValidCodepoint(@intCast(val))) {
self.err(.invalid_universal_character, .{ .unsigned = start });
return null;
}
if (val > self.kind.maxCodepoint(self.comp)) {
self.err(.char_too_large, .{ .none = {} });
}
if (val < 0xA0 and (val != '$' and val != '@' and val != '`')) {
const is_error = !self.comp.langopts.standard.atLeast(.c2x);
if (val >= 0x20 and val <= 0x7F) {
if (is_error) {
self.err(.ucn_basic_char_error, .{ .ascii = @intCast(val) });
} else {
self.warn(.ucn_basic_char_warning, .{ .ascii = @intCast(val) });
}
} else {
if (is_error) {
self.err(.ucn_control_char_error, .{ .none = {} });
} else {
self.warn(.ucn_control_char_warning, .{ .none = {} });
}
}
}
self.warn(.c89_ucn_in_literal, .{ .none = {} });
return .{ .value = val };
}
fn parseEscapedChar(self: *Parser) Item {
self.i += 1;
const c = self.literal[self.i];
defer if (c != 'x' and (c < '0' or c > '7')) {
self.i += 1;
};
switch (c) {
'\n' => unreachable, // removed by line splicing
'\r' => unreachable, // removed by line splicing
'\'', '\"', '\\', '?' => return .{ .value = c },
'n' => return .{ .value = '\n' },
'r' => return .{ .value = '\r' },
't' => return .{ .value = '\t' },
'a' => return .{ .value = 0x07 },
'b' => return .{ .value = 0x08 },
'e', 'E' => {
self.warn(.non_standard_escape_char, .{ .invalid_escape = .{ .char = c, .offset = @intCast(self.i) } });
return .{ .value = 0x1B };
},
'(', '{', '[', '%' => {
self.warn(.non_standard_escape_char, .{ .invalid_escape = .{ .char = c, .offset = @intCast(self.i) } });
return .{ .value = c };
},
'f' => return .{ .value = 0x0C },
'v' => return .{ .value = 0x0B },
'x' => return .{ .value = self.parseNumberEscape(.hex) },
'0'...'7' => return .{ .value = self.parseNumberEscape(.octal) },
'u', 'U' => unreachable, // handled by parseUnicodeEscape
else => {
self.warn(.unknown_escape_sequence, .{ .invalid_escape = .{ .char = c, .offset = @intCast(self.i) } });
return .{ .value = c };
},
}
}
fn parseNumberEscape(self: *Parser, base: EscapeBase) u32 {
var val: u32 = 0;
var count: usize = 0;
var overflowed = false;
defer self.i += count;
const slice = switch (base) {
.octal => self.literal[self.i..@min(self.literal.len, self.i + 3)], // max 3 chars
.hex => blk: {
self.i += 1;
break :blk self.literal[self.i..]; // skip over 'x'; could have an arbitrary number of chars
},
};
for (slice) |c| {
const char = std.fmt.charToDigit(c, @intFromEnum(base)) catch break;
val, const overflow = @shlWithOverflow(val, base.log2());
if (overflow != 0) overflowed = true;
val += char;
count += 1;
}
if (overflowed or val > self.kind.maxInt(self.comp)) {
self.err(.escape_sequence_overflow, .{ .unsigned = 0 });
}
if (count == 0) {
std.debug.assert(base == .hex);
self.err(.missing_hex_escape, .{ .ascii = 'x' });
}
return val;
}
};
const EscapeBase = enum(u8) {
octal = 8,
hex = 16,
fn log2(base: EscapeBase) u4 {
return switch (base) {
.octal => 3,
.hex => 4,
};
}
};

View File

@ -1,108 +0,0 @@
const std = @import("std");
const Compilation = @import("Compilation.zig");
const Tree = @import("Tree.zig");
const NodeIndex = Tree.NodeIndex;
const Object = @import("Object.zig");
const x86_64 = @import("codegen/x86_64.zig");
const Codegen = @This();
comp: *Compilation,
tree: Tree,
obj: *Object,
node_tag: []const Tree.Tag,
node_data: []const Tree.Node.Data,
pub const Error = Compilation.Error || error{CodegenFailed};
/// Generate tree to an object file.
/// Caller is responsible for flushing and freeing the returned object.
pub fn generateTree(comp: *Compilation, tree: Tree) Compilation.Error!*Object {
var c = Codegen{
.comp = comp,
.tree = tree,
.obj = try Object.create(comp),
.node_tag = tree.nodes.items(.tag),
.node_data = tree.nodes.items(.data),
};
errdefer c.obj.deinit();
const node_tags = tree.nodes.items(.tag);
for (tree.root_decls) |decl| {
switch (node_tags[@intFromEnum(decl)]) {
// these produce no code
.static_assert,
.typedef,
.struct_decl_two,
.union_decl_two,
.enum_decl_two,
.struct_decl,
.union_decl,
.enum_decl,
.struct_forward_decl,
.union_forward_decl,
.enum_forward_decl,
=> {},
// define symbol
.fn_proto,
.static_fn_proto,
.inline_fn_proto,
.inline_static_fn_proto,
.extern_var,
.threadlocal_extern_var,
=> {
const name = c.tree.tokSlice(c.node_data[@intFromEnum(decl)].decl.name);
_ = try c.obj.declareSymbol(.undefined, name, .Strong, .external, 0, 0);
},
// function definition
.fn_def,
.static_fn_def,
.inline_fn_def,
.inline_static_fn_def,
=> c.genFn(decl) catch |err| switch (err) {
error.FatalError => return error.FatalError,
error.OutOfMemory => return error.OutOfMemory,
error.CodegenFailed => continue,
},
.@"var",
.static_var,
.threadlocal_var,
.threadlocal_static_var,
.implicit_static_var,
=> c.genVar(decl) catch |err| switch (err) {
error.FatalError => return error.FatalError,
error.OutOfMemory => return error.OutOfMemory,
error.CodegenFailed => continue,
},
// TODO
.file_scope_asm => {},
else => unreachable,
}
}
return c.obj;
}
fn genFn(c: *Codegen, decl: NodeIndex) Error!void {
const section: Object.Section = .func;
const data = try c.obj.getSection(section);
const start_len = data.items.len;
switch (c.comp.target.cpu.arch) {
.x86_64 => try x86_64.genFn(c, decl, data),
else => unreachable,
}
const name = c.tree.tokSlice(c.node_data[@intFromEnum(decl)].decl.name);
_ = try c.obj.declareSymbol(section, name, .Strong, .func, start_len, data.items.len - start_len);
}
fn genVar(c: *Codegen, decl: NodeIndex) Error!void {
switch (c.comp.target.cpu.arch) {
.x86_64 => try x86_64.genVar(c, decl),
else => unreachable,
}
}

2935
deps/aro/Diagnostics.zig vendored

File diff suppressed because it is too large Load Diff

180
deps/aro/Interner.zig vendored
View File

@ -1,180 +0,0 @@
const Interner = @This();
const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const Value = @import("Value.zig");
map: std.ArrayHashMapUnmanaged(Key, void, KeyContext, false) = .{},
const KeyContext = struct {
pub fn eql(_: @This(), a: Key, b: Key, _: usize) bool {
return b.eql(a);
}
pub fn hash(_: @This(), a: Key) u32 {
return a.hash();
}
};
pub const Key = union(enum) {
int: u16,
float: u16,
ptr,
noreturn,
void,
func,
array: struct {
len: u64,
child: Ref,
},
vector: struct {
len: u32,
child: Ref,
},
value: Value,
record: struct {
/// Pointer to user data, value used for hash and equality check.
user_ptr: *anyopaque,
/// TODO make smaller if Value is made smaller
elements: []const Ref,
},
pub fn hash(key: Key) u32 {
var hasher = std.hash.Wyhash.init(0);
switch (key) {
.value => |val| {
std.hash.autoHash(&hasher, val.tag);
switch (val.tag) {
.unavailable => unreachable,
.nullptr_t => std.hash.autoHash(&hasher, @as(u64, 0)),
.int => std.hash.autoHash(&hasher, val.data.int),
.float => std.hash.autoHash(&hasher, @as(u64, @bitCast(val.data.float))),
.bytes => std.hash.autoHashStrat(&hasher, val.data.bytes, .Shallow),
}
},
.record => |info| {
std.hash.autoHash(&hasher, @intFromPtr(info.user_ptr));
},
inline else => |info| {
std.hash.autoHash(&hasher, info);
},
}
return @truncate(hasher.final());
}
pub fn eql(a: Key, b: Key) bool {
const KeyTag = std.meta.Tag(Key);
const a_tag: KeyTag = a;
const b_tag: KeyTag = b;
if (a_tag != b_tag) return false;
switch (a) {
.value => |a_info| {
const b_info = b.value;
if (a_info.tag != b_info.tag) return false;
switch (a_info.tag) {
.unavailable => unreachable,
.nullptr_t => return true,
.int => return a_info.data.int == b_info.data.int,
.float => return a_info.data.float == b_info.data.float,
.bytes => return a_info.data.bytes.start == b_info.data.bytes.start and a_info.data.bytes.end == b_info.data.bytes.end,
}
},
.record => |a_info| {
return a_info.user_ptr == b.record.user_ptr;
},
inline else => |a_info, tag| {
const b_info = @field(b, @tagName(tag));
return std.meta.eql(a_info, b_info);
},
}
}
fn toRef(key: Key) ?Ref {
switch (key) {
.int => |bits| switch (bits) {
1 => return .i1,
8 => return .i8,
16 => return .i16,
32 => return .i32,
64 => return .i64,
128 => return .i128,
else => {},
},
.float => |bits| switch (bits) {
16 => return .f16,
32 => return .f32,
64 => return .f64,
80 => return .f80,
128 => return .f128,
else => unreachable,
},
.ptr => return .ptr,
.func => return .func,
.noreturn => return .noreturn,
.void => return .void,
else => {},
}
return null;
}
};
pub const Ref = enum(u32) {
const max = std.math.maxInt(u32);
ptr = max - 0,
noreturn = max - 1,
void = max - 2,
i1 = max - 3,
i8 = max - 4,
i16 = max - 5,
i32 = max - 6,
i64 = max - 7,
i128 = max - 8,
f16 = max - 9,
f32 = max - 10,
f64 = max - 11,
f80 = max - 12,
f128 = max - 13,
func = max - 14,
_,
};
pub fn deinit(ip: *Interner, gpa: Allocator) void {
ip.map.deinit(gpa);
}
pub fn put(ip: *Interner, gpa: Allocator, key: Key) !Ref {
if (key.toRef()) |some| return some;
const gop = try ip.map.getOrPut(gpa, key);
return @enumFromInt(gop.index);
}
pub fn has(ip: *Interner, key: Key) ?Ref {
if (key.toRef()) |some| return some;
if (ip.map.getIndex(key)) |index| {
return @enumFromInt(index);
}
return null;
}
pub fn get(ip: Interner, ref: Ref) Key {
switch (ref) {
.ptr => return .ptr,
.func => return .func,
.noreturn => return .noreturn,
.void => return .void,
.i1 => return .{ .int = 1 },
.i8 => return .{ .int = 8 },
.i16 => return .{ .int = 16 },
.i32 => return .{ .int = 32 },
.i64 => return .{ .int = 64 },
.i128 => return .{ .int = 128 },
.f16 => return .{ .float = 16 },
.f32 => return .{ .float = 32 },
.f64 => return .{ .float = 64 },
.f80 => return .{ .float = 80 },
.f128 => return .{ .float = 128 },
else => {},
}
return ip.map.keys()[@intFromEnum(ref)];
}

3
deps/aro/README.md vendored
View File

@ -1,4 +1,7 @@
<img src="https://aro.vexu.eu/aro-logo.svg" alt="Aro" width="120px"/>
# Aro
A C compiler with the goal of providing fast compilation and low memory usage with good diagnostics.
Aro is included as an alternative C frontend in the [Zig compiler](https://github.com/ziglang/zig)

633
deps/aro/Value.zig vendored
View File

@ -1,633 +0,0 @@
const std = @import("std");
const assert = std.debug.assert;
const Compilation = @import("Compilation.zig");
const Type = @import("Type.zig");
const Value = @This();
pub const ByteRange = struct {
start: u32,
end: u32,
pub fn len(self: ByteRange) u32 {
return self.end - self.start;
}
pub fn trim(self: ByteRange, amount: u32) ByteRange {
std.debug.assert(self.start <= self.end - amount);
return .{ .start = self.start, .end = self.end - amount };
}
pub fn slice(self: ByteRange, all_bytes: []const u8, comptime size: Compilation.CharUnitSize) []const size.Type() {
switch (size) {
inline else => |sz| {
const aligned: []align(@alignOf(sz.Type())) const u8 = @alignCast(all_bytes[self.start..self.end]);
return std.mem.bytesAsSlice(sz.Type(), aligned);
},
}
}
pub fn dumpString(range: ByteRange, ty: Type, comp: *const Compilation, strings: []const u8, w: anytype) !void {
const size: Compilation.CharUnitSize = @enumFromInt(ty.elemType().sizeof(comp).?);
const without_null = range.trim(@intFromEnum(size));
switch (size) {
inline .@"1", .@"2" => |sz| {
const data_slice = without_null.slice(strings, sz);
const formatter = if (sz == .@"1") std.zig.fmtEscapes(data_slice) else std.unicode.fmtUtf16le(data_slice);
try w.print("\"{}\"", .{formatter});
},
.@"4" => {
try w.writeByte('"');
const data_slice = without_null.slice(strings, .@"4");
var buf: [4]u8 = undefined;
for (data_slice) |item| {
if (item <= std.math.maxInt(u21) and std.unicode.utf8ValidCodepoint(@intCast(item))) {
const codepoint: u21 = @intCast(item);
const written = std.unicode.utf8Encode(codepoint, &buf) catch unreachable;
try w.print("{s}", .{buf[0..written]});
} else {
try w.print("\\x{x}", .{item});
}
}
try w.writeByte('"');
},
}
}
};
tag: Tag = .unavailable,
data: union {
none: void,
int: u64,
float: f64,
bytes: ByteRange,
} = .{ .none = {} },
const Tag = enum {
unavailable,
nullptr_t,
/// int is used to store integer, boolean and pointer values
int,
float,
bytes,
};
pub fn zero(v: Value) Value {
return switch (v.tag) {
.int => int(0),
.float => float(0),
else => unreachable,
};
}
pub fn one(v: Value) Value {
return switch (v.tag) {
.int => int(1),
.float => float(1),
else => unreachable,
};
}
pub fn int(v: anytype) Value {
if (@TypeOf(v) == comptime_int or @typeInfo(@TypeOf(v)).Int.signedness == .unsigned)
return .{ .tag = .int, .data = .{ .int = v } }
else
return .{ .tag = .int, .data = .{ .int = @bitCast(@as(i64, v)) } };
}
pub fn float(v: anytype) Value {
return .{ .tag = .float, .data = .{ .float = v } };
}
pub fn bytes(start: u32, end: u32) Value {
return .{ .tag = .bytes, .data = .{ .bytes = .{ .start = start, .end = end } } };
}
pub fn signExtend(v: Value, old_ty: Type, comp: *Compilation) i64 {
const size = old_ty.sizeof(comp).?;
return switch (size) {
1 => v.getInt(i8),
2 => v.getInt(i16),
4 => v.getInt(i32),
8 => v.getInt(i64),
else => unreachable,
};
}
/// Number of bits needed to hold `v` which is of type `ty`.
/// Asserts that `v` is not negative
pub fn minUnsignedBits(v: Value, ty: Type, comp: *const Compilation) usize {
assert(v.compare(.gte, Value.int(0), ty, comp));
return switch (ty.sizeof(comp).?) {
1 => 8 - @clz(v.getInt(u8)),
2 => 16 - @clz(v.getInt(u16)),
4 => 32 - @clz(v.getInt(u32)),
8 => 64 - @clz(v.getInt(u64)),
else => unreachable,
};
}
test "minUnsignedBits" {
const Test = struct {
fn checkIntBits(comp: *const Compilation, specifier: Type.Specifier, v: u64, expected: usize) !void {
const val = Value.int(v);
try std.testing.expectEqual(expected, val.minUnsignedBits(.{ .specifier = specifier }, comp));
}
};
var comp = Compilation.init(std.testing.allocator);
defer comp.deinit();
comp.target = (try std.zig.CrossTarget.parse(.{ .arch_os_abi = "x86_64-linux-gnu" })).toTarget();
try Test.checkIntBits(&comp, .int, 0, 0);
try Test.checkIntBits(&comp, .int, 1, 1);
try Test.checkIntBits(&comp, .int, 2, 2);
try Test.checkIntBits(&comp, .int, std.math.maxInt(i8), 7);
try Test.checkIntBits(&comp, .int, std.math.maxInt(u8), 8);
try Test.checkIntBits(&comp, .int, std.math.maxInt(i16), 15);
try Test.checkIntBits(&comp, .int, std.math.maxInt(u16), 16);
try Test.checkIntBits(&comp, .int, std.math.maxInt(i32), 31);
try Test.checkIntBits(&comp, .uint, std.math.maxInt(u32), 32);
try Test.checkIntBits(&comp, .long, std.math.maxInt(i64), 63);
try Test.checkIntBits(&comp, .ulong, std.math.maxInt(u64), 64);
try Test.checkIntBits(&comp, .long_long, std.math.maxInt(i64), 63);
try Test.checkIntBits(&comp, .ulong_long, std.math.maxInt(u64), 64);
}
/// Minimum number of bits needed to represent `v` in 2's complement notation
/// Asserts that `v` is negative.
pub fn minSignedBits(v: Value, ty: Type, comp: *const Compilation) usize {
assert(v.compare(.lt, Value.int(0), ty, comp));
return switch (ty.sizeof(comp).?) {
1 => 8 - @clz(~v.getInt(u8)) + 1,
2 => 16 - @clz(~v.getInt(u16)) + 1,
4 => 32 - @clz(~v.getInt(u32)) + 1,
8 => 64 - @clz(~v.getInt(u64)) + 1,
else => unreachable,
};
}
test "minSignedBits" {
const Test = struct {
fn checkIntBits(comp: *const Compilation, specifier: Type.Specifier, v: i64, expected: usize) !void {
const val = Value.int(v);
try std.testing.expectEqual(expected, val.minSignedBits(.{ .specifier = specifier }, comp));
}
};
var comp = Compilation.init(std.testing.allocator);
defer comp.deinit();
comp.target = (try std.zig.CrossTarget.parse(.{ .arch_os_abi = "x86_64-linux-gnu" })).toTarget();
for ([_]Type.Specifier{ .int, .long, .long_long }) |specifier| {
try Test.checkIntBits(&comp, specifier, -1, 1);
try Test.checkIntBits(&comp, specifier, -2, 2);
try Test.checkIntBits(&comp, specifier, -10, 5);
try Test.checkIntBits(&comp, specifier, -101, 8);
try Test.checkIntBits(&comp, specifier, std.math.minInt(i8), 8);
try Test.checkIntBits(&comp, specifier, std.math.minInt(i16), 16);
try Test.checkIntBits(&comp, specifier, std.math.minInt(i32), 32);
}
try Test.checkIntBits(&comp, .long, std.math.minInt(i64), 64);
try Test.checkIntBits(&comp, .long_long, std.math.minInt(i64), 64);
}
pub const FloatToIntChangeKind = enum {
/// value did not change
none,
/// floating point number too small or large for destination integer type
out_of_range,
/// tried to convert a NaN or Infinity
overflow,
/// fractional value was converted to zero
nonzero_to_zero,
/// fractional part truncated
value_changed,
};
fn floatToIntExtra(comptime FloatTy: type, int_ty_signedness: std.builtin.Signedness, int_ty_size: u16, v: *Value) FloatToIntChangeKind {
const float_val = v.getFloat(FloatTy);
const was_zero = float_val == 0;
const had_fraction = std.math.modf(float_val).fpart != 0;
switch (int_ty_signedness) {
inline else => |signedness| switch (int_ty_size) {
inline 1, 2, 4, 8 => |bytecount| {
const IntTy = std.meta.Int(signedness, bytecount * 8);
const intVal = std.math.lossyCast(IntTy, float_val);
v.* = int(intVal);
if (!was_zero and v.isZero()) return .nonzero_to_zero;
if (float_val <= std.math.minInt(IntTy) or float_val >= std.math.maxInt(IntTy)) return .out_of_range;
if (had_fraction) return .value_changed;
return .none;
},
else => unreachable,
},
}
}
/// Converts the stored value from a float to an integer.
/// `.unavailable` value remains unchanged.
pub fn floatToInt(v: *Value, old_ty: Type, new_ty: Type, comp: *Compilation) FloatToIntChangeKind {
assert(old_ty.isFloat());
if (v.tag == .unavailable) return .none;
if (new_ty.is(.bool)) {
const was_zero = v.isZero();
const was_one = v.getFloat(f64) == 1.0;
v.toBool();
if (was_zero or was_one) return .none;
return .value_changed;
} else if (new_ty.isUnsignedInt(comp) and v.data.float < 0) {
v.* = int(0);
return .out_of_range;
} else if (!std.math.isFinite(v.data.float)) {
v.tag = .unavailable;
return .overflow;
}
const old_size = old_ty.sizeof(comp).?;
const new_size: u16 = @intCast(new_ty.sizeof(comp).?);
if (new_ty.isUnsignedInt(comp)) switch (old_size) {
1 => unreachable, // promoted to int
2 => unreachable, // promoted to int
4 => return floatToIntExtra(f32, .unsigned, new_size, v),
8 => return floatToIntExtra(f64, .unsigned, new_size, v),
else => unreachable,
} else switch (old_size) {
1 => unreachable, // promoted to int
2 => unreachable, // promoted to int
4 => return floatToIntExtra(f32, .signed, new_size, v),
8 => return floatToIntExtra(f64, .signed, new_size, v),
else => unreachable,
}
}
/// Converts the stored value from an integer to a float.
/// `.unavailable` value remains unchanged.
pub fn intToFloat(v: *Value, old_ty: Type, new_ty: Type, comp: *Compilation) void {
assert(old_ty.isInt());
if (v.tag == .unavailable) return;
if (!new_ty.isReal() or new_ty.sizeof(comp).? > 8) {
v.tag = .unavailable;
} else if (old_ty.isUnsignedInt(comp)) {
v.* = float(@as(f64, @floatFromInt(v.data.int)));
} else {
v.* = float(@as(f64, @floatFromInt(@as(i64, @bitCast(v.data.int)))));
}
}
/// Truncates or extends bits based on type.
/// old_ty is only used for size.
pub fn intCast(v: *Value, old_ty: Type, new_ty: Type, comp: *Compilation) void {
// assert(old_ty.isInt() and new_ty.isInt());
if (v.tag == .unavailable) return;
if (new_ty.is(.bool)) return v.toBool();
if (!old_ty.isUnsignedInt(comp)) {
const size = new_ty.sizeof(comp).?;
switch (size) {
1 => v.* = int(@as(u8, @truncate(@as(u64, @bitCast(v.signExtend(old_ty, comp)))))),
2 => v.* = int(@as(u16, @truncate(@as(u64, @bitCast(v.signExtend(old_ty, comp)))))),
4 => v.* = int(@as(u32, @truncate(@as(u64, @bitCast(v.signExtend(old_ty, comp)))))),
8 => return,
else => unreachable,
}
}
}
/// Converts the stored value from an integer to a float.
/// `.unavailable` value remains unchanged.
pub fn floatCast(v: *Value, old_ty: Type, new_ty: Type, comp: *Compilation) void {
assert(old_ty.isFloat() and new_ty.isFloat());
if (v.tag == .unavailable) return;
const size = new_ty.sizeof(comp).?;
if (!new_ty.isReal() or size > 8) {
v.tag = .unavailable;
} else if (size == 32) {
v.* = float(@as(f32, @floatCast(v.data.float)));
}
}
/// Truncates data.int to one bit
pub fn toBool(v: *Value) void {
if (v.tag == .unavailable) return;
const res = v.getBool();
v.* = int(@intFromBool(res));
}
pub fn isZero(v: Value) bool {
return switch (v.tag) {
.unavailable => false,
.nullptr_t => false,
.int => v.data.int == 0,
.float => v.data.float == 0,
.bytes => false,
};
}
pub fn getBool(v: Value) bool {
return switch (v.tag) {
.unavailable => unreachable,
.nullptr_t => false,
.int => v.data.int != 0,
.float => v.data.float != 0,
.bytes => true,
};
}
pub fn getInt(v: Value, comptime T: type) T {
if (T == u64) return v.data.int;
return if (@typeInfo(T).Int.signedness == .unsigned)
@truncate(v.data.int)
else
@truncate(@as(i64, @bitCast(v.data.int)));
}
pub fn getFloat(v: Value, comptime T: type) T {
if (T == f64) return v.data.float;
return @floatCast(v.data.float);
}
const bin_overflow = struct {
inline fn addInt(comptime T: type, out: *Value, a: Value, b: Value) bool {
const a_val = a.getInt(T);
const b_val = b.getInt(T);
const sum, const overflowed = @addWithOverflow(a_val, b_val);
out.* = int(sum);
return overflowed != 0;
}
inline fn addFloat(comptime T: type, aa: Value, bb: Value) Value {
const a_val = aa.getFloat(T);
const b_val = bb.getFloat(T);
return float(a_val + b_val);
}
inline fn subInt(comptime T: type, out: *Value, a: Value, b: Value) bool {
const a_val = a.getInt(T);
const b_val = b.getInt(T);
const difference, const overflowed = @subWithOverflow(a_val, b_val);
out.* = int(difference);
return overflowed != 0;
}
inline fn subFloat(comptime T: type, aa: Value, bb: Value) Value {
const a_val = aa.getFloat(T);
const b_val = bb.getFloat(T);
return float(a_val - b_val);
}
inline fn mulInt(comptime T: type, out: *Value, a: Value, b: Value) bool {
const a_val = a.getInt(T);
const b_val = b.getInt(T);
const product, const overflowed = @mulWithOverflow(a_val, b_val);
out.* = int(product);
return overflowed != 0;
}
inline fn mulFloat(comptime T: type, aa: Value, bb: Value) Value {
const a_val = aa.getFloat(T);
const b_val = bb.getFloat(T);
return float(a_val * b_val);
}
const FT = fn (*Value, Value, Value, Type, *Compilation) bool;
fn getOp(comptime intFunc: anytype, comptime floatFunc: anytype) FT {
return struct {
fn op(res: *Value, a: Value, b: Value, ty: Type, comp: *Compilation) bool {
const size = ty.sizeof(comp).?;
if (@TypeOf(floatFunc) != @TypeOf(null) and ty.isFloat()) {
res.* = switch (size) {
4 => floatFunc(f32, a, b),
8 => floatFunc(f64, a, b),
else => unreachable,
};
return false;
}
if (ty.isUnsignedInt(comp)) switch (size) {
1 => return intFunc(u8, res, a, b),
2 => return intFunc(u16, res, a, b),
4 => return intFunc(u32, res, a, b),
8 => return intFunc(u64, res, a, b),
else => unreachable,
} else switch (size) {
1 => return intFunc(u8, res, a, b),
2 => return intFunc(u16, res, a, b),
4 => return intFunc(i32, res, a, b),
8 => return intFunc(i64, res, a, b),
else => unreachable,
}
}
}.op;
}
};
pub const add = bin_overflow.getOp(bin_overflow.addInt, bin_overflow.addFloat);
pub const sub = bin_overflow.getOp(bin_overflow.subInt, bin_overflow.subFloat);
pub const mul = bin_overflow.getOp(bin_overflow.mulInt, bin_overflow.mulFloat);
const bin_ops = struct {
inline fn divInt(comptime T: type, aa: Value, bb: Value) Value {
const a_val = aa.getInt(T);
const b_val = bb.getInt(T);
return int(@divTrunc(a_val, b_val));
}
inline fn divFloat(comptime T: type, aa: Value, bb: Value) Value {
const a_val = aa.getFloat(T);
const b_val = bb.getFloat(T);
return float(a_val / b_val);
}
inline fn remInt(comptime T: type, a: Value, b: Value) Value {
const a_val = a.getInt(T);
const b_val = b.getInt(T);
if (@typeInfo(T).Int.signedness == .signed) {
if (a_val == std.math.minInt(T) and b_val == -1) {
return Value{ .tag = .unavailable, .data = .{ .none = {} } };
} else {
if (b_val > 0) return int(@rem(a_val, b_val));
return int(a_val - @divTrunc(a_val, b_val) * b_val);
}
} else {
return int(a_val % b_val);
}
}
inline fn orInt(comptime T: type, a: Value, b: Value) Value {
const a_val = a.getInt(T);
const b_val = b.getInt(T);
return int(a_val | b_val);
}
inline fn xorInt(comptime T: type, a: Value, b: Value) Value {
const a_val = a.getInt(T);
const b_val = b.getInt(T);
return int(a_val ^ b_val);
}
inline fn andInt(comptime T: type, a: Value, b: Value) Value {
const a_val = a.getInt(T);
const b_val = b.getInt(T);
return int(a_val & b_val);
}
inline fn shl(comptime T: type, a: Value, b: Value) Value {
const ShiftT = std.math.Log2Int(T);
const info = @typeInfo(T).Int;
const UT = std.meta.Int(.unsigned, info.bits);
const b_val = b.getInt(T);
if (b_val > std.math.maxInt(ShiftT)) {
return if (info.signedness == .unsigned)
int(@as(UT, std.math.maxInt(UT)))
else
int(@as(T, std.math.minInt(T)));
}
const amt: ShiftT = @truncate(@as(UT, @bitCast(b_val)));
const a_val = a.getInt(T);
return int(a_val << amt);
}
inline fn shr(comptime T: type, a: Value, b: Value) Value {
const ShiftT = std.math.Log2Int(T);
const UT = std.meta.Int(.unsigned, @typeInfo(T).Int.bits);
const b_val = b.getInt(T);
if (b_val > std.math.maxInt(ShiftT)) return Value.int(0);
const amt: ShiftT = @truncate(@as(UT, @intCast(b_val)));
const a_val = a.getInt(T);
return int(a_val >> amt);
}
const FT = fn (Value, Value, Type, *Compilation) Value;
fn getOp(comptime intFunc: anytype, comptime floatFunc: anytype) FT {
return struct {
fn op(a: Value, b: Value, ty: Type, comp: *Compilation) Value {
const size = ty.sizeof(comp).?;
if (@TypeOf(floatFunc) != @TypeOf(null) and ty.isFloat()) {
switch (size) {
4 => return floatFunc(f32, a, b),
8 => return floatFunc(f64, a, b),
else => unreachable,
}
}
if (ty.isUnsignedInt(comp)) switch (size) {
1 => unreachable, // promoted to int
2 => unreachable, // promoted to int
4 => return intFunc(u32, a, b),
8 => return intFunc(u64, a, b),
else => unreachable,
} else switch (size) {
1 => unreachable, // promoted to int
2 => unreachable, // promoted to int
4 => return intFunc(i32, a, b),
8 => return intFunc(i64, a, b),
else => unreachable,
}
}
}.op;
}
};
/// caller guarantees rhs != 0
pub const div = bin_ops.getOp(bin_ops.divInt, bin_ops.divFloat);
/// caller guarantees rhs != 0
/// caller guarantees lhs != std.math.minInt(T) OR rhs != -1
pub const rem = bin_ops.getOp(bin_ops.remInt, null);
pub const bitOr = bin_ops.getOp(bin_ops.orInt, null);
pub const bitXor = bin_ops.getOp(bin_ops.xorInt, null);
pub const bitAnd = bin_ops.getOp(bin_ops.andInt, null);
pub const shl = bin_ops.getOp(bin_ops.shl, null);
pub const shr = bin_ops.getOp(bin_ops.shr, null);
pub fn bitNot(v: Value, ty: Type, comp: *Compilation) Value {
const size = ty.sizeof(comp).?;
var out: Value = undefined;
if (ty.isUnsignedInt(comp)) switch (size) {
1 => unreachable, // promoted to int
2 => unreachable, // promoted to int
4 => out = int(~v.getInt(u32)),
8 => out = int(~v.getInt(u64)),
else => unreachable,
} else switch (size) {
1 => unreachable, // promoted to int
2 => unreachable, // promoted to int
4 => out = int(~v.getInt(i32)),
8 => out = int(~v.getInt(i64)),
else => unreachable,
}
return out;
}
pub fn compare(a: Value, op: std.math.CompareOperator, b: Value, ty: Type, comp: *const Compilation) bool {
assert(a.tag == b.tag);
if (a.tag == .nullptr_t) {
return switch (op) {
.eq => true,
.neq => false,
else => unreachable,
};
}
const S = struct {
inline fn doICompare(comptime T: type, aa: Value, opp: std.math.CompareOperator, bb: Value) bool {
const a_val = aa.getInt(T);
const b_val = bb.getInt(T);
return std.math.compare(a_val, opp, b_val);
}
inline fn doFCompare(comptime T: type, aa: Value, opp: std.math.CompareOperator, bb: Value) bool {
const a_val = aa.getFloat(T);
const b_val = bb.getFloat(T);
return std.math.compare(a_val, opp, b_val);
}
};
const size = ty.sizeof(comp).?;
switch (a.tag) {
.unavailable => return true,
.int => if (ty.isUnsignedInt(comp)) switch (size) {
1 => return S.doICompare(u8, a, op, b),
2 => return S.doICompare(u16, a, op, b),
4 => return S.doICompare(u32, a, op, b),
8 => return S.doICompare(u64, a, op, b),
else => unreachable,
} else switch (size) {
1 => return S.doICompare(i8, a, op, b),
2 => return S.doICompare(i16, a, op, b),
4 => return S.doICompare(i32, a, op, b),
8 => return S.doICompare(i64, a, op, b),
else => unreachable,
},
.float => switch (size) {
4 => return S.doFCompare(f32, a, op, b),
8 => return S.doFCompare(f64, a, op, b),
else => unreachable,
},
else => @panic("TODO"),
}
return false;
}
pub fn hash(v: Value) u64 {
switch (v.tag) {
.unavailable => unreachable,
.int => return std.hash.Wyhash.hash(0, std.mem.asBytes(&v.data.int)),
else => @panic("TODO"),
}
}
pub fn dump(v: Value, ty: Type, comp: *Compilation, strings: []const u8, w: anytype) !void {
switch (v.tag) {
.unavailable => try w.writeAll("unavailable"),
.int => if (ty.is(.bool) and comp.langopts.standard.atLeast(.c2x)) {
try w.print("{s}", .{if (v.isZero()) "false" else "true"});
} else if (ty.isUnsignedInt(comp)) {
try w.print("{d}", .{v.data.int});
} else {
try w.print("{d}", .{v.signExtend(ty, comp)});
},
.bytes => try v.data.bytes.dumpString(ty, comp, strings, w),
// std.fmt does @as instead of @floatCast
.float => try w.print("{d}", .{@as(f64, @floatCast(v.data.float))}),
else => try w.print("({s})", .{@tagName(v.tag)}),
}
}

38
deps/aro/aro.zig vendored Normal file
View File

@ -0,0 +1,38 @@
pub const CodeGen = @import("aro/CodeGen.zig");
pub const Compilation = @import("aro/Compilation.zig");
pub const Diagnostics = @import("aro/Diagnostics.zig");
pub const Driver = @import("aro/Driver.zig");
pub const Parser = @import("aro/Parser.zig");
pub const Preprocessor = @import("aro/Preprocessor.zig");
pub const Source = @import("aro/Source.zig");
pub const Tokenizer = @import("aro/Tokenizer.zig");
pub const Toolchain = @import("aro/Toolchain.zig");
pub const Tree = @import("aro/Tree.zig");
pub const Type = @import("aro/Type.zig");
pub const TypeMapper = @import("aro/StringInterner.zig").TypeMapper;
pub const target_util = @import("aro/target.zig");
pub const Value = @import("aro/Value.zig");
const backend = @import("backend");
pub const Interner = backend.Interner;
pub const Ir = backend.Ir;
pub const Object = backend.Object;
pub const CallingConvention = backend.CallingConvention;
pub const version_str = backend.version_str;
pub const version = backend.version;
test {
_ = @import("aro/Builtins.zig");
_ = @import("aro/char_info.zig");
_ = @import("aro/Compilation.zig");
_ = @import("aro/Driver/Distro.zig");
_ = @import("aro/Driver/Filesystem.zig");
_ = @import("aro/Driver/GCCVersion.zig");
_ = @import("aro/InitList.zig");
_ = @import("aro/Preprocessor.zig");
_ = @import("aro/target.zig");
_ = @import("aro/Tokenizer.zig");
_ = @import("aro/toolchains/Linux.zig");
_ = @import("aro/Value.zig");
}

View File

@ -1,7 +1,7 @@
const std = @import("std");
const mem = std.mem;
const ZigType = std.builtin.Type;
const CallingConvention = @import("lib.zig").CallingConvention;
const CallingConvention = @import("backend").CallingConvention;
const Compilation = @import("Compilation.zig");
const Diagnostics = @import("Diagnostics.zig");
const Parser = @import("Parser.zig");
@ -18,20 +18,20 @@ syntax: Syntax,
args: Arguments,
pub const Syntax = enum {
c2x,
c23,
declspec,
gnu,
keyword,
};
pub const Kind = enum {
c2x,
c23,
declspec,
gnu,
pub fn toSyntax(kind: Kind) Syntax {
return switch (kind) {
.c2x => .c2x,
.c23 => .c23,
.declspec => .declspec,
.gnu => .gnu,
};
@ -57,30 +57,6 @@ pub const ArgumentType = enum {
.expression => "an expression",
};
}
fn fromType(comptime T: type) ArgumentType {
return switch (T) {
Value.ByteRange => .string,
Identifier => .identifier,
u32 => .int,
Alignment => .alignment,
CallingConvention => .identifier,
else => switch (@typeInfo(T)) {
.Enum => if (T.opts.enum_kind == .string) .string else .identifier,
else => unreachable,
},
};
}
fn fromVal(value: Value) ArgumentType {
return switch (value.tag) {
.int => .int,
.bytes => .string,
.unavailable => .expression,
.float => .float,
.nullptr_t => .nullptr_t,
};
}
};
/// number of required arguments
@ -216,7 +192,7 @@ pub fn wantsAlignment(attr: Tag, idx: usize) bool {
}
}
pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Value, ty: Type, comp: *Compilation) ?Diagnostics.Message {
pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, res: Parser.Result, p: *Parser) !?Diagnostics.Message {
switch (attr) {
inline else => |tag| {
const arg_fields = std.meta.fields(@field(attributes, @tagName(tag)));
@ -226,12 +202,12 @@ pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Va
inline 0...arg_fields.len - 1 => |arg_i| {
if (UnwrapOptional(arg_fields[arg_i].type) != Alignment) unreachable;
if (val.tag != .int) return Diagnostics.Message{ .tag = .alignas_unavailable };
if (val.compare(.lt, Value.int(0), ty, comp)) {
return Diagnostics.Message{ .tag = .negative_alignment, .extra = .{ .signed = val.signExtend(ty, comp) } };
if (!res.val.is(.int, p.comp)) return Diagnostics.Message{ .tag = .alignas_unavailable };
if (res.val.compare(.lt, Value.zero, p.comp)) {
return Diagnostics.Message{ .tag = .negative_alignment, .extra = .{ .str = try res.str(p) } };
}
const requested = std.math.cast(u29, val.data.int) orelse {
return Diagnostics.Message{ .tag = .maximum_alignment, .extra = .{ .unsigned = val.data.int } };
const requested = res.val.toInt(u29, p.comp) orelse {
return Diagnostics.Message{ .tag = .maximum_alignment, .extra = .{ .str = try res.str(p) } };
};
if (!std.mem.isValidAlign(requested)) return Diagnostics.Message{ .tag = .non_pow2_align };
@ -247,59 +223,84 @@ pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Va
fn diagnoseField(
comptime decl: ZigType.Declaration,
comptime field: ZigType.StructField,
comptime wanted: type,
comptime Wanted: type,
arguments: *Arguments,
val: Value,
res: Parser.Result,
node: Tree.Node,
strings: []const u8,
) ?Diagnostics.Message {
switch (val.tag) {
p: *Parser,
) !?Diagnostics.Message {
if (res.val.opt_ref == .none) {
if (Wanted == Identifier and node.tag == .decl_ref_expr) {
@field(@field(arguments, decl.name), field.name) = Identifier{ .tok = node.data.decl_ref };
return null;
}
return invalidArgMsg(Wanted, .expression);
}
const key = p.comp.interner.get(res.val.ref());
switch (key) {
.int => {
if (@typeInfo(wanted) == .Int) {
@field(@field(arguments, decl.name), field.name) = val.getInt(wanted);
if (@typeInfo(Wanted) == .Int) {
@field(@field(arguments, decl.name), field.name) = res.val.toInt(Wanted, p.comp) orelse return .{
.tag = .attribute_int_out_of_range,
.extra = .{ .str = try res.str(p) },
};
return null;
}
},
.bytes => {
const bytes = val.data.bytes.trim(1); // remove null terminator
if (wanted == Value.ByteRange) {
.bytes => |bytes| {
if (Wanted == Value) {
std.debug.assert(node.tag == .string_literal_expr);
if (!node.ty.elemType().is(.char) and !node.ty.elemType().is(.uchar)) {
return Diagnostics.Message{
return .{
.tag = .attribute_requires_string,
.extra = .{ .str = decl.name },
};
}
@field(@field(arguments, decl.name), field.name) = bytes;
@field(@field(arguments, decl.name), field.name) = try p.removeNull(res.val);
return null;
} else if (@typeInfo(wanted) == .Enum and @hasDecl(wanted, "opts") and wanted.opts.enum_kind == .string) {
const str = bytes.slice(strings, .@"1");
if (std.meta.stringToEnum(wanted, str)) |enum_val| {
} else if (@typeInfo(Wanted) == .Enum and @hasDecl(Wanted, "opts") and Wanted.opts.enum_kind == .string) {
const str = bytes[0 .. bytes.len - 1];
if (std.meta.stringToEnum(Wanted, str)) |enum_val| {
@field(@field(arguments, decl.name), field.name) = enum_val;
return null;
} else {
@setEvalBranchQuota(3000);
return Diagnostics.Message{
return .{
.tag = .unknown_attr_enum,
.extra = .{ .attr_enum = .{ .tag = std.meta.stringToEnum(Tag, decl.name).? } },
};
}
}
},
else => {
if (wanted == Identifier and node.tag == .decl_ref_expr) {
@field(@field(arguments, decl.name), field.name) = Identifier{ .tok = node.data.decl_ref };
return null;
}
},
else => {},
}
return Diagnostics.Message{
return invalidArgMsg(Wanted, switch (key) {
.int => .int,
.bytes => .string,
.float => .float,
.null => .nullptr_t,
else => unreachable,
});
}
fn invalidArgMsg(comptime Expected: type, actual: ArgumentType) Diagnostics.Message {
return .{
.tag = .attribute_arg_invalid,
.extra = .{ .attr_arg_type = .{ .expected = ArgumentType.fromType(wanted), .actual = ArgumentType.fromVal(val) } },
.extra = .{ .attr_arg_type = .{ .expected = switch (Expected) {
Value => .string,
Identifier => .identifier,
u32 => .int,
Alignment => .alignment,
CallingConvention => .identifier,
else => switch (@typeInfo(Expected)) {
.Enum => if (Expected.opts.enum_kind == .string) .string else .identifier,
else => unreachable,
},
}, .actual = actual } },
};
}
pub fn diagnose(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Value, node: Tree.Node, strings: []const u8) ?Diagnostics.Message {
pub fn diagnose(attr: Tag, arguments: *Arguments, arg_idx: u32, res: Parser.Result, node: Tree.Node, p: *Parser) !?Diagnostics.Message {
switch (attr) {
inline else => |tag| {
const decl = @typeInfo(attributes).Struct.decls[@intFromEnum(tag)];
@ -311,7 +312,7 @@ pub fn diagnose(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Value, node
const arg_fields = std.meta.fields(@field(attributes, decl.name));
switch (arg_idx) {
inline 0...arg_fields.len - 1 => |arg_i| {
return diagnoseField(decl, arg_fields[arg_i], UnwrapOptional(arg_fields[arg_i].type), arguments, val, node, strings);
return diagnoseField(decl, arg_fields[arg_i], UnwrapOptional(arg_fields[arg_i].type), arguments, res, node, p);
},
else => unreachable,
}
@ -347,7 +348,7 @@ const attributes = struct {
size_index: ?u32 = null,
};
pub const alias = struct {
alias: Value.ByteRange,
alias: Value,
};
pub const aligned = struct {
alignment: ?Alignment = null,
@ -361,7 +362,7 @@ const attributes = struct {
position_2: ?u32 = null,
};
pub const allocate = struct {
segname: Value.ByteRange,
segname: Value,
};
pub const allocator = struct {};
pub const always_inline = struct {};
@ -375,7 +376,7 @@ const attributes = struct {
function: Identifier,
};
pub const code_seg = struct {
segname: Value.ByteRange,
segname: Value,
};
pub const cold = struct {};
pub const common = struct {};
@ -387,7 +388,7 @@ const attributes = struct {
function: Identifier,
};
pub const deprecated = struct {
msg: ?Value.ByteRange = null,
msg: ?Value = null,
__name_tok: TokenIndex,
};
pub const designated_init = struct {};
@ -397,7 +398,7 @@ const attributes = struct {
pub const dllexport = struct {};
pub const dllimport = struct {};
pub const @"error" = struct {
msg: Value.ByteRange,
msg: Value,
__name_tok: TokenIndex,
};
pub const externally_visible = struct {};
@ -423,7 +424,7 @@ const attributes = struct {
pub const gnu_inline = struct {};
pub const hot = struct {};
pub const ifunc = struct {
resolver: Value.ByteRange,
resolver: Value,
};
pub const interrupt = struct {};
pub const interrupt_handler = struct {};
@ -469,8 +470,8 @@ const attributes = struct {
pub const no_reorder = struct {};
pub const no_sanitize = struct {
/// Todo: represent args as union?
alignment: Value.ByteRange,
object_size: ?Value.ByteRange = null,
alignment: Value,
object_size: ?Value = null,
};
pub const no_sanitize_address = struct {};
pub const no_sanitize_coverage = struct {};
@ -521,7 +522,7 @@ const attributes = struct {
},
};
pub const section = struct {
name: Value.ByteRange,
name: Value,
};
pub const selectany = struct {};
pub const sentinel = struct {
@ -548,15 +549,15 @@ const attributes = struct {
};
pub const stack_protect = struct {};
pub const symver = struct {
version: Value.ByteRange, // TODO: validate format "name2@nodename"
version: Value, // TODO: validate format "name2@nodename"
};
pub const target = struct {
options: Value.ByteRange, // TODO: multiple arguments
options: Value, // TODO: multiple arguments
};
pub const target_clones = struct {
options: Value.ByteRange, // TODO: multiple arguments
options: Value, // TODO: multiple arguments
};
pub const thread = struct {};
@ -574,7 +575,7 @@ const attributes = struct {
};
pub const transparent_union = struct {};
pub const unavailable = struct {
msg: ?Value.ByteRange = null,
msg: ?Value = null,
__name_tok: TokenIndex,
};
pub const uninitialized = struct {};
@ -582,7 +583,7 @@ const attributes = struct {
pub const unused = struct {};
pub const used = struct {};
pub const uuid = struct {
uuid: Value.ByteRange,
uuid: Value,
};
pub const vector_size = struct {
bytes: u32, // TODO: validate "The bytes argument must be a positive power-of-two multiple of the base type size"
@ -605,12 +606,12 @@ const attributes = struct {
};
pub const warn_unused_result = struct {};
pub const warning = struct {
msg: Value.ByteRange,
msg: Value,
__name_tok: TokenIndex,
};
pub const weak = struct {};
pub const weakref = struct {
target: ?Value.ByteRange = null,
target: ?Value = null,
};
pub const zero_call_used_regs = struct {
choice: enum {
@ -630,7 +631,7 @@ const attributes = struct {
},
};
pub const asm_label = struct {
name: Value.ByteRange,
name: Value,
};
pub const calling_convention = struct {
cc: CallingConvention,
@ -684,7 +685,7 @@ pub fn fromString(kind: Kind, namespace: ?[]const u8, name: []const u8) ?Tag {
tag: Tag,
gnu: bool = false,
declspec: bool = false,
c2x: bool = false,
c23: bool = false,
};
const attribute_names = @import("Attribute/names.def").with(Properties);
@ -707,7 +708,7 @@ pub fn fromString(kind: Kind, namespace: ?[]const u8, name: []const u8) ?Tag {
return null;
}
fn normalize(name: []const u8) []const u8 {
pub fn normalize(name: []const u8) []const u8 {
if (name.len >= 4 and mem.startsWith(u8, name, "__") and mem.endsWith(u8, name, "__")) {
return name[2 .. name.len - 2];
}
@ -719,7 +720,7 @@ fn ignoredAttrErr(p: *Parser, tok: TokenIndex, attr: Attribute.Tag, context: []c
defer p.strings.items.len = strings_top;
try p.strings.writer().print("attribute '{s}' ignored on {s}", .{ @tagName(attr), context });
const str = try p.comp.diag.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
try p.errStr(.ignored_attribute, tok, str);
}
@ -1029,7 +1030,11 @@ fn applyTransparentUnion(attr: Attribute, p: *Parser, tok: TokenIndex, ty: Type)
const field_size = field.ty.bitSizeof(p.comp).?;
if (field_size == first_field_size) continue;
const mapper = p.comp.string_interner.getSlowTypeMapper();
const str = try std.fmt.allocPrint(p.comp.diag.arena.allocator(), "'{s}' ({d}", .{ mapper.lookup(field.name), field_size });
const str = try std.fmt.allocPrint(
p.comp.diagnostics.arena.allocator(),
"'{s}' ({d}",
.{ mapper.lookup(field.name), field_size },
);
try p.errStr(.transparent_union_size, field.name_tok, str);
return p.errExtra(.transparent_union_size_note, fields[0].name_tok, .{ .unsigned = first_field_size });
}

View File

@ -1,18 +1,18 @@
# multiple
deprecated
.tag = .deprecated
.c2x = true
.c23 = true
.gnu = true
.declspec = true
fallthrough
.tag = .fallthrough
.c2x = true
.c23 = true
.gnu = true
noreturn
.tag = .@"noreturn"
.c2x = true
.c23 = true
.gnu = true
.declspec = true
@ -26,22 +26,22 @@ noinline
.gnu = true
.declspec = true
# c2x only
# c23 only
nodiscard
.tag = .nodiscard
.c2x = true
.c23 = true
reproducible
.tag = .reproducible
.c2x = true
.c23 = true
unsequenced
.tag = .unsequenced
.c2x = true
.c23 = true
maybe_unused
.tag = .unused
.c2x = true
.c23 = true
# gnu only
access

View File

@ -10,8 +10,6 @@ const Parser = @import("Parser.zig");
const Properties = @import("Builtins/Properties.zig");
pub const Builtin = @import("Builtins/Builtin.def").with(Properties);
const Builtins = @This();
const Expanded = struct {
ty: Type,
builtin: Builtin,
@ -19,6 +17,8 @@ const Expanded = struct {
const NameToTypeMap = std.StringHashMapUnmanaged(Type);
const Builtins = @This();
_name_to_type_map: NameToTypeMap = .{},
pub fn deinit(b: *Builtins, gpa: std.mem.Allocator) void {
@ -355,7 +355,7 @@ test Iterator {
test "All builtins" {
var comp = Compilation.init(std.testing.allocator);
defer comp.deinit();
_ = try comp.generateBuiltinMacros();
_ = try comp.generateBuiltinMacros(.include_system_defines);
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena.deinit();
@ -378,7 +378,7 @@ test "Allocation failures" {
fn testOne(allocator: std.mem.Allocator) !void {
var comp = Compilation.init(allocator);
defer comp.deinit();
_ = try comp.generateBuiltinMacros();
_ = try comp.generateBuiltinMacros(.include_system_defines);
var arena = std.heap.ArenaAllocator.init(comp.gpa);
defer arena.deinit();

View File

@ -1,20 +1,20 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const backend = @import("backend");
const Interner = backend.Interner;
const Ir = backend.Ir;
const Builtins = @import("Builtins.zig");
const Builtin = Builtins.Builtin;
const Compilation = @import("Compilation.zig");
const Interner = @import("Interner.zig");
const Ir = @import("Ir.zig");
const Builder = Ir.Builder;
const StringId = @import("StringInterner.zig").StringId;
const StrInt = @import("StringInterner.zig");
const StringId = StrInt.StringId;
const Tree = @import("Tree.zig");
const NodeIndex = Tree.NodeIndex;
const Type = @import("Type.zig");
const Value = @import("Value.zig");
const CodeGen = @This();
const WipSwitch = struct {
cases: Cases = .{},
default: ?Ir.Ref = null,
@ -33,6 +33,8 @@ const Symbol = struct {
const Error = Compilation.Error;
const CodeGen = @This();
tree: Tree,
comp: *Compilation,
builder: Builder,
@ -44,6 +46,7 @@ symbols: std.ArrayListUnmanaged(Symbol) = .{},
ret_nodes: std.ArrayListUnmanaged(Ir.Inst.Phi.Input) = .{},
phi_nodes: std.ArrayListUnmanaged(Ir.Inst.Phi.Input) = .{},
record_elem_buf: std.ArrayListUnmanaged(Interner.Ref) = .{},
record_cache: std.AutoHashMapUnmanaged(*Type.Record, Interner.Ref) = .{},
cond_dummy_ty: ?Interner.Ref = null,
bool_invert: bool = false,
bool_end_label: Ir.Ref = .none,
@ -52,28 +55,40 @@ continue_label: Ir.Ref = undefined,
break_label: Ir.Ref = undefined,
return_label: Ir.Ref = undefined,
pub fn generateTree(comp: *Compilation, tree: Tree) Compilation.Error!void {
fn fail(c: *CodeGen, comptime fmt: []const u8, args: anytype) error{ FatalError, OutOfMemory } {
try c.comp.diagnostics.list.append(c.comp.gpa, .{
.tag = .cli_error,
.kind = .@"fatal error",
.extra = .{ .str = try std.fmt.allocPrint(c.comp.diagnostics.arena.allocator(), fmt, args) },
});
return error.FatalError;
}
pub fn genIr(tree: Tree) Compilation.Error!Ir {
const gpa = tree.comp.gpa;
var c = CodeGen{
.builder = .{
.gpa = comp.gpa,
.arena = std.heap.ArenaAllocator.init(comp.gpa),
.gpa = tree.comp.gpa,
.interner = &tree.comp.interner,
.arena = std.heap.ArenaAllocator.init(gpa),
},
.tree = tree,
.comp = comp,
.comp = tree.comp,
.node_tag = tree.nodes.items(.tag),
.node_data = tree.nodes.items(.data),
.node_ty = tree.nodes.items(.ty),
};
defer c.symbols.deinit(c.comp.gpa);
defer c.ret_nodes.deinit(c.comp.gpa);
defer c.phi_nodes.deinit(c.comp.gpa);
defer c.record_elem_buf.deinit(c.comp.gpa);
defer c.symbols.deinit(gpa);
defer c.ret_nodes.deinit(gpa);
defer c.phi_nodes.deinit(gpa);
defer c.record_elem_buf.deinit(gpa);
defer c.record_cache.deinit(gpa);
defer c.builder.deinit();
const node_tags = tree.nodes.items(.tag);
for (tree.root_decls) |decl| {
c.builder.arena.deinit();
c.builder.arena = std.heap.ArenaAllocator.init(comp.gpa);
c.builder.arena = std.heap.ArenaAllocator.init(gpa);
switch (node_tags[@intFromEnum(decl)]) {
.static_assert,
@ -114,6 +129,7 @@ pub fn generateTree(comp: *Compilation, tree: Tree) Compilation.Error!void {
else => unreachable,
}
}
return c.builder.finish();
}
fn genType(c: *CodeGen, base_ty: Type) !Interner.Ref {
@ -123,52 +139,48 @@ fn genType(c: *CodeGen, base_ty: Type) !Interner.Ref {
.void => return .void,
.bool => return .i1,
.@"struct" => {
key = .{
.record = .{
.user_ptr = ty.data.record,
.elements = undefined, // Not needed for hash lookup.
},
};
if (c.builder.pool.has(key)) |some| return some;
if (c.record_cache.get(ty.data.record)) |some| return some;
const elem_buf_top = c.record_elem_buf.items.len;
defer c.record_elem_buf.items.len = elem_buf_top;
for (ty.data.record.fields) |field| {
if (!field.isRegularField()) {
return c.comp.diag.fatalNoSrc("TODO lower struct bitfields", .{});
return c.fail("TODO lower struct bitfields", .{});
}
// TODO handle padding bits
const field_ref = try c.genType(field.ty);
try c.record_elem_buf.append(c.builder.gpa, field_ref);
}
key.record.elements = try c.builder.arena.allocator().dupe(Interner.Ref, c.record_elem_buf.items[elem_buf_top..]);
return c.builder.pool.put(c.builder.gpa, key);
return c.builder.interner.put(c.builder.gpa, .{
.record_ty = c.record_elem_buf.items[elem_buf_top..],
});
},
.@"union" => {
return c.comp.diag.fatalNoSrc("TODO lower union types", .{});
return c.fail("TODO lower union types", .{});
},
else => {},
}
if (ty.isPtr()) return .ptr;
if (ty.isFunc()) return .func;
if (!ty.isReal()) return c.comp.diag.fatalNoSrc("TODO lower complex types", .{});
if (!ty.isReal()) return c.fail("TODO lower complex types", .{});
if (ty.isInt()) {
const bits = ty.bitSizeof(c.comp).?;
key = .{ .int = @intCast(bits) };
key = .{ .int_ty = @intCast(bits) };
} else if (ty.isFloat()) {
const bits = ty.bitSizeof(c.comp).?;
key = .{ .float = @intCast(bits) };
key = .{ .float_ty = @intCast(bits) };
} else if (ty.isArray()) {
const elem = try c.genType(ty.elemType());
key = .{ .array = .{ .child = elem, .len = ty.arrayLen().? } };
key = .{ .array_ty = .{ .child = elem, .len = ty.arrayLen().? } };
} else if (ty.specifier == .vector) {
const elem = try c.genType(ty.elemType());
key = .{ .vector = .{ .child = elem, .len = @intCast(ty.data.array.len) } };
key = .{ .vector_ty = .{ .child = elem, .len = @intCast(ty.data.array.len) } };
} else if (ty.is(.nullptr_t)) {
return c.comp.diag.fatalNoSrc("TODO lower nullptr_t", .{});
return c.fail("TODO lower nullptr_t", .{});
}
return c.builder.pool.put(c.builder.gpa, key);
return c.builder.interner.put(c.builder.gpa, key);
}
fn genFn(c: *CodeGen, decl: NodeIndex) Error!void {
@ -205,14 +217,7 @@ fn genFn(c: *CodeGen, decl: NodeIndex) Error!void {
_ = try c.builder.addInst(.ret, .{ .un = phi }, .noreturn);
}
var res = Ir{
.pool = c.builder.pool,
.instructions = c.builder.instructions,
.arena = c.builder.arena.state,
.body = c.builder.body,
.strings = c.tree.strings,
};
res.dump(c.builder.gpa, name, c.comp.diag.color, std.io.getStdOut().writer()) catch {};
try c.builder.finishFn(name);
}
fn addUn(c: *CodeGen, tag: Ir.Inst.Tag, operand: Ir.Ref, ty: Type) !Ir.Ref {
@ -238,7 +243,7 @@ fn addBranch(c: *CodeGen, cond: Ir.Ref, true_label: Ir.Ref, false_label: Ir.Ref)
}
fn addBoolPhi(c: *CodeGen, value: bool) !void {
const val = try c.builder.addConstant(Value.int(@intFromBool(value)), .i1);
const val = try c.builder.addConstant((try Value.int(@intFromBool(value), c.comp)).ref(), .i1);
try c.phi_nodes.append(c.comp.gpa, .{ .label = c.builder.current_label, .value = val });
}
@ -250,7 +255,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
std.debug.assert(node != .none);
const ty = c.node_ty[@intFromEnum(node)];
if (c.tree.value_map.get(node)) |val| {
return c.builder.addConstant(val, try c.genType(ty));
return c.builder.addConstant(val.ref(), try c.genType(ty));
}
const data = c.node_data[@intFromEnum(node)];
switch (c.node_tag[@intFromEnum(node)]) {
@ -259,7 +264,6 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
.int_literal,
.char_literal,
.float_literal,
.double_literal,
.imaginary_literal,
.string_literal_expr,
.alignof_expr,
@ -301,7 +305,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
const size: u32 = @intCast(ty.sizeof(c.comp).?); // TODO add error in parser
const @"align" = ty.alignof(c.comp);
const alloc = try c.builder.addAlloc(size, @"align");
const name = try c.comp.intern(c.tree.tokSlice(data.decl.name));
const name = try StrInt.intern(c.comp, c.tree.tokSlice(data.decl.name));
try c.symbols.append(c.comp.gpa, .{ .name = name, .val = alloc });
if (data.decl.node != .none) {
try c.genInitializer(alloc, ty, data.decl.node);
@ -391,7 +395,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
const label = try c.builder.makeLabel("case");
try c.builder.startBlock(label);
try c.wip_switch.cases.append(c.builder.gpa, .{
.val = try c.builder.pool.put(c.builder.gpa, .{ .value = val }),
.val = val.ref(),
.label = label,
});
try c.genStmt(data.bin.rhs);
@ -453,7 +457,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
const old_continue_label = c.continue_label;
defer c.continue_label = old_continue_label;
const for_decl = data.forDecl(c.tree);
const for_decl = data.forDecl(&c.tree);
for (for_decl.decls) |decl| try c.genStmt(decl);
const then_label = try c.builder.makeLabel("for.then");
@ -501,7 +505,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
const old_continue_label = c.continue_label;
defer c.continue_label = old_continue_label;
const for_stmt = data.forStmt(c.tree);
const for_stmt = data.forStmt(&c.tree);
if (for_stmt.init != .none) _ = try c.genExpr(for_stmt.init);
const then_label = try c.builder.makeLabel("for.then");
@ -536,7 +540,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
},
.implicit_return => {
if (data.return_zero) {
const operand = try c.builder.addConstant(Value.int(0), try c.genType(ty));
const operand = try c.builder.addConstant(.zero, try c.genType(ty));
try c.ret_nodes.append(c.comp.gpa, .{ .value = operand, .label = c.builder.current_label });
}
// No need to emit a jump since implicit_return is always the last instruction.
@ -545,7 +549,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
.goto_stmt,
.computed_goto_stmt,
.nullptr_literal,
=> return c.comp.diag.fatalNoSrc("TODO CodeGen.genStmt {}\n", .{c.node_tag[@intFromEnum(node)]}),
=> return c.fail("TODO CodeGen.genStmt {}\n", .{c.node_tag[@intFromEnum(node)]}),
.comma_expr => {
_ = try c.genExpr(data.bin.lhs);
return c.genExpr(data.bin.rhs);
@ -635,7 +639,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
},
.plus_expr => return c.genExpr(data.un),
.negate_expr => {
const zero = try c.builder.addConstant(Value.int(0), try c.genType(ty));
const zero = try c.builder.addConstant(.zero, try c.genType(ty));
const operand = try c.genExpr(data.un);
return c.addBin(.sub, zero, operand, ty);
},
@ -644,14 +648,14 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
return c.addUn(.bit_not, operand, ty);
},
.bool_not_expr => {
const zero = try c.builder.addConstant(Value.int(0), try c.genType(ty));
const zero = try c.builder.addConstant(.zero, try c.genType(ty));
const operand = try c.genExpr(data.un);
return c.addBin(.cmp_ne, zero, operand, ty);
},
.pre_inc_expr => {
const operand = try c.genLval(data.un);
const val = try c.addUn(.load, operand, ty);
const one = try c.builder.addConstant(Value.int(1), try c.genType(ty));
const one = try c.builder.addConstant(.one, try c.genType(ty));
const plus_one = try c.addBin(.add, val, one, ty);
try c.builder.addStore(operand, plus_one);
return plus_one;
@ -659,7 +663,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
.pre_dec_expr => {
const operand = try c.genLval(data.un);
const val = try c.addUn(.load, operand, ty);
const one = try c.builder.addConstant(Value.int(1), try c.genType(ty));
const one = try c.builder.addConstant(.one, try c.genType(ty));
const plus_one = try c.addBin(.sub, val, one, ty);
try c.builder.addStore(operand, plus_one);
return plus_one;
@ -667,7 +671,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
.post_inc_expr => {
const operand = try c.genLval(data.un);
const val = try c.addUn(.load, operand, ty);
const one = try c.builder.addConstant(Value.int(1), try c.genType(ty));
const one = try c.builder.addConstant(.one, try c.genType(ty));
const plus_one = try c.addBin(.add, val, one, ty);
try c.builder.addStore(operand, plus_one);
return val;
@ -675,7 +679,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
.post_dec_expr => {
const operand = try c.genLval(data.un);
const val = try c.addUn(.load, operand, ty);
const one = try c.builder.addConstant(Value.int(1), try c.genType(ty));
const one = try c.builder.addConstant(.one, try c.genType(ty));
const plus_one = try c.addBin(.sub, val, one, ty);
try c.builder.addStore(operand, plus_one);
return val;
@ -717,7 +721,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
},
.pointer_to_bool, .int_to_bool, .float_to_bool => {
const lhs = try c.genExpr(data.cast.operand);
const rhs = try c.builder.addConstant(Value.int(0), try c.genType(c.node_ty[@intFromEnum(node)]));
const rhs = try c.builder.addConstant(.zero, try c.genType(c.node_ty[@intFromEnum(node)]));
return c.builder.addInst(.cmp_ne, .{ .bin = .{ .lhs = lhs, .rhs = rhs } }, .i1);
},
.bitcast,
@ -739,11 +743,11 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
.null_to_pointer,
.union_cast,
.vector_splat,
=> return c.comp.diag.fatalNoSrc("TODO CodeGen gen CastKind {}\n", .{data.cast.kind}),
=> return c.fail("TODO CodeGen gen CastKind {}\n", .{data.cast.kind}),
},
.binary_cond_expr => {
if (c.tree.value_map.get(data.if3.cond)) |cond| {
if (cond.getBool()) {
if (cond.toBool(c.comp)) {
c.cond_dummy_ref = try c.genExpr(data.if3.cond);
return c.genExpr(c.tree.data[data.if3.body]); // then
} else {
@ -786,7 +790,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
.cond_dummy_expr => return c.cond_dummy_ref,
.cond_expr => {
if (c.tree.value_map.get(data.if3.cond)) |cond| {
if (cond.getBool()) {
if (cond.toBool(c.comp)) {
return c.genExpr(c.tree.data[data.if3.body]); // then
} else {
return c.genExpr(c.tree.data[data.if3.body + 1]); // else
@ -826,9 +830,8 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
},
.bool_or_expr => {
if (c.tree.value_map.get(data.bin.lhs)) |lhs| {
const cond = lhs.getBool();
if (!cond) {
return c.builder.addConstant(Value.int(1), try c.genType(ty));
if (!lhs.toBool(c.comp)) {
return c.builder.addConstant(.one, try c.genType(ty));
}
return c.genExpr(data.bin.rhs);
}
@ -855,9 +858,8 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
},
.bool_and_expr => {
if (c.tree.value_map.get(data.bin.lhs)) |lhs| {
const cond = lhs.getBool();
if (!cond) {
return c.builder.addConstant(Value.int(0), try c.genType(ty));
if (!lhs.toBool(c.comp)) {
return c.builder.addConstant(.zero, try c.genType(ty));
}
return c.genExpr(data.bin.rhs);
}
@ -884,7 +886,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
},
.builtin_choose_expr => {
const cond = c.tree.value_map.get(data.if3.cond).?;
if (cond.getBool()) {
if (cond.toBool(c.comp)) {
return c.genExpr(c.tree.data[data.if3.body]);
} else {
return c.genExpr(c.tree.data[data.if3.body + 1]);
@ -949,7 +951,7 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
.real_expr,
.sizeof_expr,
.special_builtin_call_one,
=> return c.comp.diag.fatalNoSrc("TODO CodeGen.genExpr {}\n", .{c.node_tag[@intFromEnum(node)]}),
=> return c.fail("TODO CodeGen.genExpr {}\n", .{c.node_tag[@intFromEnum(node)]}),
else => unreachable, // Not an expression.
}
return .none;
@ -957,17 +959,17 @@ fn genExpr(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
fn genLval(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
std.debug.assert(node != .none);
assert(Tree.isLval(c.tree.nodes, c.tree.data, c.tree.value_map, node));
assert(c.tree.isLval(node));
const data = c.node_data[@intFromEnum(node)];
switch (c.node_tag[@intFromEnum(node)]) {
.string_literal_expr => {
const val = c.tree.value_map.get(node).?;
return c.builder.addConstant(val, .ptr);
return c.builder.addConstant(val.ref(), .ptr);
},
.paren_expr => return c.genLval(data.un),
.decl_ref_expr => {
const slice = c.tree.tokSlice(data.decl_ref);
const name = try c.comp.intern(slice);
const name = try StrInt.intern(c.comp, slice);
var i = c.symbols.items.len;
while (i > 0) {
i -= 1;
@ -992,7 +994,7 @@ fn genLval(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
},
.builtin_choose_expr => {
const cond = c.tree.value_map.get(data.if3.cond).?;
if (cond.getBool()) {
if (cond.toBool(c.comp)) {
return c.genLval(c.tree.data[data.if3.body]);
} else {
return c.genLval(c.tree.data[data.if3.body + 1]);
@ -1001,7 +1003,10 @@ fn genLval(c: *CodeGen, node: NodeIndex) Error!Ir.Ref {
.member_access_expr,
.member_access_ptr_expr,
.array_access_expr,
=> return c.comp.diag.fatalNoSrc("TODO CodeGen.genLval {}\n", .{c.node_tag[@intFromEnum(node)]}),
.static_compound_literal_expr,
.thread_local_compound_literal_expr,
.static_thread_local_compound_literal_expr,
=> return c.fail("TODO CodeGen.genLval {}\n", .{c.node_tag[@intFromEnum(node)]}),
else => unreachable, // Not an lval expression.
}
}
@ -1019,8 +1024,7 @@ fn genBoolExpr(c: *CodeGen, base: NodeIndex, true_label: Ir.Ref, false_label: Ir
switch (c.node_tag[@intFromEnum(node)]) {
.bool_or_expr => {
if (c.tree.value_map.get(data.bin.lhs)) |lhs| {
const cond = lhs.getBool();
if (cond) {
if (lhs.toBool(c.comp)) {
if (true_label == c.bool_end_label) {
return c.addBoolPhi(!c.bool_invert);
}
@ -1033,13 +1037,12 @@ fn genBoolExpr(c: *CodeGen, base: NodeIndex, true_label: Ir.Ref, false_label: Ir
try c.genBoolExpr(data.bin.lhs, true_label, new_false_label);
try c.builder.startBlock(new_false_label);
if (c.cond_dummy_ty) |ty| c.cond_dummy_ref = try c.builder.addConstant(Value.int(1), ty);
if (c.cond_dummy_ty) |ty| c.cond_dummy_ref = try c.builder.addConstant(.one, ty);
return c.genBoolExpr(data.bin.rhs, true_label, false_label);
},
.bool_and_expr => {
if (c.tree.value_map.get(data.bin.lhs)) |lhs| {
const cond = lhs.getBool();
if (!cond) {
if (!lhs.toBool(c.comp)) {
if (false_label == c.bool_end_label) {
return c.addBoolPhi(c.bool_invert);
}
@ -1052,14 +1055,14 @@ fn genBoolExpr(c: *CodeGen, base: NodeIndex, true_label: Ir.Ref, false_label: Ir
try c.genBoolExpr(data.bin.lhs, new_true_label, false_label);
try c.builder.startBlock(new_true_label);
if (c.cond_dummy_ty) |ty| c.cond_dummy_ref = try c.builder.addConstant(Value.int(1), ty);
if (c.cond_dummy_ty) |ty| c.cond_dummy_ref = try c.builder.addConstant(.one, ty);
return c.genBoolExpr(data.bin.rhs, true_label, false_label);
},
.bool_not_expr => {
c.bool_invert = !c.bool_invert;
defer c.bool_invert = !c.bool_invert;
if (c.cond_dummy_ty) |ty| c.cond_dummy_ref = try c.builder.addConstant(Value.int(0), ty);
if (c.cond_dummy_ty) |ty| c.cond_dummy_ref = try c.builder.addConstant(.zero, ty);
return c.genBoolExpr(data.un, false_label, true_label);
},
.equal_expr => {
@ -1102,7 +1105,7 @@ fn genBoolExpr(c: *CodeGen, base: NodeIndex, true_label: Ir.Ref, false_label: Ir
},
.binary_cond_expr => {
if (c.tree.value_map.get(data.if3.cond)) |cond| {
if (cond.getBool()) {
if (cond.toBool(c.comp)) {
return c.genBoolExpr(c.tree.data[data.if3.body], true_label, false_label); // then
} else {
return c.genBoolExpr(c.tree.data[data.if3.body + 1], true_label, false_label); // else
@ -1113,12 +1116,12 @@ fn genBoolExpr(c: *CodeGen, base: NodeIndex, true_label: Ir.Ref, false_label: Ir
try c.genBoolExpr(data.if3.cond, true_label, new_false_label);
try c.builder.startBlock(new_false_label);
if (c.cond_dummy_ty) |ty| c.cond_dummy_ref = try c.builder.addConstant(Value.int(1), ty);
if (c.cond_dummy_ty) |ty| c.cond_dummy_ref = try c.builder.addConstant(.one, ty);
return c.genBoolExpr(c.tree.data[data.if3.body + 1], true_label, false_label); // else
},
.cond_expr => {
if (c.tree.value_map.get(data.if3.cond)) |cond| {
if (cond.getBool()) {
if (cond.toBool(c.comp)) {
return c.genBoolExpr(c.tree.data[data.if3.body], true_label, false_label); // then
} else {
return c.genBoolExpr(c.tree.data[data.if3.body + 1], true_label, false_label); // else
@ -1132,14 +1135,14 @@ fn genBoolExpr(c: *CodeGen, base: NodeIndex, true_label: Ir.Ref, false_label: Ir
try c.builder.startBlock(new_true_label);
try c.genBoolExpr(c.tree.data[data.if3.body], true_label, false_label); // then
try c.builder.startBlock(new_false_label);
if (c.cond_dummy_ty) |ty| c.cond_dummy_ref = try c.builder.addConstant(Value.int(1), ty);
if (c.cond_dummy_ty) |ty| c.cond_dummy_ref = try c.builder.addConstant(.one, ty);
return c.genBoolExpr(c.tree.data[data.if3.body + 1], true_label, false_label); // else
},
else => {},
}
if (c.tree.value_map.get(node)) |value| {
if (value.getBool()) {
if (value.toBool(c.comp)) {
if (true_label == c.bool_end_label) {
return c.addBoolPhi(!c.bool_invert);
}
@ -1154,7 +1157,7 @@ fn genBoolExpr(c: *CodeGen, base: NodeIndex, true_label: Ir.Ref, false_label: Ir
// Assume int operand.
const lhs = try c.genExpr(node);
const rhs = try c.builder.addConstant(Value.int(0), try c.genType(c.node_ty[@intFromEnum(node)]));
const rhs = try c.builder.addConstant(.zero, try c.genType(c.node_ty[@intFromEnum(node)]));
const cmp = try c.builder.addInst(.cmp_ne, .{ .bin = .{ .lhs = lhs, .rhs = rhs } }, .i1);
if (c.cond_dummy_ty != null) c.cond_dummy_ref = cmp;
try c.addBranch(cmp, true_label, false_label);
@ -1163,7 +1166,7 @@ fn genBoolExpr(c: *CodeGen, base: NodeIndex, true_label: Ir.Ref, false_label: Ir
fn genBuiltinCall(c: *CodeGen, builtin: Builtin, arg_nodes: []const NodeIndex, ty: Type) Error!Ir.Ref {
_ = arg_nodes;
_ = ty;
return c.comp.diag.fatalNoSrc("TODO CodeGen.genBuiltinCall {s}\n", .{Builtin.nameFromTag(builtin.tag).span()});
return c.fail("TODO CodeGen.genBuiltinCall {s}\n", .{Builtin.nameFromTag(builtin.tag).span()});
}
fn genCall(c: *CodeGen, fn_node: NodeIndex, arg_nodes: []const NodeIndex, ty: Type) Error!Ir.Ref {
@ -1188,7 +1191,7 @@ fn genCall(c: *CodeGen, fn_node: NodeIndex, arg_nodes: []const NodeIndex, ty: Ty
},
.decl_ref_expr => {
const slice = c.tree.tokSlice(c.node_data[cur].decl_ref);
const name = try c.comp.intern(slice);
const name = try StrInt.intern(c.comp, slice);
var i = c.symbols.items.len;
while (i > 0) {
i -= 1;
@ -1254,7 +1257,7 @@ fn genPtrArithmetic(c: *CodeGen, ptr: Ir.Ref, offset: Ir.Ref, offset_ty: Type, t
return c.builder.addInst(.add, .{ .bin = .{ .lhs = ptr, .rhs = offset } }, try c.genType(ty));
}
const size_inst = try c.builder.addConstant(Value.int(size), try c.genType(offset_ty));
const size_inst = try c.builder.addConstant((try Value.int(size, c.comp)).ref(), try c.genType(offset_ty));
const offset_inst = try c.addBin(.mul, offset, size_inst, offset_ty);
return c.addBin(.add, ptr, offset_inst, offset_ty);
}
@ -1269,12 +1272,12 @@ fn genInitializer(c: *CodeGen, ptr: Ir.Ref, dest_ty: Type, initializer: NodeInde
.union_init_expr,
.array_filler_expr,
.default_init_expr,
=> return c.comp.diag.fatalNoSrc("TODO CodeGen.genInitializer {}\n", .{c.node_tag[@intFromEnum(initializer)]}),
=> return c.fail("TODO CodeGen.genInitializer {}\n", .{c.node_tag[@intFromEnum(initializer)]}),
.string_literal_expr => {
const val = c.tree.value_map.get(initializer).?;
const str_ptr = try c.builder.addConstant(val, .ptr);
const str_ptr = try c.builder.addConstant(val.ref(), .ptr);
if (dest_ty.isArray()) {
return c.comp.diag.fatalNoSrc("TODO memcpy\n", .{});
return c.fail("TODO memcpy\n", .{});
} else {
try c.builder.addStore(ptr, str_ptr);
}
@ -1288,5 +1291,5 @@ fn genInitializer(c: *CodeGen, ptr: Ir.Ref, dest_ty: Type, initializer: NodeInde
fn genVar(c: *CodeGen, decl: NodeIndex) Error!void {
_ = decl;
return c.comp.diag.fatalNoSrc("TODO CodeGen.genVar\n", .{});
return c.fail("TODO CodeGen.genVar\n", .{});
}

View File

@ -1,8 +1,9 @@
const std = @import("std");
const assert = std.debug.assert;
const mem = std.mem;
const Allocator = mem.Allocator;
const assert = std.debug.assert;
const EpochSeconds = std.time.epoch.EpochSeconds;
const mem = std.mem;
const Interner = @import("backend").Interner;
const Builtins = @import("Builtins.zig");
const Builtin = Builtins.Builtin;
const Diagnostics = @import("Diagnostics.zig");
@ -12,18 +13,16 @@ const Tokenizer = @import("Tokenizer.zig");
const Token = Tokenizer.Token;
const Type = @import("Type.zig");
const Pragma = @import("Pragma.zig");
const StringInterner = @import("StringInterner.zig");
const StrInt = @import("StringInterner.zig");
const record_layout = @import("record_layout.zig");
const target_util = @import("target.zig");
const Compilation = @This();
pub const Error = error{
/// A fatal error has ocurred and compilation has stopped.
FatalError,
} || Allocator.Error;
pub const bit_int_max_bits = 128;
pub const bit_int_max_bits = std.math.maxInt(u16);
const path_buf_stack_limit = 1024;
/// Environment variables used during compilation / linking.
@ -58,12 +57,12 @@ pub const Environment = struct {
/// Load all of the environment variables using the std.process API. Do not use if using Aro as a shared library on Linux without libc
/// See https://github.com/ziglang/zig/issues/4524
/// Assumes that `self` has been default-initialized
pub fn loadAll(self: *Environment, allocator: std.mem.Allocator) !void {
errdefer self.deinit(allocator);
pub fn loadAll(allocator: std.mem.Allocator) !Environment {
var env: Environment = .{};
errdefer env.deinit(allocator);
inline for (@typeInfo(@TypeOf(self.*)).Struct.fields) |field| {
std.debug.assert(@field(self, field.name) == null);
inline for (@typeInfo(@TypeOf(env)).Struct.fields) |field| {
std.debug.assert(@field(env, field.name) == null);
var env_var_buf: [field.name.len]u8 = undefined;
const env_var_name = std.ascii.upperString(&env_var_buf, field.name);
@ -72,8 +71,9 @@ pub const Environment = struct {
error.EnvironmentVariableNotFound => null,
error.InvalidUtf8 => null,
};
@field(self, field.name) = val;
@field(env, field.name) = val;
}
return env;
}
/// Use this only if environment slices were allocated with `allocator` (such as via `loadAll`)
@ -87,16 +87,19 @@ pub const Environment = struct {
}
};
const Compilation = @This();
gpa: Allocator,
diagnostics: Diagnostics,
environment: Environment = .{},
sources: std.StringArrayHashMap(Source),
diag: Diagnostics,
include_dirs: std.ArrayList([]const u8),
system_include_dirs: std.ArrayList([]const u8),
sources: std.StringArrayHashMapUnmanaged(Source) = .{},
include_dirs: std.ArrayListUnmanaged([]const u8) = .{},
system_include_dirs: std.ArrayListUnmanaged([]const u8) = .{},
target: std.Target = @import("builtin").target,
pragma_handlers: std.StringArrayHashMap(*Pragma),
pragma_handlers: std.StringArrayHashMapUnmanaged(*Pragma) = .{},
langopts: LangOpts = .{},
generated_buf: std.ArrayList(u8),
generated_buf: std.ArrayListUnmanaged(u8) = .{},
builtins: Builtins = .{},
types: struct {
wchar: Type = undefined,
@ -122,21 +125,31 @@ types: struct {
int16: Type = .{ .specifier = .invalid },
int64: Type = .{ .specifier = .invalid },
} = .{},
string_interner: StringInterner = .{},
string_interner: StrInt = .{},
interner: Interner = .{},
ms_cwd_source_id: ?Source.Id = null,
pub fn init(gpa: Allocator) Compilation {
return .{
.gpa = gpa,
.sources = std.StringArrayHashMap(Source).init(gpa),
.diag = Diagnostics.init(gpa),
.include_dirs = std.ArrayList([]const u8).init(gpa),
.system_include_dirs = std.ArrayList([]const u8).init(gpa),
.pragma_handlers = std.StringArrayHashMap(*Pragma).init(gpa),
.generated_buf = std.ArrayList(u8).init(gpa),
.diagnostics = Diagnostics.init(gpa),
};
}
/// Initialize Compilation with default environment,
/// pragma handlers and emulation mode set to target.
pub fn initDefault(gpa: Allocator) !Compilation {
var comp: Compilation = .{
.gpa = gpa,
.environment = try Environment.loadAll(gpa),
.diagnostics = Diagnostics.init(gpa),
};
errdefer comp.deinit();
try comp.addDefaultPragmaHandlers();
comp.langopts.setEmulatedCompiler(target_util.systemCompiler(comp.target));
return comp;
}
pub fn deinit(comp: *Compilation) void {
for (comp.pragma_handlers.values()) |pragma| {
pragma.deinit(pragma, comp);
@ -146,19 +159,17 @@ pub fn deinit(comp: *Compilation) void {
comp.gpa.free(source.buf);
comp.gpa.free(source.splice_locs);
}
comp.sources.deinit();
comp.diag.deinit();
comp.include_dirs.deinit();
comp.sources.deinit(comp.gpa);
comp.diagnostics.deinit();
comp.include_dirs.deinit(comp.gpa);
for (comp.system_include_dirs.items) |path| comp.gpa.free(path);
comp.system_include_dirs.deinit();
comp.pragma_handlers.deinit();
comp.generated_buf.deinit();
comp.system_include_dirs.deinit(comp.gpa);
comp.pragma_handlers.deinit(comp.gpa);
comp.generated_buf.deinit(comp.gpa);
comp.builtins.deinit(comp.gpa);
comp.string_interner.deinit(comp.gpa);
}
pub fn intern(comp: *Compilation, str: []const u8) !StringInterner.StringId {
return comp.string_interner.intern(comp.gpa, str);
comp.interner.deinit(comp.gpa);
comp.environment.deinit(comp.gpa);
}
pub fn getSourceEpoch(self: *const Compilation, max: i64) !?i64 {
@ -173,7 +184,7 @@ const max_timestamp = 253402300799;
fn getTimestamp(comp: *Compilation) !u47 {
const provided: ?i64 = comp.getSourceEpoch(max_timestamp) catch blk: {
try comp.diag.add(.{
try comp.addDiagnostic(.{
.tag = .invalid_source_epoch,
.loc = .{ .id = .unused, .byte_offset = 0, .line = 0 },
}, &.{});
@ -219,32 +230,15 @@ fn generateDateAndTime(w: anytype, timestamp: u47) !void {
});
}
/// Generate builtin macros that will be available to each source file.
pub fn generateBuiltinMacros(comp: *Compilation) !Source {
try comp.generateBuiltinTypes();
/// Which set of system defines to generate via generateBuiltinMacros
pub const SystemDefinesMode = enum {
/// Only define macros required by the C standard (date/time macros and those beginning with `__STDC`)
no_system_defines,
/// Define the standard set of system macros
include_system_defines,
};
var buf = std.ArrayList(u8).init(comp.gpa);
defer buf.deinit();
const w = buf.writer();
// standard macros
try w.writeAll(
\\#define __VERSION__ "Aro
++ @import("lib.zig").version_str ++ "\"\n" ++
\\#define __Aro__
\\#define __STDC__ 1
\\#define __STDC_HOSTED__ 1
\\#define __STDC_NO_ATOMICS__ 1
\\#define __STDC_NO_COMPLEX__ 1
\\#define __STDC_NO_THREADS__ 1
\\#define __STDC_NO_VLA__ 1
\\#define __STDC_UTF_16__ 1
\\#define __STDC_UTF_32__ 1
\\
);
if (comp.langopts.standard.StdCVersionMacro()) |stdc_version| {
try w.print("#define __STDC_VERSION__ {s}\n", .{stdc_version});
}
fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
const ptr_width = comp.target.ptrBitWidth();
// os macros
@ -414,10 +408,6 @@ pub fn generateBuiltinMacros(comp: *Compilation) !Source {
\\
);
// timestamps
const timestamp = try comp.getTimestamp();
try generateDateAndTime(w, timestamp);
// types
if (comp.getCharSignedness() == .unsigned) try w.writeAll("#define __CHAR_UNSIGNED__ 1\n");
try w.writeAll("#define __CHAR_BIT__ 8\n");
@ -489,6 +479,49 @@ pub fn generateBuiltinMacros(comp: *Compilation) !Source {
\\#define __DECIMAL_DIG__ __LDBL_DECIMAL_DIG__
\\
);
}
/// Generate builtin macros that will be available to each source file.
pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefinesMode) !Source {
try comp.generateBuiltinTypes();
var buf = std.ArrayList(u8).init(comp.gpa);
defer buf.deinit();
if (system_defines_mode == .include_system_defines) {
try buf.appendSlice(
\\#define __VERSION__ "Aro
++ @import("backend").version_str ++ "\"\n" ++
\\#define __Aro__
\\
);
}
// standard macros
try buf.appendSlice(
\\#define __STDC__ 1
\\#define __STDC_HOSTED__ 1
\\#define __STDC_NO_ATOMICS__ 1
\\#define __STDC_NO_COMPLEX__ 1
\\#define __STDC_NO_THREADS__ 1
\\#define __STDC_NO_VLA__ 1
\\#define __STDC_UTF_16__ 1
\\#define __STDC_UTF_32__ 1
\\
);
if (comp.langopts.standard.StdCVersionMacro()) |stdc_version| {
try buf.appendSlice("#define __STDC_VERSION__ ");
try buf.appendSlice(stdc_version);
try buf.append('\n');
}
// timestamps
const timestamp = try comp.getTimestamp();
try generateDateAndTime(buf.writer(), timestamp);
if (system_defines_mode == .include_system_defines) {
try comp.generateSystemDefines(buf.writer());
}
return comp.addSourceFromBuffer("<builtin>", buf.items);
}
@ -573,7 +606,7 @@ fn generateFloatMacros(w: anytype, prefix: []const u8, semantics: target_util.FP
try w.print("#define {s}MIN__ {s}{s}\n", .{ prefix_slice, min, ext });
}
fn generateTypeMacro(w: anytype, mapper: StringInterner.TypeMapper, name: []const u8, ty: Type, langopts: LangOpts) !void {
fn generateTypeMacro(w: anytype, mapper: StrInt.TypeMapper, name: []const u8, ty: Type, langopts: LangOpts) !void {
try w.print("#define {s} ", .{name});
try ty.print(mapper, langopts, w);
try w.writeByte('\n');
@ -661,7 +694,7 @@ fn intSize(comp: *const Compilation, specifier: Type.Specifier) u64 {
return ty.sizeof(comp).?;
}
fn generateExactWidthTypes(comp: *const Compilation, w: anytype, mapper: StringInterner.TypeMapper) !void {
fn generateExactWidthTypes(comp: *const Compilation, w: anytype, mapper: StrInt.TypeMapper) !void {
try comp.generateExactWidthType(w, mapper, .schar);
if (comp.intSize(.short) > comp.intSize(.char)) {
@ -726,7 +759,7 @@ fn generateSuffixMacro(comp: *const Compilation, prefix: []const u8, w: anytype,
/// Name macro (e.g. #define __UINT32_TYPE__ unsigned int)
/// Format strings (e.g. #define __UINT32_FMTu__ "u")
/// Suffix macro (e.g. #define __UINT32_C_SUFFIX__ U)
fn generateExactWidthType(comp: *const Compilation, w: anytype, mapper: StringInterner.TypeMapper, specifier: Type.Specifier) !void {
fn generateExactWidthType(comp: *const Compilation, w: anytype, mapper: StrInt.TypeMapper, specifier: Type.Specifier) !void {
var ty = Type{ .specifier = specifier };
const width = 8 * ty.sizeof(comp).?;
const unsigned = ty.isUnsignedInt(comp);
@ -751,13 +784,17 @@ fn generateExactWidthType(comp: *const Compilation, w: anytype, mapper: StringIn
try comp.generateSuffixMacro(prefix.constSlice(), w, ty);
}
pub fn hasFloat128(comp: *const Compilation) bool {
return target_util.hasFloat128(comp.target);
}
pub fn hasHalfPrecisionFloatABI(comp: *const Compilation) bool {
return comp.langopts.allow_half_args_and_returns or target_util.hasHalfPrecisionFloatABI(comp.target);
}
fn generateNsConstantStringType(comp: *Compilation) !void {
comp.types.ns_constant_string.record = .{
.name = try comp.intern("__NSConstantString_tag"),
.name = try StrInt.intern(comp, "__NSConstantString_tag"),
.fields = &comp.types.ns_constant_string.fields,
.field_attributes = null,
.type_layout = undefined,
@ -765,10 +802,10 @@ fn generateNsConstantStringType(comp: *Compilation) !void {
const const_int_ptr = Type{ .specifier = .pointer, .data = .{ .sub_type = &comp.types.ns_constant_string.int_ty } };
const const_char_ptr = Type{ .specifier = .pointer, .data = .{ .sub_type = &comp.types.ns_constant_string.char_ty } };
comp.types.ns_constant_string.fields[0] = .{ .name = try comp.intern("isa"), .ty = const_int_ptr };
comp.types.ns_constant_string.fields[1] = .{ .name = try comp.intern("flags"), .ty = .{ .specifier = .int } };
comp.types.ns_constant_string.fields[2] = .{ .name = try comp.intern("str"), .ty = const_char_ptr };
comp.types.ns_constant_string.fields[3] = .{ .name = try comp.intern("length"), .ty = .{ .specifier = .long } };
comp.types.ns_constant_string.fields[0] = .{ .name = try StrInt.intern(comp, "isa"), .ty = const_int_ptr };
comp.types.ns_constant_string.fields[1] = .{ .name = try StrInt.intern(comp, "flags"), .ty = .{ .specifier = .int } };
comp.types.ns_constant_string.fields[2] = .{ .name = try StrInt.intern(comp, "str"), .ty = const_char_ptr };
comp.types.ns_constant_string.fields[3] = .{ .name = try StrInt.intern(comp, "length"), .ty = .{ .specifier = .long } };
comp.types.ns_constant_string.ty = .{ .specifier = .@"struct", .data = .{ .record = &comp.types.ns_constant_string.record } };
record_layout.compute(&comp.types.ns_constant_string.record, comp.types.ns_constant_string.ty, comp, null);
}
@ -795,7 +832,7 @@ fn generateVaListType(comp: *Compilation) !Type {
};
// TODO this might be bad?
const arena = comp.diag.arena.allocator();
const arena = comp.diagnostics.arena.allocator();
var ty: Type = undefined;
switch (kind) {
@ -804,7 +841,7 @@ fn generateVaListType(comp: *Compilation) !Type {
.aarch64_va_list => {
const record_ty = try arena.create(Type.Record);
record_ty.* = .{
.name = try comp.intern("__va_list_tag"),
.name = try StrInt.intern(comp, "__va_list_tag"),
.fields = try arena.alloc(Type.Record.Field, 5),
.field_attributes = null,
.type_layout = undefined, // computed below
@ -812,18 +849,18 @@ fn generateVaListType(comp: *Compilation) !Type {
const void_ty = try arena.create(Type);
void_ty.* = .{ .specifier = .void };
const void_ptr = Type{ .specifier = .pointer, .data = .{ .sub_type = void_ty } };
record_ty.fields[0] = .{ .name = try comp.intern("__stack"), .ty = void_ptr };
record_ty.fields[1] = .{ .name = try comp.intern("__gr_top"), .ty = void_ptr };
record_ty.fields[2] = .{ .name = try comp.intern("__vr_top"), .ty = void_ptr };
record_ty.fields[3] = .{ .name = try comp.intern("__gr_offs"), .ty = .{ .specifier = .int } };
record_ty.fields[4] = .{ .name = try comp.intern("__vr_offs"), .ty = .{ .specifier = .int } };
record_ty.fields[0] = .{ .name = try StrInt.intern(comp, "__stack"), .ty = void_ptr };
record_ty.fields[1] = .{ .name = try StrInt.intern(comp, "__gr_top"), .ty = void_ptr };
record_ty.fields[2] = .{ .name = try StrInt.intern(comp, "__vr_top"), .ty = void_ptr };
record_ty.fields[3] = .{ .name = try StrInt.intern(comp, "__gr_offs"), .ty = .{ .specifier = .int } };
record_ty.fields[4] = .{ .name = try StrInt.intern(comp, "__vr_offs"), .ty = .{ .specifier = .int } };
ty = .{ .specifier = .@"struct", .data = .{ .record = record_ty } };
record_layout.compute(record_ty, ty, comp, null);
},
.x86_64_va_list => {
const record_ty = try arena.create(Type.Record);
record_ty.* = .{
.name = try comp.intern("__va_list_tag"),
.name = try StrInt.intern(comp, "__va_list_tag"),
.fields = try arena.alloc(Type.Record.Field, 4),
.field_attributes = null,
.type_layout = undefined, // computed below
@ -831,10 +868,10 @@ fn generateVaListType(comp: *Compilation) !Type {
const void_ty = try arena.create(Type);
void_ty.* = .{ .specifier = .void };
const void_ptr = Type{ .specifier = .pointer, .data = .{ .sub_type = void_ty } };
record_ty.fields[0] = .{ .name = try comp.intern("gp_offset"), .ty = .{ .specifier = .uint } };
record_ty.fields[1] = .{ .name = try comp.intern("fp_offset"), .ty = .{ .specifier = .uint } };
record_ty.fields[2] = .{ .name = try comp.intern("overflow_arg_area"), .ty = void_ptr };
record_ty.fields[3] = .{ .name = try comp.intern("reg_save_area"), .ty = void_ptr };
record_ty.fields[0] = .{ .name = try StrInt.intern(comp, "gp_offset"), .ty = .{ .specifier = .uint } };
record_ty.fields[1] = .{ .name = try StrInt.intern(comp, "fp_offset"), .ty = .{ .specifier = .uint } };
record_ty.fields[2] = .{ .name = try StrInt.intern(comp, "overflow_arg_area"), .ty = void_ptr };
record_ty.fields[3] = .{ .name = try StrInt.intern(comp, "reg_save_area"), .ty = void_ptr };
ty = .{ .specifier = .@"struct", .data = .{ .record = record_ty } };
record_layout.compute(record_ty, ty, comp, null);
},
@ -932,7 +969,7 @@ pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void {
base_dir.access("include/stddef.h", .{}) catch continue;
const path = try std.fs.path.join(comp.gpa, &.{ dirname, "include" });
errdefer comp.gpa.free(path);
try comp.system_include_dirs.append(path);
try comp.system_include_dirs.append(comp.gpa, path);
break;
} else return error.AroIncludeNotFound;
@ -946,12 +983,12 @@ pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void {
if (!std.meta.isError(std.fs.accessAbsolute(multiarch_path, .{}))) {
const duped = try comp.gpa.dupe(u8, multiarch_path);
errdefer comp.gpa.free(duped);
try comp.system_include_dirs.append(duped);
try comp.system_include_dirs.append(comp.gpa, duped);
}
}
const usr_include = try comp.gpa.dupe(u8, "/usr/include");
errdefer comp.gpa.free(usr_include);
try comp.system_include_dirs.append(usr_include);
try comp.system_include_dirs.append(comp.gpa, usr_include);
}
pub fn getSource(comp: *const Compilation, id: Source.Id) Source {
@ -980,7 +1017,7 @@ pub fn addSourceFromReader(comp: *Compilation, reader: anytype, path: []const u8
/// To add the contents of an arbitrary reader as a Source, see addSourceFromReader
/// To add a file's contents given its path, see addSourceFromPath
pub fn addSourceFromOwnedBuffer(comp: *Compilation, buf: []u8, path: []const u8, kind: Source.Kind) !Source {
try comp.sources.ensureUnusedCapacity(1);
try comp.sources.ensureUnusedCapacity(comp.gpa, 1);
var contents = buf;
const duped_path = try comp.gpa.dupe(u8, path);
@ -1022,7 +1059,7 @@ pub fn addSourceFromOwnedBuffer(comp: *Compilation, buf: []u8, path: []const u8,
i = backslash_loc;
try splice_list.append(i);
if (state == .trailing_ws) {
try comp.diag.add(.{
try comp.addDiagnostic(.{
.tag = .backslash_newline_escape,
.loc = .{ .id = source_id, .byte_offset = i, .line = line },
}, &.{});
@ -1046,7 +1083,7 @@ pub fn addSourceFromOwnedBuffer(comp: *Compilation, buf: []u8, path: []const u8,
try splice_list.append(i);
}
if (state == .trailing_ws) {
try comp.diag.add(.{
try comp.addDiagnostic(.{
.tag = .backslash_newline_escape,
.loc = .{ .id = source_id, .byte_offset = i, .line = line },
}, &.{});
@ -1105,7 +1142,7 @@ pub fn addSourceFromOwnedBuffer(comp: *Compilation, buf: []u8, path: []const u8,
if (i != contents.len) contents = try comp.gpa.realloc(contents, i);
errdefer @compileError("errdefers in callers would possibly free the realloced slice using the original len");
var source = Source{
const source = Source{
.id = source_id,
.path = duped_path,
.buf = contents,
@ -1259,7 +1296,7 @@ pub const IncludeType = enum {
angle_brackets,
};
fn getFileContents(comp: *Compilation, path: []const u8) ![]const u8 {
fn getFileContents(comp: *Compilation, path: []const u8, limit: ?u32) ![]const u8 {
if (mem.indexOfScalar(u8, path, 0) != null) {
return error.FileNotFound;
}
@ -1267,7 +1304,16 @@ fn getFileContents(comp: *Compilation, path: []const u8) ![]const u8 {
const file = try std.fs.cwd().openFile(path, .{});
defer file.close();
return file.readToEndAlloc(comp.gpa, std.math.maxInt(u32));
var buf = std.ArrayList(u8).init(comp.gpa);
defer buf.deinit();
const max = limit orelse std.math.maxInt(u32);
file.reader().readAllArrayList(&buf, max) catch |e| switch (e) {
error.StreamTooLong => if (limit == null) return e,
else => return e,
};
return buf.toOwnedSlice();
}
pub fn findEmbed(
@ -1276,9 +1322,10 @@ pub fn findEmbed(
includer_token_source: Source.Id,
/// angle bracket vs quotes
include_type: IncludeType,
limit: ?u32,
) !?[]const u8 {
if (std.fs.path.isAbsolute(filename)) {
return if (comp.getFileContents(filename)) |some|
return if (comp.getFileContents(filename, limit)) |some|
some
else |err| switch (err) {
error.OutOfMemory => |e| return e,
@ -1295,7 +1342,7 @@ pub fn findEmbed(
while (try it.nextWithFile(filename, stack_fallback.get())) |found| {
defer stack_fallback.get().free(found.path);
if (comp.getFileContents(found.path)) |some|
if (comp.getFileContents(found.path, limit)) |some|
return some
else |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
@ -1342,7 +1389,7 @@ pub fn findInclude(
defer stack_fallback.get().free(found.path);
if (comp.addSourceFromPathExtra(found.path, found.kind)) |some| {
if (it.tried_ms_cwd) {
try comp.diag.add(.{
try comp.addDiagnostic(.{
.tag = .ms_search_rule,
.extra = .{ .str = some.path },
.loc = .{
@ -1362,7 +1409,7 @@ pub fn findInclude(
}
pub fn addPragmaHandler(comp: *Compilation, name: []const u8, handler: *Pragma) Allocator.Error!void {
try comp.pragma_handlers.putNoClobber(name, handler);
try comp.pragma_handlers.putNoClobber(comp.gpa, name, handler);
}
pub fn addDefaultPragmaHandlers(comp: *Compilation) Allocator.Error!void {
@ -1444,7 +1491,7 @@ pub const CharUnitSize = enum(u32) {
}
};
pub const renderErrors = Diagnostics.render;
pub const addDiagnostic = Diagnostics.add;
test "addSourceFromReader" {
const Test = struct {
@ -1456,7 +1503,7 @@ test "addSourceFromReader" {
const source = try comp.addSourceFromReader(buf_reader.reader(), "path", .user);
try std.testing.expectEqualStrings(expected, source.buf);
try std.testing.expectEqual(warning_count, @as(u32, @intCast(comp.diag.list.items.len)));
try std.testing.expectEqual(warning_count, @as(u32, @intCast(comp.diagnostics.list.items.len)));
try std.testing.expectEqualSlices(u32, splices, source.splice_locs);
}

588
deps/aro/aro/Diagnostics.zig vendored Normal file
View File

@ -0,0 +1,588 @@
const std = @import("std");
const Allocator = mem.Allocator;
const mem = std.mem;
const Source = @import("Source.zig");
const Compilation = @import("Compilation.zig");
const Attribute = @import("Attribute.zig");
const Builtins = @import("Builtins.zig");
const Builtin = Builtins.Builtin;
const Header = @import("Builtins/Properties.zig").Header;
const Tree = @import("Tree.zig");
const is_windows = @import("builtin").os.tag == .windows;
const LangOpts = @import("LangOpts.zig");
pub const Message = struct {
tag: Tag,
kind: Kind = undefined,
loc: Source.Location = .{},
extra: Extra = .{ .none = {} },
pub const Extra = union {
str: []const u8,
tok_id: struct {
expected: Tree.Token.Id,
actual: Tree.Token.Id,
},
tok_id_expected: Tree.Token.Id,
arguments: struct {
expected: u32,
actual: u32,
},
codepoints: struct {
actual: u21,
resembles: u21,
},
attr_arg_count: struct {
attribute: Attribute.Tag,
expected: u32,
},
attr_arg_type: struct {
expected: Attribute.ArgumentType,
actual: Attribute.ArgumentType,
},
attr_enum: struct {
tag: Attribute.Tag,
},
ignored_record_attr: struct {
tag: Attribute.Tag,
specifier: enum { @"struct", @"union", @"enum" },
},
builtin_with_header: struct {
builtin: Builtin.Tag,
header: Header,
},
invalid_escape: struct {
offset: u32,
char: u8,
},
actual_codepoint: u21,
ascii: u7,
unsigned: u64,
offset: u64,
pow_2_as_string: u8,
signed: i64,
normalized: []const u8,
none: void,
};
};
const Properties = struct {
msg: []const u8,
kind: Kind,
extra: std.meta.FieldEnum(Message.Extra) = .none,
opt: ?u8 = null,
all: bool = false,
w_extra: bool = false,
pedantic: bool = false,
suppress_version: ?LangOpts.Standard = null,
suppress_unless_version: ?LangOpts.Standard = null,
suppress_gnu: bool = false,
suppress_gcc: bool = false,
suppress_clang: bool = false,
suppress_msvc: bool = false,
pub fn makeOpt(comptime str: []const u8) u16 {
return @offsetOf(Options, str);
}
pub fn getKind(prop: Properties, options: *Options) Kind {
const opt = @as([*]Kind, @ptrCast(options))[prop.opt orelse return prop.kind];
if (opt == .default) return prop.kind;
return opt;
}
pub const max_bits = Compilation.bit_int_max_bits;
};
pub const Tag = @import("Diagnostics/messages.def").with(Properties).Tag;
pub const Kind = enum { @"fatal error", @"error", note, warning, off, default };
pub const Options = struct {
// do not directly use these, instead add `const NAME = true;`
all: Kind = .default,
extra: Kind = .default,
pedantic: Kind = .default,
@"unsupported-pragma": Kind = .default,
@"c99-extensions": Kind = .default,
@"implicit-int": Kind = .default,
@"duplicate-decl-specifier": Kind = .default,
@"missing-declaration": Kind = .default,
@"extern-initializer": Kind = .default,
@"implicit-function-declaration": Kind = .default,
@"unused-value": Kind = .default,
@"unreachable-code": Kind = .default,
@"unknown-warning-option": Kind = .default,
@"gnu-empty-struct": Kind = .default,
@"gnu-alignof-expression": Kind = .default,
@"macro-redefined": Kind = .default,
@"generic-qual-type": Kind = .default,
multichar: Kind = .default,
@"pointer-integer-compare": Kind = .default,
@"compare-distinct-pointer-types": Kind = .default,
@"literal-conversion": Kind = .default,
@"cast-qualifiers": Kind = .default,
@"array-bounds": Kind = .default,
@"int-conversion": Kind = .default,
@"pointer-type-mismatch": Kind = .default,
@"c23-extensions": Kind = .default,
@"incompatible-pointer-types": Kind = .default,
@"excess-initializers": Kind = .default,
@"division-by-zero": Kind = .default,
@"initializer-overrides": Kind = .default,
@"incompatible-pointer-types-discards-qualifiers": Kind = .default,
@"unknown-attributes": Kind = .default,
@"ignored-attributes": Kind = .default,
@"builtin-macro-redefined": Kind = .default,
@"gnu-label-as-value": Kind = .default,
@"malformed-warning-check": Kind = .default,
@"#pragma-messages": Kind = .default,
@"newline-eof": Kind = .default,
@"empty-translation-unit": Kind = .default,
@"implicitly-unsigned-literal": Kind = .default,
@"c99-compat": Kind = .default,
@"unicode-zero-width": Kind = .default,
@"unicode-homoglyph": Kind = .default,
unicode: Kind = .default,
@"return-type": Kind = .default,
@"dollar-in-identifier-extension": Kind = .default,
@"unknown-pragmas": Kind = .default,
@"predefined-identifier-outside-function": Kind = .default,
@"many-braces-around-scalar-init": Kind = .default,
uninitialized: Kind = .default,
@"gnu-statement-expression": Kind = .default,
@"gnu-imaginary-constant": Kind = .default,
@"gnu-complex-integer": Kind = .default,
@"ignored-qualifiers": Kind = .default,
@"integer-overflow": Kind = .default,
@"extra-semi": Kind = .default,
@"gnu-binary-literal": Kind = .default,
@"variadic-macros": Kind = .default,
varargs: Kind = .default,
@"#warnings": Kind = .default,
@"deprecated-declarations": Kind = .default,
@"backslash-newline-escape": Kind = .default,
@"pointer-to-int-cast": Kind = .default,
@"gnu-case-range": Kind = .default,
@"c++-compat": Kind = .default,
vla: Kind = .default,
@"float-overflow-conversion": Kind = .default,
@"float-zero-conversion": Kind = .default,
@"float-conversion": Kind = .default,
@"gnu-folding-constant": Kind = .default,
undef: Kind = .default,
@"ignored-pragmas": Kind = .default,
@"gnu-include-next": Kind = .default,
@"include-next-outside-header": Kind = .default,
@"include-next-absolute-path": Kind = .default,
@"enum-too-large": Kind = .default,
@"fixed-enum-extension": Kind = .default,
@"designated-init": Kind = .default,
@"attribute-warning": Kind = .default,
@"invalid-noreturn": Kind = .default,
@"zero-length-array": Kind = .default,
@"old-style-flexible-struct": Kind = .default,
@"gnu-zero-variadic-macro-arguments": Kind = .default,
@"main-return-type": Kind = .default,
@"expansion-to-defined": Kind = .default,
@"bit-int-extension": Kind = .default,
@"keyword-macro": Kind = .default,
@"pointer-arith": Kind = .default,
@"sizeof-array-argument": Kind = .default,
@"pre-c23-compat": Kind = .default,
@"pointer-bool-conversion": Kind = .default,
@"string-conversion": Kind = .default,
@"gnu-auto-type": Kind = .default,
@"gnu-union-cast": Kind = .default,
@"pointer-sign": Kind = .default,
@"fuse-ld-path": Kind = .default,
@"language-extension-token": Kind = .default,
@"complex-component-init": Kind = .default,
@"microsoft-include": Kind = .default,
@"microsoft-end-of-file": Kind = .default,
@"invalid-source-encoding": Kind = .default,
@"four-char-constants": Kind = .default,
@"unknown-escape-sequence": Kind = .default,
@"invalid-pp-token": Kind = .default,
@"deprecated-non-prototype": Kind = .default,
@"duplicate-embed-param": Kind = .default,
@"unsupported-embed-param": Kind = .default,
@"unused-result": Kind = .default,
normalized: Kind = .default,
};
const Diagnostics = @This();
list: std.ArrayListUnmanaged(Message) = .{},
arena: std.heap.ArenaAllocator,
fatal_errors: bool = false,
options: Options = .{},
errors: u32 = 0,
macro_backtrace_limit: u32 = 6,
pub fn warningExists(name: []const u8) bool {
inline for (std.meta.fields(Options)) |f| {
if (mem.eql(u8, f.name, name)) return true;
}
return false;
}
pub fn set(d: *Diagnostics, name: []const u8, to: Kind) !void {
inline for (std.meta.fields(Options)) |f| {
if (mem.eql(u8, f.name, name)) {
@field(d.options, f.name) = to;
return;
}
}
try d.addExtra(.{}, .{
.tag = .unknown_warning,
.extra = .{ .str = name },
}, &.{});
}
pub fn init(gpa: Allocator) Diagnostics {
return .{
.arena = std.heap.ArenaAllocator.init(gpa),
};
}
pub fn deinit(d: *Diagnostics) void {
d.list.deinit(d.arena.child_allocator);
d.arena.deinit();
}
pub fn add(comp: *Compilation, msg: Message, expansion_locs: []const Source.Location) Compilation.Error!void {
return comp.diagnostics.addExtra(comp.langopts, msg, expansion_locs);
}
pub fn addExtra(
d: *Diagnostics,
langopts: LangOpts,
msg: Message,
expansion_locs: []const Source.Location,
) Compilation.Error!void {
const kind = d.tagKind(msg.tag, langopts);
if (kind == .off) return;
var copy = msg;
copy.kind = kind;
if (expansion_locs.len != 0) copy.loc = expansion_locs[expansion_locs.len - 1];
try d.list.append(d.arena.child_allocator, copy);
if (expansion_locs.len != 0) {
// Add macro backtrace notes in reverse order omitting from the middle if needed.
var i = expansion_locs.len - 1;
const half = d.macro_backtrace_limit / 2;
const limit = if (i < d.macro_backtrace_limit) 0 else i - half;
try d.list.ensureUnusedCapacity(
d.arena.child_allocator,
if (limit == 0) expansion_locs.len else d.macro_backtrace_limit + 1,
);
while (i > limit) {
i -= 1;
d.list.appendAssumeCapacity(.{
.tag = .expanded_from_here,
.kind = .note,
.loc = expansion_locs[i],
});
}
if (limit != 0) {
d.list.appendAssumeCapacity(.{
.tag = .skipping_macro_backtrace,
.kind = .note,
.extra = .{ .unsigned = expansion_locs.len - d.macro_backtrace_limit },
});
i = half - 1;
while (i > 0) {
i -= 1;
d.list.appendAssumeCapacity(.{
.tag = .expanded_from_here,
.kind = .note,
.loc = expansion_locs[i],
});
}
}
d.list.appendAssumeCapacity(.{
.tag = .expanded_from_here,
.kind = .note,
.loc = msg.loc,
});
}
if (kind == .@"fatal error" or (kind == .@"error" and d.fatal_errors))
return error.FatalError;
}
pub fn render(comp: *Compilation, config: std.io.tty.Config) void {
if (comp.diagnostics.list.items.len == 0) return;
var m = defaultMsgWriter(config);
defer m.deinit();
renderMessages(comp, &m);
}
pub fn defaultMsgWriter(config: std.io.tty.Config) MsgWriter {
return MsgWriter.init(config);
}
pub fn renderMessages(comp: *Compilation, m: anytype) void {
var errors: u32 = 0;
var warnings: u32 = 0;
for (comp.diagnostics.list.items) |msg| {
switch (msg.kind) {
.@"fatal error", .@"error" => errors += 1,
.warning => warnings += 1,
.note => {},
.off => continue, // happens if an error is added before it is disabled
.default => unreachable,
}
renderMessage(comp, m, msg);
}
const w_s: []const u8 = if (warnings == 1) "" else "s";
const e_s: []const u8 = if (errors == 1) "" else "s";
if (errors != 0 and warnings != 0) {
m.print("{d} warning{s} and {d} error{s} generated.\n", .{ warnings, w_s, errors, e_s });
} else if (warnings != 0) {
m.print("{d} warning{s} generated.\n", .{ warnings, w_s });
} else if (errors != 0) {
m.print("{d} error{s} generated.\n", .{ errors, e_s });
}
comp.diagnostics.list.items.len = 0;
comp.diagnostics.errors += errors;
}
pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void {
var line: ?[]const u8 = null;
var end_with_splice = false;
const width = if (msg.loc.id != .unused) blk: {
var loc = msg.loc;
switch (msg.tag) {
.escape_sequence_overflow,
.invalid_universal_character,
=> loc.byte_offset += @truncate(msg.extra.offset),
.non_standard_escape_char,
.unknown_escape_sequence,
=> loc.byte_offset += msg.extra.invalid_escape.offset,
else => {},
}
const source = comp.getSource(loc.id);
var line_col = source.lineCol(loc);
line = line_col.line;
end_with_splice = line_col.end_with_splice;
if (msg.tag == .backslash_newline_escape) {
line = line_col.line[0 .. line_col.col - 1];
line_col.col += 1;
line_col.width += 1;
}
m.location(source.path, line_col.line_no, line_col.col);
break :blk line_col.width;
} else 0;
m.start(msg.kind);
const prop = msg.tag.property();
switch (prop.extra) {
.str => printRt(m, prop.msg, .{"{s}"}, .{msg.extra.str}),
.tok_id => printRt(m, prop.msg, .{ "{s}", "{s}" }, .{
msg.extra.tok_id.expected.symbol(),
msg.extra.tok_id.actual.symbol(),
}),
.tok_id_expected => printRt(m, prop.msg, .{"{s}"}, .{msg.extra.tok_id_expected.symbol()}),
.arguments => printRt(m, prop.msg, .{ "{d}", "{d}" }, .{
msg.extra.arguments.expected,
msg.extra.arguments.actual,
}),
.codepoints => printRt(m, prop.msg, .{ "{X:0>4}", "{u}" }, .{
msg.extra.codepoints.actual,
msg.extra.codepoints.resembles,
}),
.attr_arg_count => printRt(m, prop.msg, .{ "{s}", "{d}" }, .{
@tagName(msg.extra.attr_arg_count.attribute),
msg.extra.attr_arg_count.expected,
}),
.attr_arg_type => printRt(m, prop.msg, .{ "{s}", "{s}" }, .{
msg.extra.attr_arg_type.expected.toString(),
msg.extra.attr_arg_type.actual.toString(),
}),
.actual_codepoint => printRt(m, prop.msg, .{"{X:0>4}"}, .{msg.extra.actual_codepoint}),
.ascii => printRt(m, prop.msg, .{"{c}"}, .{msg.extra.ascii}),
.unsigned => printRt(m, prop.msg, .{"{d}"}, .{msg.extra.unsigned}),
.pow_2_as_string => printRt(m, prop.msg, .{"{s}"}, .{switch (msg.extra.pow_2_as_string) {
63 => "9223372036854775808",
64 => "18446744073709551616",
127 => "170141183460469231731687303715884105728",
128 => "340282366920938463463374607431768211456",
else => unreachable,
}}),
.signed => printRt(m, prop.msg, .{"{d}"}, .{msg.extra.signed}),
.attr_enum => printRt(m, prop.msg, .{ "{s}", "{s}" }, .{
@tagName(msg.extra.attr_enum.tag),
Attribute.Formatting.choices(msg.extra.attr_enum.tag),
}),
.ignored_record_attr => printRt(m, prop.msg, .{ "{s}", "{s}" }, .{
@tagName(msg.extra.ignored_record_attr.tag),
@tagName(msg.extra.ignored_record_attr.specifier),
}),
.builtin_with_header => printRt(m, prop.msg, .{ "{s}", "{s}" }, .{
@tagName(msg.extra.builtin_with_header.header),
Builtin.nameFromTag(msg.extra.builtin_with_header.builtin).span(),
}),
.invalid_escape => {
if (std.ascii.isPrint(msg.extra.invalid_escape.char)) {
const str: [1]u8 = .{msg.extra.invalid_escape.char};
printRt(m, prop.msg, .{"{s}"}, .{&str});
} else {
var buf: [3]u8 = undefined;
const str = std.fmt.bufPrint(&buf, "x{x}", .{std.fmt.fmtSliceHexLower(&.{msg.extra.invalid_escape.char})}) catch unreachable;
printRt(m, prop.msg, .{"{s}"}, .{str});
}
},
.normalized => {
const f = struct {
pub fn f(
bytes: []const u8,
comptime _: []const u8,
_: std.fmt.FormatOptions,
writer: anytype,
) !void {
var it: std.unicode.Utf8Iterator = .{
.bytes = bytes,
.i = 0,
};
while (it.nextCodepoint()) |codepoint| {
if (codepoint < 0x7F) {
try writer.writeByte(@intCast(codepoint));
} else if (codepoint < 0xFFFF) {
try writer.writeAll("\\u");
try std.fmt.formatInt(codepoint, 16, .upper, .{
.fill = '0',
.width = 4,
}, writer);
} else {
try writer.writeAll("\\U");
try std.fmt.formatInt(codepoint, 16, .upper, .{
.fill = '0',
.width = 8,
}, writer);
}
}
}
}.f;
printRt(m, prop.msg, .{"{s}"}, .{
std.fmt.Formatter(f){ .data = msg.extra.normalized },
});
},
.none, .offset => m.write(prop.msg),
}
if (prop.opt) |some| {
if (msg.kind == .@"error" and prop.kind != .@"error") {
m.print(" [-Werror,-W{s}]", .{optName(some)});
} else if (msg.kind != .note) {
m.print(" [-W{s}]", .{optName(some)});
}
}
m.end(line, width, end_with_splice);
}
fn printRt(m: anytype, str: []const u8, comptime fmts: anytype, args: anytype) void {
var i: usize = 0;
inline for (fmts, args) |fmt, arg| {
const new = std.mem.indexOfPos(u8, str, i, fmt).?;
m.write(str[i..new]);
i = new + fmt.len;
m.print(fmt, .{arg});
}
m.write(str[i..]);
}
fn optName(offset: u16) []const u8 {
return std.meta.fieldNames(Options)[offset / @sizeOf(Kind)];
}
fn tagKind(d: *Diagnostics, tag: Tag, langopts: LangOpts) Kind {
const prop = tag.property();
var kind = prop.getKind(&d.options);
if (prop.all) {
if (d.options.all != .default) kind = d.options.all;
}
if (prop.w_extra) {
if (d.options.extra != .default) kind = d.options.extra;
}
if (prop.pedantic) {
if (d.options.pedantic != .default) kind = d.options.pedantic;
}
if (prop.suppress_version) |some| if (langopts.standard.atLeast(some)) return .off;
if (prop.suppress_unless_version) |some| if (!langopts.standard.atLeast(some)) return .off;
if (prop.suppress_gnu and langopts.standard.isExplicitGNU()) return .off;
if (prop.suppress_gcc and langopts.emulate == .gcc) return .off;
if (prop.suppress_clang and langopts.emulate == .clang) return .off;
if (prop.suppress_msvc and langopts.emulate == .msvc) return .off;
if (kind == .@"error" and d.fatal_errors) kind = .@"fatal error";
return kind;
}
const MsgWriter = struct {
w: std.io.BufferedWriter(4096, std.fs.File.Writer),
config: std.io.tty.Config,
fn init(config: std.io.tty.Config) MsgWriter {
std.debug.getStderrMutex().lock();
return .{
.w = std.io.bufferedWriter(std.io.getStdErr().writer()),
.config = config,
};
}
pub fn deinit(m: *MsgWriter) void {
m.w.flush() catch {};
std.debug.getStderrMutex().unlock();
}
pub fn print(m: *MsgWriter, comptime fmt: []const u8, args: anytype) void {
m.w.writer().print(fmt, args) catch {};
}
fn write(m: *MsgWriter, msg: []const u8) void {
m.w.writer().writeAll(msg) catch {};
}
fn setColor(m: *MsgWriter, color: std.io.tty.Color) void {
m.config.setColor(m.w.writer(), color) catch {};
}
fn location(m: *MsgWriter, path: []const u8, line: u32, col: u32) void {
m.setColor(.bold);
m.print("{s}:{d}:{d}: ", .{ path, line, col });
}
fn start(m: *MsgWriter, kind: Kind) void {
switch (kind) {
.@"fatal error", .@"error" => m.setColor(.bright_red),
.note => m.setColor(.bright_cyan),
.warning => m.setColor(.bright_magenta),
.off, .default => unreachable,
}
m.write(switch (kind) {
.@"fatal error" => "fatal error: ",
.@"error" => "error: ",
.note => "note: ",
.warning => "warning: ",
.off, .default => unreachable,
});
m.setColor(.white);
}
fn end(m: *MsgWriter, maybe_line: ?[]const u8, col: u32, end_with_splice: bool) void {
const line = maybe_line orelse {
m.write("\n");
m.setColor(.reset);
return;
};
const trailer = if (end_with_splice) "\\ " else "";
m.setColor(.reset);
m.print("\n{s}{s}\n{s: >[3]}", .{ line, trailer, "", col });
m.setColor(.bold);
m.setColor(.bright_green);
m.write("^\n");
m.setColor(.reset);
}
};

2446
deps/aro/aro/Diagnostics/messages.def vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,18 +2,17 @@ const std = @import("std");
const mem = std.mem;
const Allocator = mem.Allocator;
const process = std.process;
const Codegen = @import("Codegen_legacy.zig");
const backend = @import("backend");
const Ir = backend.Ir;
const Object = backend.Object;
const Compilation = @import("Compilation.zig");
const Diagnostics = @import("Diagnostics.zig");
const LangOpts = @import("LangOpts.zig");
const Preprocessor = @import("Preprocessor.zig");
const Parser = @import("Parser.zig");
const Source = @import("Source.zig");
const Toolchain = @import("Toolchain.zig");
const util = @import("util.zig");
const target_util = @import("target.zig");
const Driver = @This();
pub const Linker = enum {
ld,
bfd,
@ -22,11 +21,14 @@ pub const Linker = enum {
mold,
};
const Driver = @This();
comp: *Compilation,
inputs: std.ArrayListUnmanaged(Source) = .{},
link_objects: std.ArrayListUnmanaged([]const u8) = .{},
output_name: ?[]const u8 = null,
sysroot: ?[]const u8 = null,
system_defines: Compilation.SystemDefinesMode = .include_system_defines,
temp_file_count: u32 = 0,
/// If false, do not emit line directives in -E mode
line_commands: bool = true,
@ -40,6 +42,7 @@ verbose_ast: bool = false,
verbose_pp: bool = false,
verbose_ir: bool = false,
verbose_linker_args: bool = false,
color: ?bool = null,
/// Full path to the aro executable
aro_name: []const u8 = "",
@ -87,8 +90,8 @@ pub const usage =
\\ -c, --compile Only run preprocess, compile, and assemble steps
\\ -D <macro>=<value> Define <macro> to <value> (defaults to 1)
\\ -E Only run the preprocessor
\\ -fchar8_t Enable char8_t (enabled by default in C2X and later)
\\ -fno-char8_t Disable char8_t (disabled by default for pre-C2X)
\\ -fchar8_t Enable char8_t (enabled by default in C23 and later)
\\ -fno-char8_t Disable char8_t (disabled by default for pre-C23)
\\ -fcolor-diagnostics Enable colors in diagnostics
\\ -fno-color-diagnostics Disable colors in diagnostics
\\ -fdeclspec Enable support for __declspec attributes
@ -131,6 +134,7 @@ pub const usage =
\\ --sysroot=<dir> Use dir as the logical root directory for headers and libraries (not fully implemented)
\\ --target=<value> Generate code for the given target
\\ -U <macro> Undefine <macro>
\\ -undef Do not predefine any system-specific macros. Standard predefined macros remain defined.
\\ -Werror Treat all warnings as errors
\\ -Werror=<warning> Treat warning as error
\\ -W<warning> Enable the specified warning
@ -172,23 +176,18 @@ pub fn parseArgs(
args: []const []const u8,
) !bool {
var i: usize = 1;
var color_setting: enum {
on,
off,
unset,
} = .unset;
var comment_arg: []const u8 = "";
while (i < args.len) : (i += 1) {
const arg = args[i];
if (mem.startsWith(u8, arg, "-") and arg.len > 1) {
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
std_out.print(usage, .{args[0]}) catch |er| {
return d.fatal("unable to print usage: {s}", .{util.errorDescription(er)});
return d.fatal("unable to print usage: {s}", .{errorDescription(er)});
};
return true;
} else if (mem.eql(u8, arg, "-v") or mem.eql(u8, arg, "--version")) {
std_out.writeAll(@import("lib.zig").version_str ++ "\n") catch |er| {
return d.fatal("unable to print version: {s}", .{util.errorDescription(er)});
std_out.writeAll(@import("backend").version_str ++ "\n") catch |er| {
return d.fatal("unable to print version: {s}", .{errorDescription(er)});
};
return true;
} else if (mem.startsWith(u8, arg, "-D")) {
@ -218,6 +217,8 @@ pub fn parseArgs(
macro = args[i];
}
try macro_buf.print("#undef {s}\n", .{macro});
} else if (mem.eql(u8, arg, "-undef")) {
d.system_defines = .no_system_defines;
} else if (mem.eql(u8, arg, "-c") or mem.eql(u8, arg, "--compile")) {
d.only_compile = true;
} else if (mem.eql(u8, arg, "-E")) {
@ -233,9 +234,9 @@ pub fn parseArgs(
} else if (mem.eql(u8, arg, "-fno-char8_t")) {
d.comp.langopts.has_char8_t_override = false;
} else if (mem.eql(u8, arg, "-fcolor-diagnostics")) {
color_setting = .on;
d.color = true;
} else if (mem.eql(u8, arg, "-fno-color-diagnostics")) {
color_setting = .off;
d.color = false;
} else if (mem.eql(u8, arg, "-fdollars-in-identifiers")) {
d.comp.langopts.dollars_in_identifiers = true;
} else if (mem.eql(u8, arg, "-fno-dollars-in-identifiers")) {
@ -255,7 +256,7 @@ pub fn parseArgs(
};
if (limit == 0) limit = std.math.maxInt(u32);
d.comp.diag.macro_backtrace_limit = limit;
d.comp.diagnostics.macro_backtrace_limit = limit;
} else if (mem.eql(u8, arg, "-fnative-half-type")) {
d.comp.langopts.use_native_half_type = true;
} else if (mem.eql(u8, arg, "-fnative-half-arguments-and-returns")) {
@ -290,7 +291,7 @@ pub fn parseArgs(
}
path = args[i];
}
try d.comp.include_dirs.append(path);
try d.comp.include_dirs.append(d.comp.gpa, path);
} else if (mem.startsWith(u8, arg, "-fsyntax-only")) {
d.only_syntax = true;
} else if (mem.startsWith(u8, arg, "-fno-syntax-only")) {
@ -307,17 +308,17 @@ pub fn parseArgs(
}
const duped = try d.comp.gpa.dupe(u8, path);
errdefer d.comp.gpa.free(duped);
try d.comp.system_include_dirs.append(duped);
try d.comp.system_include_dirs.append(d.comp.gpa, duped);
} else if (option(arg, "--emulate=")) |compiler_str| {
const compiler = std.meta.stringToEnum(LangOpts.Compiler, compiler_str) orelse {
try d.comp.diag.add(.{ .tag = .cli_invalid_emulate, .extra = .{ .str = arg } }, &.{});
try d.comp.addDiagnostic(.{ .tag = .cli_invalid_emulate, .extra = .{ .str = arg } }, &.{});
continue;
};
d.comp.langopts.setEmulatedCompiler(compiler);
} else if (option(arg, "-ffp-eval-method=")) |fp_method_str| {
const fp_eval_method = std.meta.stringToEnum(LangOpts.FPEvalMethod, fp_method_str) orelse .indeterminate;
if (fp_eval_method == .indeterminate) {
try d.comp.diag.add(.{ .tag = .cli_invalid_fp_eval_method, .extra = .{ .str = fp_method_str } }, &.{});
try d.comp.addDiagnostic(.{ .tag = .cli_invalid_fp_eval_method, .extra = .{ .str = fp_method_str } }, &.{});
continue;
}
d.comp.langopts.setFpEvalMethod(fp_eval_method);
@ -335,31 +336,31 @@ pub fn parseArgs(
} else if (option(arg, "--sysroot=")) |sysroot| {
d.sysroot = sysroot;
} else if (mem.eql(u8, arg, "-pedantic")) {
d.comp.diag.options.pedantic = .warning;
d.comp.diagnostics.options.pedantic = .warning;
} else if (option(arg, "--rtlib=")) |rtlib| {
if (mem.eql(u8, rtlib, "compiler-rt") or mem.eql(u8, rtlib, "libgcc") or mem.eql(u8, rtlib, "platform")) {
d.rtlib = rtlib;
} else {
try d.comp.diag.add(.{ .tag = .invalid_rtlib, .extra = .{ .str = rtlib } }, &.{});
try d.comp.addDiagnostic(.{ .tag = .invalid_rtlib, .extra = .{ .str = rtlib } }, &.{});
}
} else if (option(arg, "-Werror=")) |err_name| {
try d.comp.diag.set(err_name, .@"error");
try d.comp.diagnostics.set(err_name, .@"error");
} else if (mem.eql(u8, arg, "-Wno-fatal-errors")) {
d.comp.diag.fatal_errors = false;
d.comp.diagnostics.fatal_errors = false;
} else if (option(arg, "-Wno-")) |err_name| {
try d.comp.diag.set(err_name, .off);
try d.comp.diagnostics.set(err_name, .off);
} else if (mem.eql(u8, arg, "-Wfatal-errors")) {
d.comp.diag.fatal_errors = true;
d.comp.diagnostics.fatal_errors = true;
} else if (option(arg, "-W")) |err_name| {
try d.comp.diag.set(err_name, .warning);
try d.comp.diagnostics.set(err_name, .warning);
} else if (option(arg, "-std=")) |standard| {
d.comp.langopts.setStandard(standard) catch
try d.comp.diag.add(.{ .tag = .cli_invalid_standard, .extra = .{ .str = arg } }, &.{});
try d.comp.addDiagnostic(.{ .tag = .cli_invalid_standard, .extra = .{ .str = arg } }, &.{});
} else if (mem.eql(u8, arg, "-S") or mem.eql(u8, arg, "--assemble")) {
d.only_preprocess_and_compile = true;
} else if (option(arg, "--target=")) |triple| {
const cross = std.zig.CrossTarget.parse(.{ .arch_os_abi = triple }) catch {
try d.comp.diag.add(.{ .tag = .cli_invalid_target, .extra = .{ .str = arg } }, &.{});
try d.comp.addDiagnostic(.{ .tag = .cli_invalid_target, .extra = .{ .str = arg } }, &.{});
continue;
};
d.comp.target = cross.toTarget(); // TODO deprecated
@ -422,25 +423,20 @@ pub fn parseArgs(
break;
}
} else {
try d.comp.diag.add(.{ .tag = .invalid_unwindlib, .extra = .{ .str = unwindlib } }, &.{});
try d.comp.addDiagnostic(.{ .tag = .invalid_unwindlib, .extra = .{ .str = unwindlib } }, &.{});
}
} else {
try d.comp.diag.add(.{ .tag = .cli_unknown_arg, .extra = .{ .str = arg } }, &.{});
try d.comp.addDiagnostic(.{ .tag = .cli_unknown_arg, .extra = .{ .str = arg } }, &.{});
}
} else if (std.mem.endsWith(u8, arg, ".o") or std.mem.endsWith(u8, arg, ".obj")) {
try d.link_objects.append(d.comp.gpa, arg);
} else {
const source = d.addSource(arg) catch |er| {
return d.fatal("unable to add source file '{s}': {s}", .{ arg, util.errorDescription(er) });
return d.fatal("unable to add source file '{s}': {s}", .{ arg, errorDescription(er) });
};
try d.inputs.append(d.comp.gpa, source);
}
}
d.comp.diag.color = switch (color_setting) {
.on => true,
.off => false,
.unset => util.fileSupportsColor(std.io.getStdErr()) and !std.process.hasEnvVarConstant("NO_COLOR"),
};
if (d.comp.langopts.preserve_comments and !d.only_preprocess) {
return d.fatal("invalid argument '{s}' only allowed with '-E'", .{comment_arg});
}
@ -465,15 +461,65 @@ fn addSource(d: *Driver, path: []const u8) !Source {
}
pub fn err(d: *Driver, msg: []const u8) !void {
try d.comp.diag.add(.{ .tag = .cli_error, .extra = .{ .str = msg } }, &.{});
try d.comp.addDiagnostic(.{ .tag = .cli_error, .extra = .{ .str = msg } }, &.{});
}
pub fn fatal(d: *Driver, comptime fmt: []const u8, args: anytype) error{FatalError} {
d.comp.renderErrors();
return d.comp.diag.fatalNoSrc(fmt, args);
pub fn fatal(d: *Driver, comptime fmt: []const u8, args: anytype) error{ FatalError, OutOfMemory } {
try d.comp.diagnostics.list.append(d.comp.gpa, .{
.tag = .cli_error,
.kind = .@"fatal error",
.extra = .{ .str = try std.fmt.allocPrint(d.comp.diagnostics.arena.allocator(), fmt, args) },
});
return error.FatalError;
}
pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8) !void {
pub fn renderErrors(d: *Driver) void {
Diagnostics.render(d.comp, d.detectConfig(std.io.getStdErr()));
}
pub fn detectConfig(d: *Driver, file: std.fs.File) std.io.tty.Config {
if (d.color == true) return .escape_codes;
if (d.color == false) return .no_color;
if (file.supportsAnsiEscapeCodes()) return .escape_codes;
if (@import("builtin").os.tag == .windows and file.isTty()) {
var info: std.os.windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
if (std.os.windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != std.os.windows.TRUE) {
return .no_color;
}
return .{ .windows_api = .{
.handle = file.handle,
.reset_attributes = info.wAttributes,
} };
}
return .no_color;
}
pub fn errorDescription(e: anyerror) []const u8 {
return switch (e) {
error.OutOfMemory => "ran out of memory",
error.FileNotFound => "file not found",
error.IsDir => "is a directory",
error.NotDir => "is not a directory",
error.NotOpenForReading => "file is not open for reading",
error.NotOpenForWriting => "file is not open for writing",
error.InvalidUtf8 => "input is not valid UTF-8",
error.FileBusy => "file is busy",
error.NameTooLong => "file name is too long",
error.AccessDenied => "access denied",
error.FileTooBig => "file is too big",
error.ProcessFdQuotaExceeded, error.SystemFdQuotaExceeded => "ran out of file descriptors",
error.SystemResources => "ran out of system resources",
error.FatalError => "a fatal error occurred",
error.Unexpected => "an unexpected error occurred",
else => @errorName(e),
};
}
/// The entry point of the Aro compiler.
/// **MAY call `exit` if `fast_exit` is set.**
pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8, comptime fast_exit: bool) !void {
var macro_buf = std.ArrayList(u8).init(d.comp.gpa);
defer macro_buf.deinit();
@ -489,7 +535,7 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8) !void {
}
if (!linking) for (d.link_objects.items) |obj| {
try d.comp.diag.add(.{ .tag = .cli_unused_link_object, .extra = .{ .str = obj } }, &.{});
try d.comp.addDiagnostic(.{ .tag = .cli_unused_link_object, .extra = .{ .str = obj } }, &.{});
};
d.comp.defineSystemIncludes(d.aro_name) catch |er| switch (er) {
@ -497,15 +543,13 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8) !void {
error.AroIncludeNotFound => return d.fatal("unable to find Aro builtin headers", .{}),
};
const builtin = try d.comp.generateBuiltinMacros();
const builtin = try d.comp.generateBuiltinMacros(d.system_defines);
const user_macros = try d.comp.addSourceFromBuffer("<command line>", macro_buf.items);
const fast_exit = @import("builtin").mode != .Debug;
if (fast_exit and d.inputs.items.len == 1) {
d.processSource(tc, d.inputs.items[0], builtin, user_macros, fast_exit) catch |e| switch (e) {
error.FatalError => {
d.comp.renderErrors();
d.renderErrors();
d.exitWithCleanup(1);
},
else => |er| return er,
@ -516,12 +560,12 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8) !void {
for (d.inputs.items) |source| {
d.processSource(tc, source, builtin, user_macros, fast_exit) catch |e| switch (e) {
error.FatalError => {
d.comp.renderErrors();
d.renderErrors();
},
else => |er| return er,
};
}
if (d.comp.diag.errors != 0) {
if (d.comp.diagnostics.errors != 0) {
if (fast_exit) d.exitWithCleanup(1);
return;
}
@ -540,7 +584,7 @@ fn processSource(
comptime fast_exit: bool,
) !void {
d.comp.generated_buf.items.len = 0;
var pp = Preprocessor.init(d.comp);
var pp = try Preprocessor.initDefault(d.comp);
defer pp.deinit();
if (d.comp.langopts.ms_extensions) {
@ -554,52 +598,48 @@ fn processSource(
pp.linemarkers = if (d.use_line_directives) .line_directives else .numeric_directives;
}
}
try pp.addBuiltinMacros();
try pp.addIncludeStart(source);
try pp.addIncludeStart(builtin);
_ = try pp.preprocess(builtin);
try pp.addIncludeStart(user_macros);
_ = try pp.preprocess(user_macros);
try pp.addIncludeResume(source.id, 0, 0);
const eof = try pp.preprocess(source);
try pp.tokens.append(pp.comp.gpa, eof);
try pp.preprocessSources(&.{ source, builtin, user_macros });
if (d.only_preprocess) {
d.comp.renderErrors();
d.renderErrors();
if (d.comp.diagnostics.errors != 0) {
if (fast_exit) std.process.exit(1); // Not linking, no need for cleanup.
return;
}
const file = if (d.output_name) |some|
std.fs.cwd().createFile(some, .{}) catch |er|
return d.fatal("unable to create output file '{s}': {s}", .{ some, util.errorDescription(er) })
return d.fatal("unable to create output file '{s}': {s}", .{ some, errorDescription(er) })
else
std.io.getStdOut();
defer if (d.output_name != null) file.close();
var buf_w = std.io.bufferedWriter(file.writer());
pp.prettyPrintTokens(buf_w.writer()) catch |er|
return d.fatal("unable to write result: {s}", .{util.errorDescription(er)});
return d.fatal("unable to write result: {s}", .{errorDescription(er)});
buf_w.flush() catch |er|
return d.fatal("unable to write result: {s}", .{util.errorDescription(er)});
return d.fatal("unable to write result: {s}", .{errorDescription(er)});
if (fast_exit) std.process.exit(0); // Not linking, no need for cleanup.
return;
}
var tree = try Parser.parse(&pp);
var tree = try pp.parse();
defer tree.deinit();
if (d.verbose_ast) {
const stdout = std.io.getStdOut();
var buf_writer = std.io.bufferedWriter(stdout.writer());
const color = d.comp.diag.color and util.fileSupportsColor(stdout);
tree.dump(color, buf_writer.writer()) catch {};
tree.dump(d.detectConfig(stdout), buf_writer.writer()) catch {};
buf_writer.flush() catch {};
}
const prev_errors = d.comp.diag.errors;
d.comp.renderErrors();
const prev_errors = d.comp.diagnostics.errors;
d.renderErrors();
if (d.comp.diag.errors != prev_errors) {
if (d.comp.diagnostics.errors != prev_errors) {
if (fast_exit) d.exitWithCleanup(1);
return; // do not compile if there were errors
}
@ -616,11 +656,31 @@ fn processSource(
);
}
var ir = try tree.genIr();
defer ir.deinit(d.comp.gpa);
if (d.verbose_ir) {
try @import("CodeGen.zig").generateTree(d.comp, tree);
const stdout = std.io.getStdOut();
var buf_writer = std.io.bufferedWriter(stdout.writer());
ir.dump(d.comp.gpa, d.detectConfig(stdout), buf_writer.writer()) catch {};
buf_writer.flush() catch {};
}
const obj = try Codegen.generateTree(d.comp, tree);
var render_errors: Ir.Renderer.ErrorList = .{};
defer {
for (render_errors.values()) |msg| d.comp.gpa.free(msg);
render_errors.deinit(d.comp.gpa);
}
var obj = ir.render(d.comp.gpa, d.comp.target, &render_errors) catch |e| switch (e) {
error.OutOfMemory => return error.OutOfMemory,
error.LowerFail => {
return d.fatal(
"unable to render Ir to machine code: {s}",
.{render_errors.values()[0]},
);
},
};
defer obj.deinit();
// If it's used, name_buf will either hold a filename or `/tmp/<12 random bytes with base-64 encoding>.<extension>`
@ -653,11 +713,11 @@ fn processSource(
};
const out_file = std.fs.cwd().createFile(out_file_name, .{}) catch |er|
return d.fatal("unable to create output file '{s}': {s}", .{ out_file_name, util.errorDescription(er) });
return d.fatal("unable to create output file '{s}': {s}", .{ out_file_name, errorDescription(er) });
defer out_file.close();
obj.finish(out_file) catch |er|
return d.fatal("could not output to object file '{s}': {s}", .{ out_file_name, util.errorDescription(er) });
return d.fatal("could not output to object file '{s}': {s}", .{ out_file_name, errorDescription(er) });
if (d.only_compile) {
if (fast_exit) std.process.exit(0); // Not linking, no need for cleanup.
@ -680,6 +740,8 @@ fn dumpLinkerArgs(items: []const []const u8) !void {
try stdout.writeByte('\n');
}
/// The entry point of the Aro compiler.
/// **MAY call `exit` if `fast_exit` is set.**
pub fn invokeLinker(d: *Driver, tc: *Toolchain, comptime fast_exit: bool) !void {
try tc.discover();
@ -694,7 +756,7 @@ pub fn invokeLinker(d: *Driver, tc: *Toolchain, comptime fast_exit: bool) !void
if (d.verbose_linker_args) {
dumpLinkerArgs(argv.items) catch |er| {
return d.fatal("unable to dump linker args: {s}", .{util.errorDescription(er)});
return d.fatal("unable to dump linker args: {s}", .{errorDescription(er)});
};
}
var child = std.ChildProcess.init(argv.items, d.comp.gpa);
@ -704,11 +766,19 @@ pub fn invokeLinker(d: *Driver, tc: *Toolchain, comptime fast_exit: bool) !void
child.stderr_behavior = .Inherit;
const term = child.spawnAndWait() catch |er| {
return d.fatal("unable to spawn linker: {s}", .{util.errorDescription(er)});
return d.fatal("unable to spawn linker: {s}", .{errorDescription(er)});
};
switch (term) {
.Exited => |code| if (code != 0) d.exitWithCleanup(code),
else => std.process.abort(),
.Exited => |code| if (code != 0) {
const e = d.fatal("linker exited with an error code", .{});
if (fast_exit) d.exitWithCleanup(code);
return e;
},
else => {
const e = d.fatal("linker crashed", .{});
if (fast_exit) d.exitWithCleanup(1);
return e;
},
}
if (fast_exit) d.exitWithCleanup(0);
}

View File

@ -2,7 +2,6 @@
const std = @import("std");
const mem = std.mem;
const util = @import("../util.zig");
const Filesystem = @import("Filesystem.zig").Filesystem;
const MAX_BYTES = 1024; // TODO: Can we assume 1024 bytes enough for the info we need?

View File

@ -1,7 +1,6 @@
const std = @import("std");
const mem = std.mem;
const builtin = @import("builtin");
const system_defaults = @import("system_defaults");
const is_windows = builtin.os.tag == .windows;
fn readFileFake(entries: []const Filesystem.Entry, path: []const u8, buf: []u8) ?[]const u8 {
@ -25,7 +24,7 @@ fn findProgramByNameFake(entries: []const Filesystem.Entry, name: []const u8, pa
const path_env = path orelse return null;
var fib = std.heap.FixedBufferAllocator.init(buf);
var it = mem.tokenizeScalar(u8, path_env, system_defaults.path_sep);
var it = mem.tokenizeScalar(u8, path_env, std.fs.path.delimiter);
while (it.next()) |path_dir| {
defer fib.reset();
const full_path = std.fs.path.join(fib.allocator(), &.{ path_dir, name }) catch continue;
@ -86,7 +85,7 @@ fn findProgramByNamePosix(name: []const u8, path: ?[]const u8, buf: []u8) ?[]con
const path_env = path orelse return null;
var fib = std.heap.FixedBufferAllocator.init(buf);
var it = mem.tokenizeScalar(u8, path_env, system_defaults.path_sep);
var it = mem.tokenizeScalar(u8, path_env, std.fs.path.delimiter);
while (it.next()) |path_dir| {
defer fib.reset();
const full_path = std.fs.path.join(fib.allocator(), &.{ path_dir, name }) catch continue;
@ -122,8 +121,6 @@ pub const Filesystem = union(enum) {
base: []const u8,
i: usize = 0,
const Self = @This();
fn next(self: *@This()) !?std.fs.IterableDir.Entry {
while (self.i < self.entries.len) {
const entry = self.entries[self.i];

View File

@ -2,9 +2,9 @@ const std = @import("std");
const Toolchain = @import("../Toolchain.zig");
const target_util = @import("../target.zig");
const system_defaults = @import("system_defaults");
const util = @import("../util.zig");
const GCCVersion = @import("GCCVersion.zig");
const Multilib = @import("Multilib.zig");
const GCCDetector = @This();
is_valid: bool = false,
@ -403,13 +403,22 @@ pub fn discover(self: *GCCDetector, tc: *Toolchain) !void {
var fib = std.heap.FixedBufferAllocator.init(&path_buf);
const target = tc.getTarget();
const biarch_variant_target = if (target.ptrBitWidth() == 32) target_util.get64BitArchVariant(target) else target_util.get32BitArchVariant(target);
const biarch_variant_target = if (target.ptrBitWidth() == 32)
target_util.get64BitArchVariant(target)
else
target_util.get32BitArchVariant(target);
var candidate_lib_dirs: PathPrefixes = .{};
var candidate_biarch_lib_dirs: PathPrefixes = .{};
var candidate_triple_aliases: PathPrefixes = .{};
var candidate_biarch_lib_dirs: PathPrefixes = .{};
var candidate_biarch_triple_aliases: PathPrefixes = .{};
try collectLibDirsAndTriples(tc, &candidate_lib_dirs, &candidate_biarch_lib_dirs, &candidate_triple_aliases, &candidate_biarch_triple_aliases);
try collectLibDirsAndTriples(
tc,
&candidate_lib_dirs,
&candidate_triple_aliases,
&candidate_biarch_lib_dirs,
&candidate_biarch_triple_aliases,
);
var target_buf: [64]u8 = undefined;
const triple_str = target_util.toLLVMTriple(target, &target_buf);
@ -476,7 +485,13 @@ pub fn discover(self: *GCCDetector, tc: *Toolchain) !void {
}
}
fn findBiarchMultilibs(tc: *const Toolchain, result: *Multilib.Detected, target: std.Target, path: [2][]const u8, needs_biarch_suffix: bool) !bool {
fn findBiarchMultilibs(
tc: *const Toolchain,
result: *Multilib.Detected,
target: std.Target,
path: [2][]const u8,
needs_biarch_suffix: bool,
) !bool {
const suff64 = if (target.os.tag == .solaris) switch (target.cpu.arch) {
.x86, .x86_64 => "/amd64",
.sparc => "/sparcv9",
@ -531,7 +546,13 @@ fn findBiarchMultilibs(tc: *const Toolchain, result: *Multilib.Detected, target:
return result.select(flags);
}
fn scanGCCForMultilibs(self: *GCCDetector, tc: *const Toolchain, target: std.Target, path: [2][]const u8, needs_biarch_suffix: bool) !bool {
fn scanGCCForMultilibs(
self: *GCCDetector,
tc: *const Toolchain,
target: std.Target,
path: [2][]const u8,
needs_biarch_suffix: bool,
) !bool {
var detected: Multilib.Detected = .{};
if (target.cpu.arch == .csky) {
// TODO

View File

@ -1,5 +1,4 @@
const std = @import("std");
const util = @import("../util.zig");
const Filesystem = @import("Filesystem.zig").Filesystem;
pub const Flags = std.BoundedArray([]const u8, 6);

View File

@ -12,8 +12,6 @@ const Diagnostics = @import("Diagnostics.zig");
const NodeList = std.ArrayList(NodeIndex);
const Parser = @import("Parser.zig");
const InitList = @This();
const Item = struct {
list: InitList = .{},
index: u64,
@ -23,6 +21,8 @@ const Item = struct {
}
};
const InitList = @This();
list: std.ArrayListUnmanaged(Item) = .{},
node: NodeIndex = .none,
tok: TokenIndex = 0,

View File

@ -1,8 +1,6 @@
const std = @import("std");
const DiagnosticTag = @import("Diagnostics.zig").Tag;
const CharInfo = @import("CharInfo.zig");
const LangOpts = @This();
const char_info = @import("char_info.zig");
pub const Compiler = enum {
clang,
@ -44,19 +42,21 @@ pub const Standard = enum {
default,
/// ISO C 2017 with GNU extensions
gnu17,
/// Working Draft for ISO C2x
c2x,
/// Working Draft for ISO C2x with GNU extensions
gnu2x,
/// Working Draft for ISO C23
c23,
/// Working Draft for ISO C23 with GNU extensions
gnu23,
const NameMap = std.ComptimeStringMap(Standard, .{
.{ "c89", .c89 }, .{ "c90", .c89 }, .{ "iso9899:1990", .c89 },
.{ "iso9899:199409", .iso9899 }, .{ "gnu89", .gnu89 }, .{ "gnu90", .gnu89 },
.{ "c99", .c99 }, .{ "iso9899:1999", .c99 }, .{ "gnu99", .gnu99 },
.{ "c11", .c11 }, .{ "iso9899:2011", .c11 }, .{ "gnu11", .gnu11 },
.{ "c17", .c17 }, .{ "iso9899:2017", .c17 }, .{ "c18", .c17 },
.{ "iso9899:2018", .c17 }, .{ "gnu17", .gnu17 }, .{ "gnu18", .gnu17 },
.{ "c2x", .c2x }, .{ "gnu2x", .gnu2x },
.{ "c99", .c99 }, .{ "iso9899:1999", .c99 }, .{ "c9x", .c99 },
.{ "iso9899:199x", .c99 }, .{ "gnu99", .gnu99 }, .{ "gnu9x", .gnu99 },
.{ "c11", .c11 }, .{ "iso9899:2011", .c11 }, .{ "c1x", .c11 },
.{ "iso9899:201x", .c11 }, .{ "gnu11", .gnu11 }, .{ "c17", .c17 },
.{ "iso9899:2017", .c17 }, .{ "c18", .c17 }, .{ "iso9899:2018", .c17 },
.{ "gnu17", .gnu17 }, .{ "gnu18", .gnu17 }, .{ "c23", .c23 },
.{ "gnu23", .gnu23 }, .{ "c2x", .c23 }, .{ "gnu2x", .gnu23 },
});
pub fn atLeast(self: Standard, other: Standard) bool {
@ -65,7 +65,7 @@ pub const Standard = enum {
pub fn isGNU(standard: Standard) bool {
return switch (standard) {
.gnu89, .gnu99, .gnu11, .default, .gnu17, .gnu2x => true,
.gnu89, .gnu99, .gnu11, .default, .gnu17, .gnu23 => true,
else => false,
};
}
@ -82,26 +82,31 @@ pub const Standard = enum {
.c99, .gnu99 => "199901L",
.c11, .gnu11 => "201112L",
.default, .c17, .gnu17 => "201710L",
// todo: subject to change, verify once c23 finalized
.c2x, .gnu2x => "202311L",
.c23, .gnu23 => "202311L",
};
}
pub fn codepointAllowedInIdentifier(standard: Standard, codepoint: u21, is_start: bool) bool {
if (is_start) {
return if (standard.atLeast(.c11))
CharInfo.isC11IdChar(codepoint) and !CharInfo.isC11DisallowedInitialIdChar(codepoint)
return if (standard.atLeast(.c23))
char_info.isXidStart(codepoint)
else if (standard.atLeast(.c11))
char_info.isC11IdChar(codepoint) and !char_info.isC11DisallowedInitialIdChar(codepoint)
else
CharInfo.isC99IdChar(codepoint) and !CharInfo.isC99DisallowedInitialIDChar(codepoint);
char_info.isC99IdChar(codepoint) and !char_info.isC99DisallowedInitialIDChar(codepoint);
} else {
return if (standard.atLeast(.c11))
CharInfo.isC11IdChar(codepoint)
return if (standard.atLeast(.c23))
char_info.isXidContinue(codepoint)
else if (standard.atLeast(.c11))
char_info.isC11IdChar(codepoint)
else
CharInfo.isC99IdChar(codepoint);
char_info.isC99IdChar(codepoint);
}
}
};
const LangOpts = @This();
emulate: Compiler = .clang,
standard: Standard = .default,
/// -fshort-enums option, makes enums only take up as much space as they need to hold all the values.
@ -119,7 +124,7 @@ allow_half_args_and_returns: bool = false,
fp_eval_method: ?FPEvalMethod = null,
/// If set, use specified signedness for `char` instead of the target's default char signedness
char_signedness_override: ?std.builtin.Signedness = null,
/// If set, override the default availability of char8_t (by default, enabled in C2X and later; disabled otherwise)
/// If set, override the default availability of char8_t (by default, enabled in C23 and later; disabled otherwise)
has_char8_t_override: ?bool = null,
/// Whether to allow GNU-style inline assembly
@ -145,7 +150,7 @@ pub fn disableMSExtensions(self: *LangOpts) void {
}
pub fn hasChar8_T(self: *const LangOpts) bool {
return self.has_char8_t_override orelse self.standard.atLeast(.c2x);
return self.has_char8_t_override orelse self.standard.atLeast(.c23);
}
pub fn hasDigraphs(self: *const LangOpts) bool {

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,10 @@ const Preprocessor = @import("Preprocessor.zig");
const Parser = @import("Parser.zig");
const TokenIndex = @import("Tree.zig").TokenIndex;
const Pragma = @This();
pub const Error = Compilation.Error || error{ UnknownPragma, StopPreprocessing };
const Pragma = @This();
/// Called during Preprocessor.init
beforePreprocess: ?*const fn (*Pragma, *Compilation) void = null,

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
const std = @import("std");
const Source = @This();
pub const Id = enum(u32) {
unused = 0,
@ -27,6 +26,8 @@ pub const Location = struct {
}
};
const Source = @This();
path: []const u8,
buf: []const u8,
id: Id,

View File

@ -1,7 +1,6 @@
const std = @import("std");
const mem = std.mem;
const StringInterner = @This();
const Compilation = @import("Compilation.zig");
const StringToIdMap = std.StringHashMapUnmanaged(StringId);
@ -43,6 +42,8 @@ pub const TypeMapper = struct {
}
};
const StringInterner = @This();
string_table: StringToIdMap = .{},
next_id: StringId = @enumFromInt(@intFromEnum(StringId.empty) + 1),
@ -50,7 +51,11 @@ pub fn deinit(self: *StringInterner, allocator: mem.Allocator) void {
self.string_table.deinit(allocator);
}
pub fn intern(self: *StringInterner, allocator: mem.Allocator, str: []const u8) !StringId {
pub fn intern(comp: *Compilation, str: []const u8) !StringId {
return comp.string_interner.internExtra(comp.gpa, str);
}
pub fn internExtra(self: *StringInterner, allocator: mem.Allocator, str: []const u8) !StringId {
if (str.len == 0) return .empty;
const gop = try self.string_table.getOrPut(allocator, str);

View File

@ -11,8 +11,6 @@ const Parser = @import("Parser.zig");
const Value = @import("Value.zig");
const StringId = @import("StringInterner.zig").StringId;
const SymbolStack = @This();
pub const Symbol = struct {
name: StringId,
ty: Type,
@ -33,6 +31,8 @@ pub const Kind = enum {
constexpr,
};
const SymbolStack = @This();
syms: std.MultiArrayList(Symbol) = .{},
scopes: std.ArrayListUnmanaged(u32) = .{},

View File

@ -4,8 +4,6 @@ const Compilation = @import("Compilation.zig");
const Source = @import("Source.zig");
const LangOpts = @import("LangOpts.zig");
const Tokenizer = @This();
pub const Token = struct {
id: Id,
source: Source.Id,
@ -121,6 +119,8 @@ pub const Token = struct {
macro_ws,
/// Special token for implementing __has_attribute
macro_param_has_attribute,
/// Special token for implementing __has_c_attribute
macro_param_has_c_attribute,
/// Special token for implementing __has_declspec_attribute
macro_param_has_declspec_attribute,
/// Special token for implementing __has_warning
@ -135,6 +135,8 @@ pub const Token = struct {
macro_param_has_include,
/// Special token for implementing __has_include_next
macro_param_has_include_next,
/// Special token for implementing __has_embed
macro_param_has_embed,
/// Special token for implementing __is_identifier
macro_param_is_identifier,
/// Special token for implementing __FILE__
@ -216,6 +218,7 @@ pub const Token = struct {
keyword_true,
keyword_false,
keyword_nullptr,
keyword_typeof_unqual,
// Preprocessor directives
keyword_include,
@ -235,6 +238,7 @@ pub const Token = struct {
keyword_pragma,
keyword_line,
keyword_va_args,
keyword_va_opt,
// gcc keywords
keyword_const1,
@ -255,7 +259,10 @@ pub const Token = struct {
keyword_asm1,
keyword_asm2,
keyword_float80,
keyword_float128,
/// _Float128
keyword_float128_1,
/// __float128
keyword_float128_2,
keyword_int128,
keyword_imag1,
keyword_imag2,
@ -335,6 +342,7 @@ pub const Token = struct {
.keyword_pragma,
.keyword_line,
.keyword_va_args,
.keyword_va_opt,
.macro_func,
.macro_function,
.macro_pretty_func,
@ -410,7 +418,8 @@ pub const Token = struct {
.keyword_asm1,
.keyword_asm2,
.keyword_float80,
.keyword_float128,
.keyword_float128_1,
.keyword_float128_2,
.keyword_int128,
.keyword_imag1,
.keyword_imag2,
@ -443,6 +452,7 @@ pub const Token = struct {
.keyword_true,
.keyword_false,
.keyword_nullptr,
.keyword_typeof_unqual,
=> return true,
else => return false,
}
@ -469,6 +479,7 @@ pub const Token = struct {
.keyword_pragma,
.keyword_line,
.keyword_va_args,
.keyword_va_opt,
=> id.* = .identifier,
.keyword_defined => if (defined_to_identifier) {
id.* = .identifier;
@ -485,9 +496,9 @@ pub const Token = struct {
return switch (id) {
.include_start,
.include_resume,
.unterminated_comment, // Fatal error; parsing should not be attempted
=> unreachable,
.unterminated_comment,
.invalid,
.identifier,
.extended_identifier,
@ -521,6 +532,7 @@ pub const Token = struct {
.stringify_param,
.stringify_va_args,
.macro_param_has_attribute,
.macro_param_has_c_attribute,
.macro_param_has_declspec_attribute,
.macro_param_has_warning,
.macro_param_has_feature,
@ -528,6 +540,7 @@ pub const Token = struct {
.macro_param_has_builtin,
.macro_param_has_include,
.macro_param_has_include_next,
.macro_param_has_embed,
.macro_param_is_identifier,
.macro_file,
.macro_line,
@ -647,6 +660,7 @@ pub const Token = struct {
.keyword_true => "true",
.keyword_false => "false",
.keyword_nullptr => "nullptr",
.keyword_typeof_unqual => "typeof_unqual",
.keyword_include => "include",
.keyword_include_next => "include_next",
.keyword_embed => "embed",
@ -664,6 +678,7 @@ pub const Token = struct {
.keyword_pragma => "pragma",
.keyword_line => "line",
.keyword_va_args => "__VA_ARGS__",
.keyword_va_opt => "__VA_OPT__",
.keyword_const1 => "__const",
.keyword_const2 => "__const__",
.keyword_inline1 => "__inline",
@ -688,7 +703,8 @@ pub const Token = struct {
.keyword_asm1 => "__asm",
.keyword_asm2 => "__asm__",
.keyword_float80 => "__float80",
.keyword_float128 => "__float18",
.keyword_float128_1 => "_Float128",
.keyword_float128_2 => "__float128",
.keyword_int128 => "__int128",
.keyword_imag1 => "__imag",
.keyword_imag2 => "__imag__",
@ -819,7 +835,7 @@ pub const Token = struct {
return switch (kw) {
.keyword_inline => if (standard.isGNU() or standard.atLeast(.c99)) kw else .identifier,
.keyword_restrict => if (standard.atLeast(.c99)) kw else .identifier,
.keyword_typeof => if (standard.isGNU() or standard.atLeast(.c2x)) kw else .identifier,
.keyword_typeof => if (standard.isGNU() or standard.atLeast(.c23)) kw else .identifier,
.keyword_asm => if (standard.isGNU()) kw else .identifier,
.keyword_declspec => if (comp.langopts.declspec_attrs) kw else .identifier,
@ -832,9 +848,10 @@ pub const Token = struct {
.keyword_true,
.keyword_false,
.keyword_nullptr,
.keyword_typeof_unqual,
.keyword_elifdef,
.keyword_elifndef,
=> if (standard.atLeast(.c2x)) kw else .identifier,
=> if (standard.atLeast(.c23)) kw else .identifier,
.keyword_int64,
.keyword_int64_2,
@ -918,6 +935,7 @@ pub const Token = struct {
.{ "true", .keyword_true },
.{ "false", .keyword_false },
.{ "nullptr", .keyword_nullptr },
.{ "typeof_unqual", .keyword_typeof_unqual },
// Preprocessor directives
.{ "include", .keyword_include },
@ -937,6 +955,7 @@ pub const Token = struct {
.{ "pragma", .keyword_pragma },
.{ "line", .keyword_line },
.{ "__VA_ARGS__", .keyword_va_args },
.{ "__VA_OPT__", .keyword_va_opt },
.{ "__func__", .macro_func },
.{ "__FUNCTION__", .macro_function },
.{ "__PRETTY_FUNCTION__", .macro_pretty_func },
@ -961,7 +980,8 @@ pub const Token = struct {
.{ "__asm", .keyword_asm1 },
.{ "__asm__", .keyword_asm2 },
.{ "__float80", .keyword_float80 },
.{ "__float128", .keyword_float128 },
.{ "_Float128", .keyword_float128_1 },
.{ "__float128", .keyword_float128_2 },
.{ "__int128", .keyword_int128 },
.{ "__imag", .keyword_imag1 },
.{ "__imag__", .keyword_imag2 },
@ -998,6 +1018,8 @@ pub const Token = struct {
});
};
const Tokenizer = @This();
buf: []const u8,
index: u32 = 0,
source: Source.Id,
@ -1345,7 +1367,7 @@ pub fn next(self: *Tokenizer) Token {
break;
},
':' => {
if (self.comp.langopts.standard.atLeast(.c2x)) {
if (self.comp.langopts.standard.atLeast(.c23)) {
id = .colon_colon;
self.index += 1;
break;
@ -1651,7 +1673,7 @@ pub fn next(self: *Tokenizer) Token {
'.',
=> {},
'e', 'E', 'p', 'P' => state = .pp_num_exponent,
'\'' => if (self.comp.langopts.standard.atLeast(.c2x)) {
'\'' => if (self.comp.langopts.standard.atLeast(.c23)) {
state = .pp_num_digit_separator;
} else {
id = .pp_num;
@ -1679,14 +1701,17 @@ pub fn next(self: *Tokenizer) Token {
},
},
.pp_num_exponent => switch (c) {
'a'...'z',
'A'...'Z',
'a'...'o',
'q'...'z',
'A'...'O',
'Q'...'Z',
'0'...'9',
'_',
'.',
'+',
'-',
=> state = .pp_num,
'p', 'P' => {},
else => {
id = .pp_num;
break;
@ -1761,6 +1786,16 @@ pub fn nextNoWSComments(self: *Tokenizer) Token {
return tok;
}
/// Try to tokenize a '::' even if not supported by the current language standard.
pub fn colonColon(self: *Tokenizer) Token {
var tok = self.nextNoWS();
if (tok.id == .colon and self.buf[self.index] == ':') {
self.index += 1;
tok.id = .colon_colon;
}
return tok;
}
test "operators" {
try expectTokens(
\\ ! != | || |= = ==
@ -2091,7 +2126,7 @@ test "digraphs" {
}
test "C23 keywords" {
try expectTokensExtra("true false alignas alignof bool static_assert thread_local nullptr", &.{
try expectTokensExtra("true false alignas alignof bool static_assert thread_local nullptr typeof_unqual", &.{
.keyword_true,
.keyword_false,
.keyword_c23_alignas,
@ -2100,7 +2135,8 @@ test "C23 keywords" {
.keyword_c23_static_assert,
.keyword_c23_thread_local,
.keyword_nullptr,
}, .c2x);
.keyword_typeof_unqual,
}, .c23);
}
fn expectTokensExtra(contents: []const u8, expected_tokens: []const Token.Id, standard: ?LangOpts.Standard) !void {

View File

@ -1,7 +1,6 @@
const std = @import("std");
const Driver = @import("Driver.zig");
const Compilation = @import("Compilation.zig");
const util = @import("util.zig");
const mem = std.mem;
const system_defaults = @import("system_defaults");
const target_util = @import("target.zig");
@ -9,8 +8,6 @@ const Linux = @import("toolchains/Linux.zig");
const Multilib = @import("Driver/Multilib.zig");
const Filesystem = @import("Driver/Filesystem.zig").Filesystem;
const Toolchain = @This();
pub const PathList = std.ArrayListUnmanaged([]const u8);
pub const RuntimeLibKind = enum {
@ -49,6 +46,8 @@ const Inner = union(enum) {
}
};
const Toolchain = @This();
filesystem: Filesystem = .{ .real = {} },
driver: *Driver,
arena: mem.Allocator,
@ -152,7 +151,7 @@ pub fn getLinkerPath(tc: *const Toolchain, buf: []u8) ![]const u8 {
// to a relative path is surprising. This is more complex due to priorities
// among -B, COMPILER_PATH and PATH. --ld-path= should be used instead.
if (mem.indexOfScalar(u8, use_linker, '/') != null) {
try tc.driver.comp.diag.add(.{ .tag = .fuse_ld_path }, &.{});
try tc.driver.comp.addDiagnostic(.{ .tag = .fuse_ld_path }, &.{});
}
if (std.fs.path.isAbsolute(use_linker)) {
@ -402,7 +401,7 @@ fn getUnwindLibKind(tc: *const Toolchain) !UnwindLibKind {
return .libgcc;
} else if (mem.eql(u8, libname, "libunwind")) {
if (tc.getRuntimeLibKind() == .libgcc) {
try tc.driver.comp.diag.add(.{ .tag = .incompatible_unwindlib }, &.{});
try tc.driver.comp.addDiagnostic(.{ .tag = .incompatible_unwindlib }, &.{});
}
return .compiler_rt;
} else {
@ -479,7 +478,7 @@ pub fn addRuntimeLibs(tc: *const Toolchain, argv: *std.ArrayList([]const u8)) !v
if (target_util.isKnownWindowsMSVCEnvironment(target)) {
const rtlib_str = tc.driver.rtlib orelse system_defaults.rtlib;
if (!mem.eql(u8, rtlib_str, "platform")) {
try tc.driver.comp.diag.add(.{ .tag = .unsupported_rtlib_gcc, .extra = .{ .str = "MSVC" } }, &.{});
try tc.driver.comp.addDiagnostic(.{ .tag = .unsupported_rtlib_gcc, .extra = .{ .str = "MSVC" } }, &.{});
}
} else {
try tc.addLibGCC(argv);

View File

@ -1,14 +1,14 @@
const std = @import("std");
const Interner = @import("backend").Interner;
const Type = @import("Type.zig");
const Tokenizer = @import("Tokenizer.zig");
const CodeGen = @import("CodeGen.zig");
const Compilation = @import("Compilation.zig");
const Source = @import("Source.zig");
const Attribute = @import("Attribute.zig");
const Value = @import("Value.zig");
const StringInterner = @import("StringInterner.zig");
const Tree = @This();
pub const Token = struct {
id: Id,
flags: packed struct {
@ -79,7 +79,7 @@ pub const Token = struct {
pub fn checkMsEof(tok: Token, source: Source, comp: *Compilation) !void {
std.debug.assert(tok.id == .eof);
if (source.buf.len > tok.loc.byte_offset and source.buf[tok.loc.byte_offset] == 0x1A) {
try comp.diag.add(.{
try comp.addDiagnostic(.{
.tag = .ctrl_z_eof,
.loc = .{
.id = source.id,
@ -98,6 +98,8 @@ pub const TokenIndex = u32;
pub const NodeIndex = enum(u32) { none, _ };
pub const ValueMap = std.AutoHashMap(NodeIndex, Value);
const Tree = @This();
comp: *Compilation,
arena: std.heap.ArenaAllocator,
generated: []const u8,
@ -105,13 +107,13 @@ tokens: Token.List.Slice,
nodes: Node.List.Slice,
data: []const NodeIndex,
root_decls: []const NodeIndex,
strings: []const u8,
value_map: ValueMap,
pub const genIr = CodeGen.genIr;
pub fn deinit(tree: *Tree) void {
tree.comp.gpa.free(tree.root_decls);
tree.comp.gpa.free(tree.data);
tree.comp.gpa.free(tree.strings);
tree.nodes.deinit(tree.comp.gpa);
tree.arena.deinit();
tree.value_map.deinit();
@ -161,7 +163,7 @@ pub const Node = struct {
int: u64,
return_zero: bool,
pub fn forDecl(data: Data, tree: Tree) struct {
pub fn forDecl(data: Data, tree: *const Tree) struct {
decls: []const NodeIndex,
cond: NodeIndex,
incr: NodeIndex,
@ -178,7 +180,7 @@ pub const Node = struct {
};
}
pub fn forStmt(data: Data, tree: Tree) struct {
pub fn forStmt(data: Data, tree: *const Tree) struct {
init: NodeIndex,
cond: NodeIndex,
incr: NodeIndex,
@ -495,12 +497,8 @@ pub const Tag = enum(u8) {
int_literal,
/// Same as int_literal, but originates from a char literal
char_literal,
/// _Float16 literal
float16_literal,
/// f32 literal
/// a floating point literal
float_literal,
/// f64 literal
double_literal,
/// wraps a float or double literal: un
imaginary_literal,
/// tree.str[index..][0..len]
@ -540,6 +538,12 @@ pub const Tag = enum(u8) {
union_init_expr,
/// (ty){ un }
compound_literal_expr,
/// (static ty){ un }
static_compound_literal_expr,
/// (thread_local ty){ un }
thread_local_compound_literal_expr,
/// (static thread_local ty){ un }
static_thread_local_compound_literal_expr,
/// Inserted at the end of a function body if no return stmt is found.
/// ty is the functions return type
@ -566,18 +570,18 @@ pub const Tag = enum(u8) {
}
};
pub fn isBitfield(nodes: Node.List.Slice, node: NodeIndex) bool {
return bitfieldWidth(nodes, node, false) != null;
pub fn isBitfield(tree: *const Tree, node: NodeIndex) bool {
return tree.bitfieldWidth(node, false) != null;
}
/// Returns null if node is not a bitfield. If inspect_lval is true, this function will
/// recurse into implicit lval_to_rval casts (useful for arithmetic conversions)
pub fn bitfieldWidth(nodes: Node.List.Slice, node: NodeIndex, inspect_lval: bool) ?u32 {
pub fn bitfieldWidth(tree: *const Tree, node: NodeIndex, inspect_lval: bool) ?u32 {
if (node == .none) return null;
switch (nodes.items(.tag)[@intFromEnum(node)]) {
switch (tree.nodes.items(.tag)[@intFromEnum(node)]) {
.member_access_expr, .member_access_ptr_expr => {
const member = nodes.items(.data)[@intFromEnum(node)].member;
var ty = nodes.items(.ty)[@intFromEnum(member.lhs)];
const member = tree.nodes.items(.data)[@intFromEnum(node)].member;
var ty = tree.nodes.items(.ty)[@intFromEnum(member.lhs)];
if (ty.isPtr()) ty = ty.elemType();
const record_ty = ty.get(.@"struct") orelse ty.get(.@"union") orelse return null;
const field = record_ty.data.record.fields[member.index];
@ -586,9 +590,9 @@ pub fn bitfieldWidth(nodes: Node.List.Slice, node: NodeIndex, inspect_lval: bool
.implicit_cast => {
if (!inspect_lval) return null;
const data = nodes.items(.data)[@intFromEnum(node)];
const data = tree.nodes.items(.data)[@intFromEnum(node)];
return switch (data.cast.kind) {
.lval_to_rval => bitfieldWidth(nodes, data.cast.operand, false),
.lval_to_rval => tree.bitfieldWidth(data.cast.operand, false),
else => null,
};
},
@ -596,59 +600,63 @@ pub fn bitfieldWidth(nodes: Node.List.Slice, node: NodeIndex, inspect_lval: bool
}
}
pub fn isLval(nodes: Node.List.Slice, extra: []const NodeIndex, value_map: ValueMap, node: NodeIndex) bool {
pub fn isLval(tree: *const Tree, node: NodeIndex) bool {
var is_const: bool = undefined;
return isLvalExtra(nodes, extra, value_map, node, &is_const);
return tree.isLvalExtra(node, &is_const);
}
pub fn isLvalExtra(nodes: Node.List.Slice, extra: []const NodeIndex, value_map: ValueMap, node: NodeIndex, is_const: *bool) bool {
pub fn isLvalExtra(tree: *const Tree, node: NodeIndex, is_const: *bool) bool {
is_const.* = false;
switch (nodes.items(.tag)[@intFromEnum(node)]) {
.compound_literal_expr => {
is_const.* = nodes.items(.ty)[@intFromEnum(node)].isConst();
switch (tree.nodes.items(.tag)[@intFromEnum(node)]) {
.compound_literal_expr,
.static_compound_literal_expr,
.thread_local_compound_literal_expr,
.static_thread_local_compound_literal_expr,
=> {
is_const.* = tree.nodes.items(.ty)[@intFromEnum(node)].isConst();
return true;
},
.string_literal_expr => return true,
.member_access_ptr_expr => {
const lhs_expr = nodes.items(.data)[@intFromEnum(node)].member.lhs;
const ptr_ty = nodes.items(.ty)[@intFromEnum(lhs_expr)];
const lhs_expr = tree.nodes.items(.data)[@intFromEnum(node)].member.lhs;
const ptr_ty = tree.nodes.items(.ty)[@intFromEnum(lhs_expr)];
if (ptr_ty.isPtr()) is_const.* = ptr_ty.elemType().isConst();
return true;
},
.array_access_expr => {
const lhs_expr = nodes.items(.data)[@intFromEnum(node)].bin.lhs;
const lhs_expr = tree.nodes.items(.data)[@intFromEnum(node)].bin.lhs;
if (lhs_expr != .none) {
const array_ty = nodes.items(.ty)[@intFromEnum(lhs_expr)];
const array_ty = tree.nodes.items(.ty)[@intFromEnum(lhs_expr)];
if (array_ty.isPtr() or array_ty.isArray()) is_const.* = array_ty.elemType().isConst();
}
return true;
},
.decl_ref_expr => {
const decl_ty = nodes.items(.ty)[@intFromEnum(node)];
const decl_ty = tree.nodes.items(.ty)[@intFromEnum(node)];
is_const.* = decl_ty.isConst();
return true;
},
.deref_expr => {
const data = nodes.items(.data)[@intFromEnum(node)];
const operand_ty = nodes.items(.ty)[@intFromEnum(data.un)];
const data = tree.nodes.items(.data)[@intFromEnum(node)];
const operand_ty = tree.nodes.items(.ty)[@intFromEnum(data.un)];
if (operand_ty.isFunc()) return false;
if (operand_ty.isPtr() or operand_ty.isArray()) is_const.* = operand_ty.elemType().isConst();
return true;
},
.member_access_expr => {
const data = nodes.items(.data)[@intFromEnum(node)];
return isLvalExtra(nodes, extra, value_map, data.member.lhs, is_const);
const data = tree.nodes.items(.data)[@intFromEnum(node)];
return tree.isLvalExtra(data.member.lhs, is_const);
},
.paren_expr => {
const data = nodes.items(.data)[@intFromEnum(node)];
return isLvalExtra(nodes, extra, value_map, data.un, is_const);
const data = tree.nodes.items(.data)[@intFromEnum(node)];
return tree.isLvalExtra(data.un, is_const);
},
.builtin_choose_expr => {
const data = nodes.items(.data)[@intFromEnum(node)];
const data = tree.nodes.items(.data)[@intFromEnum(node)];
if (value_map.get(data.if3.cond)) |val| {
const offset = @intFromBool(val.isZero());
return isLvalExtra(nodes, extra, value_map, extra[data.if3.body + offset], is_const);
if (tree.value_map.get(data.if3.cond)) |val| {
const offset = @intFromBool(val.isZero(tree.comp));
return tree.isLvalExtra(tree.data[data.if3.body + offset], is_const);
}
return false;
},
@ -656,7 +664,7 @@ pub fn isLvalExtra(nodes: Node.List.Slice, extra: []const NodeIndex, value_map:
}
}
pub fn tokSlice(tree: Tree, tok_i: TokenIndex) []const u8 {
pub fn tokSlice(tree: *const Tree, tok_i: TokenIndex) []const u8 {
if (tree.tokens.items(.id)[tok_i].lexeme()) |some| return some;
const loc = tree.tokens.items(.loc)[tok_i];
var tmp_tokenizer = Tokenizer{
@ -669,25 +677,25 @@ pub fn tokSlice(tree: Tree, tok_i: TokenIndex) []const u8 {
return tmp_tokenizer.buf[tok.start..tok.end];
}
pub fn dump(tree: Tree, color: bool, writer: anytype) @TypeOf(writer).Error!void {
pub fn dump(tree: *const Tree, config: std.io.tty.Config, writer: anytype) !void {
const mapper = tree.comp.string_interner.getFastTypeMapper(tree.comp.gpa) catch tree.comp.string_interner.getSlowTypeMapper();
defer mapper.deinit(tree.comp.gpa);
for (tree.root_decls) |i| {
try tree.dumpNode(i, 0, mapper, color, writer);
try tree.dumpNode(i, 0, mapper, config, writer);
try writer.writeByte('\n');
}
}
fn dumpFieldAttributes(attributes: []const Attribute, level: u32, strings: []const u8, writer: anytype) !void {
fn dumpFieldAttributes(tree: *const Tree, attributes: []const Attribute, level: u32, writer: anytype) !void {
for (attributes) |attr| {
try writer.writeByteNTimes(' ', level);
try writer.print("field attr: {s}", .{@tagName(attr.tag)});
try dumpAttribute(attr, strings, writer);
try tree.dumpAttribute(attr, writer);
}
}
fn dumpAttribute(attr: Attribute, strings: []const u8, writer: anytype) !void {
fn dumpAttribute(tree: *const Tree, attr: Attribute, writer: anytype) !void {
switch (attr.tag) {
inline else => |tag| {
const args = @field(attr.args, @tagName(tag));
@ -705,8 +713,8 @@ fn dumpAttribute(attr: Attribute, strings: []const u8, writer: anytype) !void {
try writer.writeAll(f.name);
try writer.writeAll(": ");
switch (f.type) {
Value.ByteRange => try writer.print("\"{s}\"", .{@field(args, f.name).slice(strings, .@"1")}),
?Value.ByteRange => try writer.print("\"{?s}\"", .{if (@field(args, f.name)) |range| range.slice(strings, .@"1") else null}),
Interner.Ref => try writer.print("\"{s}\"", .{tree.interner.get(@field(args, f.name)).bytes}),
?Interner.Ref => try writer.print("\"{?s}\"", .{if (@field(args, f.name)) |str| tree.interner.get(str).bytes else null}),
else => switch (@typeInfo(f.type)) {
.Enum => try writer.writeAll(@tagName(@field(args, f.name))),
else => try writer.print("{any}", .{@field(args, f.name)}),
@ -719,16 +727,22 @@ fn dumpAttribute(attr: Attribute, strings: []const u8, writer: anytype) !void {
}
}
fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.TypeMapper, color: bool, w: anytype) @TypeOf(w).Error!void {
fn dumpNode(
tree: *const Tree,
node: NodeIndex,
level: u32,
mapper: StringInterner.TypeMapper,
config: std.io.tty.Config,
w: anytype,
) !void {
const delta = 2;
const half = delta / 2;
const util = @import("util.zig");
const TYPE = util.Color.purple;
const TAG = util.Color.cyan;
const IMPLICIT = util.Color.blue;
const NAME = util.Color.red;
const LITERAL = util.Color.green;
const ATTRIBUTE = util.Color.yellow;
const TYPE = std.io.tty.Color.bright_magenta;
const TAG = std.io.tty.Color.bright_cyan;
const IMPLICIT = std.io.tty.Color.bright_blue;
const NAME = std.io.tty.Color.bright_red;
const LITERAL = std.io.tty.Color.bright_green;
const ATTRIBUTE = std.io.tty.Color.bright_yellow;
std.debug.assert(node != .none);
const tag = tree.nodes.items(.tag)[@intFromEnum(node)];
@ -736,68 +750,68 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
const ty = tree.nodes.items(.ty)[@intFromEnum(node)];
try w.writeByteNTimes(' ', level);
if (color) util.setColor(if (tag.isImplicit()) IMPLICIT else TAG, w);
try config.setColor(w, if (tag.isImplicit()) IMPLICIT else TAG);
try w.print("{s}: ", .{@tagName(tag)});
if (tag == .implicit_cast or tag == .explicit_cast) {
if (color) util.setColor(.white, w);
try config.setColor(w, .white);
try w.print("({s}) ", .{@tagName(data.cast.kind)});
}
if (color) util.setColor(TYPE, w);
try config.setColor(w, TYPE);
try w.writeByte('\'');
try ty.dump(mapper, tree.comp.langopts, w);
try w.writeByte('\'');
if (isLval(tree.nodes, tree.data, tree.value_map, node)) {
if (color) util.setColor(ATTRIBUTE, w);
if (tree.isLval(node)) {
try config.setColor(w, ATTRIBUTE);
try w.writeAll(" lvalue");
}
if (isBitfield(tree.nodes, node)) {
if (color) util.setColor(ATTRIBUTE, w);
if (tree.isBitfield(node)) {
try config.setColor(w, ATTRIBUTE);
try w.writeAll(" bitfield");
}
if (tree.value_map.get(node)) |val| {
if (color) util.setColor(LITERAL, w);
try config.setColor(w, LITERAL);
try w.writeAll(" (value: ");
try val.dump(ty, tree.comp, tree.strings, w);
try val.print(ty, tree.comp, w);
try w.writeByte(')');
}
if (tag == .implicit_return and data.return_zero) {
if (color) util.setColor(IMPLICIT, w);
try config.setColor(w, IMPLICIT);
try w.writeAll(" (value: 0)");
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
}
try w.writeAll("\n");
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
if (ty.specifier == .attributed) {
if (color) util.setColor(ATTRIBUTE, w);
try config.setColor(w, ATTRIBUTE);
for (ty.data.attributed.attributes) |attr| {
try w.writeByteNTimes(' ', level + half);
try w.print("attr: {s}", .{@tagName(attr.tag)});
try dumpAttribute(attr, tree.strings, w);
try tree.dumpAttribute(attr, w);
}
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
}
switch (tag) {
.invalid => unreachable,
.file_scope_asm => {
try w.writeByteNTimes(' ', level + 1);
try tree.dumpNode(data.decl.node, level + delta, mapper, color, w);
try tree.dumpNode(data.decl.node, level + delta, mapper, config, w);
},
.gnu_asm_simple => {
try w.writeByteNTimes(' ', level);
try tree.dumpNode(data.un, level, mapper, color, w);
try tree.dumpNode(data.un, level, mapper, config, w);
},
.static_assert => {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("condition:\n");
try tree.dumpNode(data.bin.lhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
if (data.bin.rhs != .none) {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("diagnostic:\n");
try tree.dumpNode(data.bin.rhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
}
},
.fn_proto,
@ -807,9 +821,9 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
=> {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{tree.tokSlice(data.decl.name)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
},
.fn_def,
.static_fn_def,
@ -818,12 +832,12 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
=> {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{tree.tokSlice(data.decl.name)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
try w.writeByteNTimes(' ', level + half);
try w.writeAll("body:\n");
try tree.dumpNode(data.decl.node, level + delta, mapper, color, w);
try tree.dumpNode(data.decl.node, level + delta, mapper, config, w);
},
.typedef,
.@"var",
@ -836,39 +850,39 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
=> {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{tree.tokSlice(data.decl.name)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
if (data.decl.node != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("init:\n");
try tree.dumpNode(data.decl.node, level + delta, mapper, color, w);
try tree.dumpNode(data.decl.node, level + delta, mapper, config, w);
}
},
.enum_field_decl => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{tree.tokSlice(data.decl.name)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
if (data.decl.node != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("value:\n");
try tree.dumpNode(data.decl.node, level + delta, mapper, color, w);
try tree.dumpNode(data.decl.node, level + delta, mapper, config, w);
}
},
.record_field_decl => {
if (data.decl.name != 0) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{tree.tokSlice(data.decl.name)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
}
if (data.decl.node != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("bits:\n");
try tree.dumpNode(data.decl.node, level + delta, mapper, color, w);
try tree.dumpNode(data.decl.node, level + delta, mapper, config, w);
}
},
.indirect_record_field_decl => {},
@ -882,13 +896,13 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
const maybe_field_attributes = if (ty.getRecord()) |record| record.field_attributes else null;
for (tree.data[data.range.start..data.range.end], 0..) |stmt, i| {
if (i != 0) try w.writeByte('\n');
try tree.dumpNode(stmt, level + delta, mapper, color, w);
try tree.dumpNode(stmt, level + delta, mapper, config, w);
if (maybe_field_attributes) |field_attributes| {
if (field_attributes[i].len == 0) continue;
if (color) util.setColor(ATTRIBUTE, w);
try dumpFieldAttributes(field_attributes[i], level + delta + half, tree.strings, w);
if (color) util.setColor(.reset, w);
try config.setColor(w, ATTRIBUTE);
try tree.dumpFieldAttributes(field_attributes[i], level + delta + half, w);
try config.setColor(w, .reset);
}
}
},
@ -903,91 +917,95 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
const empty: [][]const Attribute = &attr_array;
const field_attributes = if (ty.getRecord()) |record| (record.field_attributes orelse empty.ptr) else empty.ptr;
if (data.bin.lhs != .none) {
try tree.dumpNode(data.bin.lhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
if (field_attributes[0].len > 0) {
if (color) util.setColor(ATTRIBUTE, w);
try dumpFieldAttributes(field_attributes[0], level + delta + half, tree.strings, w);
if (color) util.setColor(.reset, w);
try config.setColor(w, ATTRIBUTE);
try tree.dumpFieldAttributes(field_attributes[0], level + delta + half, w);
try config.setColor(w, .reset);
}
}
if (data.bin.rhs != .none) {
try tree.dumpNode(data.bin.rhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
if (field_attributes[1].len > 0) {
if (color) util.setColor(ATTRIBUTE, w);
try dumpFieldAttributes(field_attributes[1], level + delta + half, tree.strings, w);
if (color) util.setColor(.reset, w);
try config.setColor(w, ATTRIBUTE);
try tree.dumpFieldAttributes(field_attributes[1], level + delta + half, w);
try config.setColor(w, .reset);
}
}
},
.union_init_expr => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("field index: ");
if (color) util.setColor(LITERAL, w);
try config.setColor(w, LITERAL);
try w.print("{d}\n", .{data.union_init.field_index});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
if (data.union_init.node != .none) {
try tree.dumpNode(data.union_init.node, level + delta, mapper, color, w);
try tree.dumpNode(data.union_init.node, level + delta, mapper, config, w);
}
},
.compound_literal_expr => {
try tree.dumpNode(data.un, level + half, mapper, color, w);
.compound_literal_expr,
.static_compound_literal_expr,
.thread_local_compound_literal_expr,
.static_thread_local_compound_literal_expr,
=> {
try tree.dumpNode(data.un, level + half, mapper, config, w);
},
.labeled_stmt => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("label: ");
if (color) util.setColor(LITERAL, w);
try config.setColor(w, LITERAL);
try w.print("{s}\n", .{tree.tokSlice(data.decl.name)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
if (data.decl.node != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("stmt:\n");
try tree.dumpNode(data.decl.node, level + delta, mapper, color, w);
try tree.dumpNode(data.decl.node, level + delta, mapper, config, w);
}
},
.case_stmt => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("value:\n");
try tree.dumpNode(data.bin.lhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
if (data.bin.rhs != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("stmt:\n");
try tree.dumpNode(data.bin.rhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
}
},
.case_range_stmt => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("range start:\n");
try tree.dumpNode(tree.data[data.if3.body], level + delta, mapper, color, w);
try tree.dumpNode(tree.data[data.if3.body], level + delta, mapper, config, w);
try w.writeByteNTimes(' ', level + half);
try w.writeAll("range end:\n");
try tree.dumpNode(tree.data[data.if3.body + 1], level + delta, mapper, color, w);
try tree.dumpNode(tree.data[data.if3.body + 1], level + delta, mapper, config, w);
if (data.if3.cond != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("stmt:\n");
try tree.dumpNode(data.if3.cond, level + delta, mapper, color, w);
try tree.dumpNode(data.if3.cond, level + delta, mapper, config, w);
}
},
.default_stmt => {
if (data.un != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("stmt:\n");
try tree.dumpNode(data.un, level + delta, mapper, color, w);
try tree.dumpNode(data.un, level + delta, mapper, config, w);
}
},
.binary_cond_expr, .cond_expr, .if_then_else_stmt, .builtin_choose_expr => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("cond:\n");
try tree.dumpNode(data.if3.cond, level + delta, mapper, color, w);
try tree.dumpNode(data.if3.cond, level + delta, mapper, config, w);
try w.writeByteNTimes(' ', level + half);
try w.writeAll("then:\n");
try tree.dumpNode(tree.data[data.if3.body], level + delta, mapper, color, w);
try tree.dumpNode(tree.data[data.if3.body], level + delta, mapper, config, w);
try w.writeByteNTimes(' ', level + half);
try w.writeAll("else:\n");
try tree.dumpNode(tree.data[data.if3.body + 1], level + delta, mapper, color, w);
try tree.dumpNode(tree.data[data.if3.body + 1], level + delta, mapper, config, w);
},
.builtin_types_compatible_p => {
std.debug.assert(tree.nodes.items(.tag)[@intFromEnum(data.bin.lhs)] == .invalid);
@ -997,40 +1015,40 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
try w.writeAll("lhs: ");
const lhs_ty = tree.nodes.items(.ty)[@intFromEnum(data.bin.lhs)];
if (color) util.setColor(TYPE, w);
try config.setColor(w, TYPE);
try lhs_ty.dump(mapper, tree.comp.langopts, w);
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
try w.writeByte('\n');
try w.writeByteNTimes(' ', level + half);
try w.writeAll("rhs: ");
const rhs_ty = tree.nodes.items(.ty)[@intFromEnum(data.bin.rhs)];
if (color) util.setColor(TYPE, w);
try config.setColor(w, TYPE);
try rhs_ty.dump(mapper, tree.comp.langopts, w);
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
try w.writeByte('\n');
},
.if_then_stmt => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("cond:\n");
try tree.dumpNode(data.bin.lhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
if (data.bin.rhs != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("then:\n");
try tree.dumpNode(data.bin.rhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
}
},
.switch_stmt, .while_stmt, .do_while_stmt => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("cond:\n");
try tree.dumpNode(data.bin.lhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
if (data.bin.rhs != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("body:\n");
try tree.dumpNode(data.bin.rhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
}
},
.for_decl_stmt => {
@ -1039,30 +1057,30 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
try w.writeByteNTimes(' ', level + half);
try w.writeAll("decl:\n");
for (for_decl.decls) |decl| {
try tree.dumpNode(decl, level + delta, mapper, color, w);
try tree.dumpNode(decl, level + delta, mapper, config, w);
try w.writeByte('\n');
}
if (for_decl.cond != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("cond:\n");
try tree.dumpNode(for_decl.cond, level + delta, mapper, color, w);
try tree.dumpNode(for_decl.cond, level + delta, mapper, config, w);
}
if (for_decl.incr != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("incr:\n");
try tree.dumpNode(for_decl.incr, level + delta, mapper, color, w);
try tree.dumpNode(for_decl.incr, level + delta, mapper, config, w);
}
if (for_decl.body != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("body:\n");
try tree.dumpNode(for_decl.body, level + delta, mapper, color, w);
try tree.dumpNode(for_decl.body, level + delta, mapper, config, w);
}
},
.forever_stmt => {
if (data.un != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("body:\n");
try tree.dumpNode(data.un, level + delta, mapper, color, w);
try tree.dumpNode(data.un, level + delta, mapper, config, w);
}
},
.for_stmt => {
@ -1071,91 +1089,91 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
if (for_stmt.init != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("init:\n");
try tree.dumpNode(for_stmt.init, level + delta, mapper, color, w);
try tree.dumpNode(for_stmt.init, level + delta, mapper, config, w);
}
if (for_stmt.cond != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("cond:\n");
try tree.dumpNode(for_stmt.cond, level + delta, mapper, color, w);
try tree.dumpNode(for_stmt.cond, level + delta, mapper, config, w);
}
if (for_stmt.incr != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("incr:\n");
try tree.dumpNode(for_stmt.incr, level + delta, mapper, color, w);
try tree.dumpNode(for_stmt.incr, level + delta, mapper, config, w);
}
if (for_stmt.body != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("body:\n");
try tree.dumpNode(for_stmt.body, level + delta, mapper, color, w);
try tree.dumpNode(for_stmt.body, level + delta, mapper, config, w);
}
},
.goto_stmt, .addr_of_label => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("label: ");
if (color) util.setColor(LITERAL, w);
try config.setColor(w, LITERAL);
try w.print("{s}\n", .{tree.tokSlice(data.decl_ref)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
},
.continue_stmt, .break_stmt, .implicit_return, .null_stmt => {},
.return_stmt => {
if (data.un != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("expr:\n");
try tree.dumpNode(data.un, level + delta, mapper, color, w);
try tree.dumpNode(data.un, level + delta, mapper, config, w);
}
},
.call_expr => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("lhs:\n");
try tree.dumpNode(tree.data[data.range.start], level + delta, mapper, color, w);
try tree.dumpNode(tree.data[data.range.start], level + delta, mapper, config, w);
try w.writeByteNTimes(' ', level + half);
try w.writeAll("args:\n");
for (tree.data[data.range.start + 1 .. data.range.end]) |arg| try tree.dumpNode(arg, level + delta, mapper, color, w);
for (tree.data[data.range.start + 1 .. data.range.end]) |arg| try tree.dumpNode(arg, level + delta, mapper, config, w);
},
.call_expr_one => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("lhs:\n");
try tree.dumpNode(data.bin.lhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
if (data.bin.rhs != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("arg:\n");
try tree.dumpNode(data.bin.rhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
}
},
.builtin_call_expr => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{tree.tokSlice(@intFromEnum(tree.data[data.range.start]))});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
try w.writeByteNTimes(' ', level + half);
try w.writeAll("args:\n");
for (tree.data[data.range.start + 1 .. data.range.end]) |arg| try tree.dumpNode(arg, level + delta, mapper, color, w);
for (tree.data[data.range.start + 1 .. data.range.end]) |arg| try tree.dumpNode(arg, level + delta, mapper, config, w);
},
.builtin_call_expr_one => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{tree.tokSlice(data.decl.name)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
if (data.decl.node != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("arg:\n");
try tree.dumpNode(data.decl.node, level + delta, mapper, color, w);
try tree.dumpNode(data.decl.node, level + delta, mapper, config, w);
}
},
.special_builtin_call_one => {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{tree.tokSlice(data.decl.name)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
if (data.decl.node != .none) {
try w.writeByteNTimes(' ', level + half);
try w.writeAll("arg:\n");
try tree.dumpNode(data.decl.node, level + delta, mapper, color, w);
try tree.dumpNode(data.decl.node, level + delta, mapper, config, w);
}
},
.comma_expr,
@ -1191,12 +1209,12 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
=> {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("lhs:\n");
try tree.dumpNode(data.bin.lhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("rhs:\n");
try tree.dumpNode(data.bin.rhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
},
.explicit_cast, .implicit_cast => try tree.dumpNode(data.cast.operand, level + delta, mapper, color, w),
.explicit_cast, .implicit_cast => try tree.dumpNode(data.cast.operand, level + delta, mapper, config, w),
.addr_of_expr,
.computed_goto_stmt,
.deref_expr,
@ -1214,35 +1232,33 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
=> {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("operand:\n");
try tree.dumpNode(data.un, level + delta, mapper, color, w);
try tree.dumpNode(data.un, level + delta, mapper, config, w);
},
.decl_ref_expr => {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{tree.tokSlice(data.decl_ref)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
},
.enumeration_ref => {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{tree.tokSlice(data.decl_ref)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
},
.bool_literal,
.nullptr_literal,
.int_literal,
.char_literal,
.float16_literal,
.float_literal,
.double_literal,
.string_literal_expr,
=> {},
.member_access_expr, .member_access_ptr_expr => {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("lhs:\n");
try tree.dumpNode(data.member.lhs, level + delta, mapper, color, w);
try tree.dumpNode(data.member.lhs, level + delta, mapper, config, w);
var lhs_ty = tree.nodes.items(.ty)[@intFromEnum(data.member.lhs)];
if (lhs_ty.isPtr()) lhs_ty = lhs_ty.elemType();
@ -1250,60 +1266,60 @@ fn dumpNode(tree: Tree, node: NodeIndex, level: u32, mapper: StringInterner.Type
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("name: ");
if (color) util.setColor(NAME, w);
try config.setColor(w, NAME);
try w.print("{s}\n", .{mapper.lookup(lhs_ty.data.record.fields[data.member.index].name)});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
},
.array_access_expr => {
if (data.bin.lhs != .none) {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("lhs:\n");
try tree.dumpNode(data.bin.lhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
}
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("index:\n");
try tree.dumpNode(data.bin.rhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
},
.sizeof_expr, .alignof_expr => {
if (data.un != .none) {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("expr:\n");
try tree.dumpNode(data.un, level + delta, mapper, color, w);
try tree.dumpNode(data.un, level + delta, mapper, config, w);
}
},
.generic_expr_one => {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("controlling:\n");
try tree.dumpNode(data.bin.lhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
try w.writeByteNTimes(' ', level + 1);
if (data.bin.rhs != .none) {
try w.writeAll("chosen:\n");
try tree.dumpNode(data.bin.rhs, level + delta, mapper, color, w);
try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
}
},
.generic_expr => {
const nodes = tree.data[data.range.start..data.range.end];
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("controlling:\n");
try tree.dumpNode(nodes[0], level + delta, mapper, color, w);
try tree.dumpNode(nodes[0], level + delta, mapper, config, w);
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("chosen:\n");
try tree.dumpNode(nodes[1], level + delta, mapper, color, w);
try tree.dumpNode(nodes[1], level + delta, mapper, config, w);
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("rest:\n");
for (nodes[2..]) |expr| {
try tree.dumpNode(expr, level + delta, mapper, color, w);
try tree.dumpNode(expr, level + delta, mapper, config, w);
}
},
.generic_association_expr, .generic_default_expr, .stmt_expr, .imaginary_literal => {
try tree.dumpNode(data.un, level + delta, mapper, color, w);
try tree.dumpNode(data.un, level + delta, mapper, config, w);
},
.array_filler_expr => {
try w.writeByteNTimes(' ', level + 1);
try w.writeAll("count: ");
if (color) util.setColor(LITERAL, w);
try config.setColor(w, LITERAL);
try w.print("{d}\n", .{data.int});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
},
.struct_forward_decl,
.union_forward_decl,

View File

@ -10,8 +10,6 @@ const StringId = StringInterner.StringId;
const target_util = @import("target.zig");
const LangOpts = @import("LangOpts.zig");
const Type = @This();
pub const Qualifiers = packed struct {
@"const": bool = false,
atomic: bool = false,
@ -104,22 +102,20 @@ pub const Func = struct {
name_tok: TokenIndex,
};
fn eql(a: *const Func, b: *const Func, a_var_args: bool, b_var_args: bool, comp: *const Compilation) bool {
fn eql(a: *const Func, b: *const Func, a_spec: Specifier, b_spec: Specifier, comp: *const Compilation) bool {
// return type cannot have qualifiers
if (!a.return_type.eql(b.return_type, comp, false)) return false;
if (a.params.len != b.params.len) {
const a_no_proto = a_var_args and a.params.len == 0 and !comp.langopts.standard.atLeast(.c2x);
const b_no_proto = b_var_args and b.params.len == 0 and !comp.langopts.standard.atLeast(.c2x);
if (a_no_proto or b_no_proto) {
const maybe_has_params = if (a_no_proto) b else a;
if (a_spec == .old_style_func or b_spec == .old_style_func) {
const maybe_has_params = if (a_spec == .old_style_func) b else a;
for (maybe_has_params.params) |param| {
if (param.ty.undergoesDefaultArgPromotion(comp)) return false;
}
return true;
}
}
if (a_var_args != b_var_args) return false;
if ((a_spec == .func) != (b_spec == .func)) return false;
// TODO validate this
for (a.params, b.params) |param, b_qual| {
var a_unqual = param.ty;
@ -149,10 +145,10 @@ pub const Attributed = struct {
base: Type,
pub fn create(allocator: std.mem.Allocator, base: Type, existing_attributes: []const Attribute, attributes: []const Attribute) !*Attributed {
var attributed_type = try allocator.create(Attributed);
const attributed_type = try allocator.create(Attributed);
errdefer allocator.destroy(attributed_type);
var all_attrs = try allocator.alloc(Attribute, existing_attributes.len + attributes.len);
const all_attrs = try allocator.alloc(Attribute, existing_attributes.len + attributes.len);
std.mem.copy(Attribute, all_attrs, existing_attributes);
std.mem.copy(Attribute, all_attrs[existing_attributes.len..], attributes);
@ -312,6 +308,8 @@ pub const Specifier = enum {
/// GNU auto type
/// This is a placeholder specifier - it must be replaced by the actual type specifier (determined by the initializer)
auto_type,
/// C23 auto, behaves like auto_type
c23_auto,
void,
bool,
@ -411,6 +409,8 @@ pub const Specifier = enum {
nullptr_t,
};
const Type = @This();
/// All fields of Type except data may be mutated
data: union {
sub_type: *Type,
@ -422,7 +422,7 @@ data: union {
attributed: *Attributed,
none: void,
int: struct {
bits: u8,
bits: u16,
signedness: std.builtin.Signedness,
},
} = .{ .none = {} },
@ -623,17 +623,21 @@ pub fn isConst(ty: Type) bool {
}
pub fn isUnsignedInt(ty: Type, comp: *const Compilation) bool {
return ty.signedness(comp) == .unsigned;
}
pub fn signedness(ty: Type, comp: *const Compilation) std.builtin.Signedness {
return switch (ty.specifier) {
// zig fmt: off
.char, .complex_char => return comp.getCharSignedness() == .unsigned,
.char, .complex_char => return comp.getCharSignedness(),
.uchar, .ushort, .uint, .ulong, .ulong_long, .bool, .complex_uchar, .complex_ushort,
.complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128 => true,
.complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128 => .unsigned,
// zig fmt: on
.bit_int, .complex_bit_int => return ty.data.int.signedness == .unsigned,
.typeof_type => ty.data.sub_type.isUnsignedInt(comp),
.typeof_expr => ty.data.expr.ty.isUnsignedInt(comp),
.attributed => ty.data.attributed.base.isUnsignedInt(comp),
else => false,
.bit_int, .complex_bit_int => ty.data.int.signedness,
.typeof_type => ty.data.sub_type.signedness(comp),
.typeof_expr => ty.data.expr.ty.signedness(comp),
.attributed => ty.data.attributed.base.signedness(comp),
else => .signed,
};
}
@ -760,7 +764,7 @@ pub fn getRecord(ty: Type) ?*const Type.Record {
};
}
fn compareIntegerRanks(a: Type, b: Type, comp: *const Compilation) std.math.Order {
pub fn compareIntegerRanks(a: Type, b: Type, comp: *const Compilation) std.math.Order {
std.debug.assert(a.isInt() and b.isInt());
if (a.eql(b, comp, false)) return .eq;
@ -898,7 +902,7 @@ pub fn bitfieldPromotion(ty: Type, comp: *Compilation, width: u32) ?Type {
pub fn hasIncompleteSize(ty: Type) bool {
return switch (ty.specifier) {
.void, .incomplete_array, .invalid => true,
.void, .incomplete_array => true,
.@"enum" => ty.data.@"enum".isIncomplete() and !ty.data.@"enum".fixed,
.@"struct", .@"union" => ty.data.record.isIncomplete(),
.array, .static_array => ty.data.array.elem.hasIncompleteSize(),
@ -958,6 +962,7 @@ pub fn hasField(ty: Type, name: StringId) bool {
return false;
}
// TODO handle bitints
pub fn minInt(ty: Type, comp: *const Compilation) i64 {
std.debug.assert(ty.isInt());
if (ty.isUnsignedInt(comp)) return 0;
@ -970,6 +975,7 @@ pub fn minInt(ty: Type, comp: *const Compilation) i64 {
};
}
// TODO handle bitints
pub fn maxInt(ty: Type, comp: *const Compilation) u64 {
std.debug.assert(ty.isInt());
return switch (ty.sizeof(comp).?) {
@ -1001,7 +1007,7 @@ pub fn sizeCompare(a: Type, b: Type, comp: *Compilation) TypeSizeOrder {
/// Size of type as reported by sizeof
pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {
return switch (ty.specifier) {
.auto_type => unreachable,
.auto_type, .c23_auto => unreachable,
.variable_len_array, .unspecified_variable_len_array => return null,
.incomplete_array => return if (comp.langopts.emulate == .msvc) @as(?u64, 0) else null,
.func, .var_args_func, .old_style_func, .void, .bool => 1,
@ -1104,7 +1110,7 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
return switch (ty.specifier) {
.invalid => unreachable,
.auto_type => unreachable,
.auto_type, .c23_auto => unreachable,
.variable_len_array,
.incomplete_array,
@ -1271,7 +1277,7 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi
.func,
.var_args_func,
.old_style_func,
=> if (!a.data.func.eql(b.data.func, a.specifier == .var_args_func, b.specifier == .var_args_func, comp)) return false,
=> if (!a.data.func.eql(b.data.func, a.specifier, b.specifier, comp)) return false,
.array,
.static_array,
@ -1418,7 +1424,7 @@ pub fn combine(inner: *Type, outer: Type) Parser.Error!void {
.decayed_typeof_type,
.decayed_typeof_expr,
=> unreachable, // type should not be able to decay before being combined
.void => inner.* = outer,
.void, .invalid => inner.* = outer,
else => unreachable,
}
}
@ -1496,6 +1502,8 @@ pub const Builder = struct {
void,
/// GNU __auto_type extension
auto_type,
/// C23 auto
c23_auto,
nullptr_t,
bool,
char,
@ -1557,12 +1565,12 @@ pub const Builder = struct {
complex_int128,
complex_sint128,
complex_uint128,
bit_int: i16,
sbit_int: i16,
ubit_int: i16,
complex_bit_int: i16,
complex_sbit_int: i16,
complex_ubit_int: i16,
bit_int: u64,
sbit_int: u64,
ubit_int: u64,
complex_bit_int: u64,
complex_sbit_int: u64,
complex_ubit_int: u64,
fp16,
float16,
@ -1608,8 +1616,9 @@ pub const Builder = struct {
.none => unreachable,
.void => "void",
.auto_type => "__auto_type",
.c23_auto => "auto",
.nullptr_t => "nullptr_t",
.bool => if (langopts.standard.atLeast(.c2x)) "bool" else "_Bool",
.bool => if (langopts.standard.atLeast(.c23)) "bool" else "_Bool",
.char => "char",
.schar => "signed char",
.uchar => "unsigned char",
@ -1706,7 +1715,7 @@ pub const Builder = struct {
// TODO this really should be easier
switch (ty.specifier) {
.array, .static_array, .incomplete_array => {
var old = ty.data.array;
const old = ty.data.array;
ty.data.array = try p.arena.create(Array);
ty.data.array.* = .{
.len = old.len,
@ -1714,7 +1723,7 @@ pub const Builder = struct {
};
},
.variable_len_array, .unspecified_variable_len_array => {
var old = ty.data.expr;
const old = ty.data.expr;
ty.data.expr = try p.arena.create(Expr);
ty.data.expr.* = .{
.node = old.node,
@ -1738,8 +1747,8 @@ pub const Builder = struct {
ty = typeof;
} else {
ty.specifier = .int;
if (p.comp.langopts.standard.atLeast(.c2x)) {
try p.err(.missing_type_specifier_c2x);
if (p.comp.langopts.standard.atLeast(.c23)) {
try p.err(.missing_type_specifier_c23);
} else {
try p.err(.missing_type_specifier);
}
@ -1747,6 +1756,7 @@ pub const Builder = struct {
},
.void => ty.specifier = .void,
.auto_type => ty.specifier = .auto_type,
.c23_auto => ty.specifier = .c23_auto,
.nullptr_t => unreachable, // nullptr_t can only be accessed via typeof(nullptr)
.bool => ty.specifier = .bool,
.char => ty.specifier = .char,
@ -1785,17 +1795,17 @@ pub const Builder = struct {
if (unsigned) {
if (bits < 1) {
try p.errStr(.unsigned_bit_int_too_small, b.bit_int_tok.?, b.specifier.str(p.comp.langopts).?);
return error.ParsingFailed;
return Type.invalid;
}
} else {
if (bits < 2) {
try p.errStr(.signed_bit_int_too_small, b.bit_int_tok.?, b.specifier.str(p.comp.langopts).?);
return error.ParsingFailed;
return Type.invalid;
}
}
if (bits > Compilation.bit_int_max_bits) {
try p.errStr(.bit_int_too_big, b.bit_int_tok.?, b.specifier.str(p.comp.langopts).?);
return error.ParsingFailed;
return Type.invalid;
}
ty.specifier = if (b.complex_tok != null) .complex_bit_int else .bit_int;
ty.data = .{ .int = .{
@ -2175,6 +2185,10 @@ pub const Builder = struct {
.none => .auto_type,
else => return b.cannotCombine(p, source_tok),
},
.c23_auto => b.specifier = switch (b.specifier) {
.none => .c23_auto,
else => return b.cannotCombine(p, source_tok),
},
.fp16 => b.specifier = switch (b.specifier) {
.none => .fp16,
else => return b.cannotCombine(p, source_tok),
@ -2292,6 +2306,7 @@ pub const Builder = struct {
return switch (ty.specifier) {
.void => .void,
.auto_type => .auto_type,
.c23_auto => .c23_auto,
.nullptr_t => .nullptr_t,
.bool => .bool,
.char => .char,
@ -2606,7 +2621,10 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
try ty.data.sub_type.dump(mapper, langopts, w);
},
.func, .var_args_func, .old_style_func => {
try w.writeAll("fn (");
if (ty.specifier == .old_style_func)
try w.writeAll("kr (")
else
try w.writeAll("fn (");
for (ty.data.func.params, 0..) |param, i| {
if (i != 0) try w.writeAll(", ");
if (param.name != .empty) try w.print("{s}: ", .{mapper.lookup(param.name)});
@ -2620,7 +2638,7 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
try ty.data.func.return_type.dump(mapper, langopts, w);
},
.array, .static_array, .decayed_array, .decayed_static_array => {
if (ty.specifier == .decayed_array or ty.specifier == .decayed_static_array) try w.writeByte('d');
if (ty.specifier == .decayed_array or ty.specifier == .decayed_static_array) try w.writeAll("*d");
try w.writeByte('[');
if (ty.specifier == .static_array or ty.specifier == .decayed_static_array) try w.writeAll("static ");
try w.print("{d}]", .{ty.data.array.len});
@ -2632,7 +2650,7 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
try w.writeAll(")");
},
.incomplete_array, .decayed_incomplete_array => {
if (ty.specifier == .decayed_incomplete_array) try w.writeByte('d');
if (ty.specifier == .decayed_incomplete_array) try w.writeAll("*d");
try w.writeAll("[]");
try ty.data.array.elem.dump(mapper, langopts, w);
},
@ -2655,12 +2673,12 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
if (dump_detailed_containers) try dumpRecord(ty.data.record, mapper, langopts, w);
},
.unspecified_variable_len_array, .decayed_unspecified_variable_len_array => {
if (ty.specifier == .decayed_unspecified_variable_len_array) try w.writeByte('d');
if (ty.specifier == .decayed_unspecified_variable_len_array) try w.writeAll("*d");
try w.writeAll("[*]");
try ty.data.sub_type.dump(mapper, langopts, w);
},
.variable_len_array, .decayed_variable_len_array => {
if (ty.specifier == .decayed_variable_len_array) try w.writeByte('d');
if (ty.specifier == .decayed_variable_len_array) try w.writeAll("*d");
try w.writeAll("[<expr>]");
try ty.data.expr.ty.dump(mapper, langopts, w);
},

726
deps/aro/aro/Value.zig vendored Normal file
View File

@ -0,0 +1,726 @@
const std = @import("std");
const assert = std.debug.assert;
const BigIntConst = std.math.big.int.Const;
const BigIntMutable = std.math.big.int.Mutable;
const backend = @import("backend");
const Interner = backend.Interner;
const BigIntSpace = Interner.Tag.Int.BigIntSpace;
const Compilation = @import("Compilation.zig");
const Type = @import("Type.zig");
const target_util = @import("target.zig");
const Value = @This();
opt_ref: Interner.OptRef = .none,
pub const zero = Value{ .opt_ref = .zero };
pub const one = Value{ .opt_ref = .one };
pub const @"null" = Value{ .opt_ref = .null };
pub fn intern(comp: *Compilation, k: Interner.Key) !Value {
const r = try comp.interner.put(comp.gpa, k);
return .{ .opt_ref = @enumFromInt(@intFromEnum(r)) };
}
pub fn int(i: anytype, comp: *Compilation) !Value {
const info = @typeInfo(@TypeOf(i));
if (info == .ComptimeInt or info.Int.signedness == .unsigned) {
return intern(comp, .{ .int = .{ .u64 = i } });
} else {
return intern(comp, .{ .int = .{ .i64 = i } });
}
}
pub fn ref(v: Value) Interner.Ref {
std.debug.assert(v.opt_ref != .none);
return @enumFromInt(@intFromEnum(v.opt_ref));
}
pub fn is(v: Value, tag: std.meta.Tag(Interner.Key), comp: *const Compilation) bool {
if (v.opt_ref == .none) return false;
return comp.interner.get(v.ref()) == tag;
}
/// Number of bits needed to hold `v`.
/// Asserts that `v` is not negative
pub fn minUnsignedBits(v: Value, comp: *const Compilation) usize {
var space: BigIntSpace = undefined;
const big = v.toBigInt(&space, comp);
assert(big.positive);
return big.bitCountAbs();
}
test "minUnsignedBits" {
const Test = struct {
fn checkIntBits(comp: *Compilation, v: u64, expected: usize) !void {
const val = try intern(comp, .{ .int = .{ .u64 = v } });
try std.testing.expectEqual(expected, val.minUnsignedBits(comp));
}
};
var comp = Compilation.init(std.testing.allocator);
defer comp.deinit();
comp.target = (try std.zig.CrossTarget.parse(.{ .arch_os_abi = "x86_64-linux-gnu" })).toTarget();
try Test.checkIntBits(&comp, 0, 0);
try Test.checkIntBits(&comp, 1, 1);
try Test.checkIntBits(&comp, 2, 2);
try Test.checkIntBits(&comp, std.math.maxInt(i8), 7);
try Test.checkIntBits(&comp, std.math.maxInt(u8), 8);
try Test.checkIntBits(&comp, std.math.maxInt(i16), 15);
try Test.checkIntBits(&comp, std.math.maxInt(u16), 16);
try Test.checkIntBits(&comp, std.math.maxInt(i32), 31);
try Test.checkIntBits(&comp, std.math.maxInt(u32), 32);
try Test.checkIntBits(&comp, std.math.maxInt(i64), 63);
try Test.checkIntBits(&comp, std.math.maxInt(u64), 64);
}
/// Minimum number of bits needed to represent `v` in 2's complement notation
/// Asserts that `v` is negative.
pub fn minSignedBits(v: Value, comp: *const Compilation) usize {
var space: BigIntSpace = undefined;
const big = v.toBigInt(&space, comp);
assert(!big.positive);
return big.bitCountTwosComp();
}
test "minSignedBits" {
const Test = struct {
fn checkIntBits(comp: *Compilation, v: i64, expected: usize) !void {
const val = try intern(comp, .{ .int = .{ .i64 = v } });
try std.testing.expectEqual(expected, val.minSignedBits(comp));
}
};
var comp = Compilation.init(std.testing.allocator);
defer comp.deinit();
comp.target = (try std.zig.CrossTarget.parse(.{ .arch_os_abi = "x86_64-linux-gnu" })).toTarget();
try Test.checkIntBits(&comp, -1, 1);
try Test.checkIntBits(&comp, -2, 2);
try Test.checkIntBits(&comp, -10, 5);
try Test.checkIntBits(&comp, -101, 8);
try Test.checkIntBits(&comp, std.math.minInt(i8), 8);
try Test.checkIntBits(&comp, std.math.minInt(i16), 16);
try Test.checkIntBits(&comp, std.math.minInt(i32), 32);
try Test.checkIntBits(&comp, std.math.minInt(i64), 64);
}
pub const FloatToIntChangeKind = enum {
/// value did not change
none,
/// floating point number too small or large for destination integer type
out_of_range,
/// tried to convert a NaN or Infinity
overflow,
/// fractional value was converted to zero
nonzero_to_zero,
/// fractional part truncated
value_changed,
};
/// Converts the stored value from a float to an integer.
/// `.none` value remains unchanged.
pub fn floatToInt(v: *Value, dest_ty: Type, comp: *Compilation) !FloatToIntChangeKind {
if (v.opt_ref == .none) return .none;
const float_val = v.toFloat(f128, comp);
const was_zero = float_val == 0;
if (dest_ty.is(.bool)) {
const was_one = float_val == 1.0;
v.* = fromBool(!was_zero);
if (was_zero or was_one) return .none;
return .value_changed;
} else if (dest_ty.isUnsignedInt(comp) and v.compare(.lt, zero, comp)) {
v.* = zero;
return .out_of_range;
}
const had_fraction = @rem(float_val, 1) != 0;
const is_negative = std.math.signbit(float_val);
const floored = @floor(@abs(float_val));
var rational = try std.math.big.Rational.init(comp.gpa);
defer rational.deinit();
rational.setFloat(f128, floored) catch |err| switch (err) {
error.NonFiniteFloat => {
v.* = .{};
return .overflow;
},
error.OutOfMemory => return error.OutOfMemory,
};
// The float is reduced in rational.setFloat, so we assert that denominator is equal to one
const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
assert(rational.q.toConst().eqlAbs(big_one));
if (is_negative) {
rational.negate();
}
const signedness = dest_ty.signedness(comp);
const bits: usize = @intCast(dest_ty.bitSizeof(comp).?);
// rational.p.truncate(rational.p.toConst(), signedness: Signedness, bit_count: usize)
const fits = rational.p.fitsInTwosComp(signedness, bits);
v.* = try intern(comp, .{ .int = .{ .big_int = rational.p.toConst() } });
try rational.p.truncate(&rational.p, signedness, bits);
if (!was_zero and v.isZero(comp)) return .nonzero_to_zero;
if (!fits) return .out_of_range;
if (had_fraction) return .value_changed;
return .none;
}
/// Converts the stored value from an integer to a float.
/// `.none` value remains unchanged.
pub fn intToFloat(v: *Value, dest_ty: Type, comp: *Compilation) !void {
if (v.opt_ref == .none) return;
const bits = dest_ty.bitSizeof(comp).?;
return switch (comp.interner.get(v.ref()).int) {
inline .u64, .i64 => |data| {
const f: Interner.Key.Float = switch (bits) {
16 => .{ .f16 = @floatFromInt(data) },
32 => .{ .f32 = @floatFromInt(data) },
64 => .{ .f64 = @floatFromInt(data) },
80 => .{ .f80 = @floatFromInt(data) },
128 => .{ .f128 = @floatFromInt(data) },
else => unreachable,
};
v.* = try intern(comp, .{ .float = f });
},
.big_int => |data| {
const big_f = bigIntToFloat(data.limbs, data.positive);
const f: Interner.Key.Float = switch (bits) {
16 => .{ .f16 = @floatCast(big_f) },
32 => .{ .f32 = @floatCast(big_f) },
64 => .{ .f64 = @floatCast(big_f) },
80 => .{ .f80 = @floatCast(big_f) },
128 => .{ .f128 = @floatCast(big_f) },
else => unreachable,
};
v.* = try intern(comp, .{ .float = f });
},
};
}
/// Truncates or extends bits based on type.
/// `.none` value remains unchanged.
pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
if (v.opt_ref == .none) return;
const bits: usize = @intCast(dest_ty.bitSizeof(comp).?);
var space: BigIntSpace = undefined;
const big = v.toBigInt(&space, comp);
const limbs = try comp.gpa.alloc(
std.math.big.Limb,
std.math.big.int.calcTwosCompLimbCount(bits),
);
defer comp.gpa.free(limbs);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
result_bigint.truncate(big, dest_ty.signedness(comp), bits);
v.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
}
/// Converts the stored value from an integer to a float.
/// `.none` value remains unchanged.
pub fn floatCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
if (v.opt_ref == .none) return;
// TODO complex values
const bits = dest_ty.makeReal().bitSizeof(comp).?;
const f: Interner.Key.Float = switch (bits) {
16 => .{ .f16 = v.toFloat(f16, comp) },
32 => .{ .f32 = v.toFloat(f32, comp) },
64 => .{ .f64 = v.toFloat(f64, comp) },
80 => .{ .f80 = v.toFloat(f80, comp) },
128 => .{ .f128 = v.toFloat(f128, comp) },
else => unreachable,
};
v.* = try intern(comp, .{ .float = f });
}
pub fn toFloat(v: Value, comptime T: type, comp: *const Compilation) T {
return switch (comp.interner.get(v.ref())) {
.int => |repr| switch (repr) {
inline .u64, .i64 => |data| @floatFromInt(data),
.big_int => |data| @floatCast(bigIntToFloat(data.limbs, data.positive)),
},
.float => |repr| switch (repr) {
inline else => |data| @floatCast(data),
},
else => unreachable,
};
}
fn bigIntToFloat(limbs: []const std.math.big.Limb, positive: bool) f128 {
if (limbs.len == 0) return 0;
const base = std.math.maxInt(std.math.big.Limb) + 1;
var result: f128 = 0;
var i: usize = limbs.len;
while (i != 0) {
i -= 1;
const limb: f128 = @as(f128, @floatFromInt(limbs[i]));
result = @mulAdd(f128, base, result, limb);
}
if (positive) {
return result;
} else {
return -result;
}
}
pub fn toBigInt(val: Value, space: *BigIntSpace, comp: *const Compilation) BigIntConst {
return switch (comp.interner.get(val.ref()).int) {
inline .u64, .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(),
.big_int => |b| b,
};
}
pub fn isZero(v: Value, comp: *const Compilation) bool {
if (v.opt_ref == .none) return false;
switch (v.ref()) {
.zero => return true,
.one => return false,
.null => return target_util.nullRepr(comp.target) == 0,
else => {},
}
const key = comp.interner.get(v.ref());
switch (key) {
.float => |repr| switch (repr) {
inline else => |data| return data == 0,
},
.int => |repr| switch (repr) {
inline .i64, .u64 => |data| return data == 0,
.big_int => |data| return data.eqlZero(),
},
.bytes => return false,
else => unreachable,
}
}
/// Converts value to zero or one;
/// `.none` value remains unchanged.
pub fn boolCast(v: *Value, comp: *const Compilation) void {
if (v.opt_ref == .none) return;
v.* = fromBool(v.toBool(comp));
}
pub fn fromBool(b: bool) Value {
return if (b) one else zero;
}
pub fn toBool(v: Value, comp: *const Compilation) bool {
return !v.isZero(comp);
}
pub fn toInt(v: Value, comptime T: type, comp: *const Compilation) ?T {
if (v.opt_ref == .none) return null;
if (comp.interner.get(v.ref()) != .int) return null;
var space: BigIntSpace = undefined;
const big_int = v.toBigInt(&space, comp);
return big_int.to(T) catch null;
}
pub fn add(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
const bits: usize = @intCast(ty.bitSizeof(comp).?);
if (ty.isFloat()) {
const f: Interner.Key.Float = switch (bits) {
16 => .{ .f16 = lhs.toFloat(f16, comp) + rhs.toFloat(f16, comp) },
32 => .{ .f32 = lhs.toFloat(f32, comp) + rhs.toFloat(f32, comp) },
64 => .{ .f64 = lhs.toFloat(f64, comp) + rhs.toFloat(f64, comp) },
80 => .{ .f80 = lhs.toFloat(f80, comp) + rhs.toFloat(f80, comp) },
128 => .{ .f128 = lhs.toFloat(f128, comp) + rhs.toFloat(f128, comp) },
else => unreachable,
};
res.* = try intern(comp, .{ .float = f });
return false;
} else {
var lhs_space: BigIntSpace = undefined;
var rhs_space: BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
const limbs = try comp.gpa.alloc(
std.math.big.Limb,
std.math.big.int.calcTwosCompLimbCount(bits),
);
defer comp.gpa.free(limbs);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, ty.signedness(comp), bits);
res.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
return overflowed;
}
}
pub fn sub(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
const bits: usize = @intCast(ty.bitSizeof(comp).?);
if (ty.isFloat()) {
const f: Interner.Key.Float = switch (bits) {
16 => .{ .f16 = lhs.toFloat(f16, comp) - rhs.toFloat(f16, comp) },
32 => .{ .f32 = lhs.toFloat(f32, comp) - rhs.toFloat(f32, comp) },
64 => .{ .f64 = lhs.toFloat(f64, comp) - rhs.toFloat(f64, comp) },
80 => .{ .f80 = lhs.toFloat(f80, comp) - rhs.toFloat(f80, comp) },
128 => .{ .f128 = lhs.toFloat(f128, comp) - rhs.toFloat(f128, comp) },
else => unreachable,
};
res.* = try intern(comp, .{ .float = f });
return false;
} else {
var lhs_space: BigIntSpace = undefined;
var rhs_space: BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
const limbs = try comp.gpa.alloc(
std.math.big.Limb,
std.math.big.int.calcTwosCompLimbCount(bits),
);
defer comp.gpa.free(limbs);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, ty.signedness(comp), bits);
res.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
return overflowed;
}
}
pub fn mul(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
const bits: usize = @intCast(ty.bitSizeof(comp).?);
if (ty.isFloat()) {
const f: Interner.Key.Float = switch (bits) {
16 => .{ .f16 = lhs.toFloat(f16, comp) * rhs.toFloat(f16, comp) },
32 => .{ .f32 = lhs.toFloat(f32, comp) * rhs.toFloat(f32, comp) },
64 => .{ .f64 = lhs.toFloat(f64, comp) * rhs.toFloat(f64, comp) },
80 => .{ .f80 = lhs.toFloat(f80, comp) * rhs.toFloat(f80, comp) },
128 => .{ .f128 = lhs.toFloat(f128, comp) * rhs.toFloat(f128, comp) },
else => unreachable,
};
res.* = try intern(comp, .{ .float = f });
return false;
} else {
var lhs_space: BigIntSpace = undefined;
var rhs_space: BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
const limbs = try comp.gpa.alloc(
std.math.big.Limb,
lhs_bigint.limbs.len + rhs_bigint.limbs.len,
);
defer comp.gpa.free(limbs);
var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
const limbs_buffer = try comp.gpa.alloc(
std.math.big.Limb,
std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1),
);
defer comp.gpa.free(limbs_buffer);
result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, comp.gpa);
const signedness = ty.signedness(comp);
const overflowed = !result_bigint.toConst().fitsInTwosComp(signedness, bits);
if (overflowed) {
result_bigint.truncate(result_bigint.toConst(), signedness, bits);
}
res.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
return overflowed;
}
}
/// caller guarantees rhs != 0
pub fn div(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
const bits: usize = @intCast(ty.bitSizeof(comp).?);
if (ty.isFloat()) {
const f: Interner.Key.Float = switch (bits) {
16 => .{ .f16 = lhs.toFloat(f16, comp) / rhs.toFloat(f16, comp) },
32 => .{ .f32 = lhs.toFloat(f32, comp) / rhs.toFloat(f32, comp) },
64 => .{ .f64 = lhs.toFloat(f64, comp) / rhs.toFloat(f64, comp) },
80 => .{ .f80 = lhs.toFloat(f80, comp) / rhs.toFloat(f80, comp) },
128 => .{ .f128 = lhs.toFloat(f128, comp) / rhs.toFloat(f128, comp) },
else => unreachable,
};
res.* = try intern(comp, .{ .float = f });
return false;
} else {
var lhs_space: BigIntSpace = undefined;
var rhs_space: BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
const limbs_q = try comp.gpa.alloc(
std.math.big.Limb,
lhs_bigint.limbs.len,
);
defer comp.gpa.free(limbs_q);
var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
const limbs_r = try comp.gpa.alloc(
std.math.big.Limb,
rhs_bigint.limbs.len,
);
defer comp.gpa.free(limbs_r);
var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
const limbs_buffer = try comp.gpa.alloc(
std.math.big.Limb,
std.math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
);
defer comp.gpa.free(limbs_buffer);
result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
res.* = try intern(comp, .{ .int = .{ .big_int = result_q.toConst() } });
return !result_q.toConst().fitsInTwosComp(ty.signedness(comp), bits);
}
}
/// caller guarantees rhs != 0
/// caller guarantees lhs != std.math.minInt(T) OR rhs != -1
pub fn rem(lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !Value {
var lhs_space: BigIntSpace = undefined;
var rhs_space: BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
const signedness = ty.signedness(comp);
if (signedness == .signed) {
var spaces: [3]BigIntSpace = undefined;
const min_val = BigIntMutable.init(&spaces[0].limbs, ty.minInt(comp)).toConst();
const negative = BigIntMutable.init(&spaces[1].limbs, -1).toConst();
const big_one = BigIntMutable.init(&spaces[2].limbs, 1).toConst();
if (lhs_bigint.eql(min_val) and rhs_bigint.eql(negative)) {
return .{};
} else if (rhs_bigint.order(big_one).compare(.lt)) {
// lhs - @divTrunc(lhs, rhs) * rhs
var tmp: Value = undefined;
_ = try tmp.div(lhs, rhs, ty, comp);
_ = try tmp.mul(tmp, rhs, ty, comp);
_ = try tmp.sub(lhs, tmp, ty, comp);
return tmp;
}
}
const limbs_q = try comp.gpa.alloc(
std.math.big.Limb,
lhs_bigint.limbs.len,
);
defer comp.gpa.free(limbs_q);
var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
const limbs_r = try comp.gpa.alloc(
std.math.big.Limb,
rhs_bigint.limbs.len,
);
defer comp.gpa.free(limbs_r);
var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
const limbs_buffer = try comp.gpa.alloc(
std.math.big.Limb,
std.math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
);
defer comp.gpa.free(limbs_buffer);
result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
return intern(comp, .{ .int = .{ .big_int = result_r.toConst() } });
}
pub fn bitOr(lhs: Value, rhs: Value, comp: *Compilation) !Value {
var lhs_space: BigIntSpace = undefined;
var rhs_space: BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
const limbs = try comp.gpa.alloc(
std.math.big.Limb,
@max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
);
defer comp.gpa.free(limbs);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
result_bigint.bitOr(lhs_bigint, rhs_bigint);
return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
}
pub fn bitXor(lhs: Value, rhs: Value, comp: *Compilation) !Value {
var lhs_space: BigIntSpace = undefined;
var rhs_space: BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
const limbs = try comp.gpa.alloc(
std.math.big.Limb,
@max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
);
defer comp.gpa.free(limbs);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
result_bigint.bitXor(lhs_bigint, rhs_bigint);
return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
}
pub fn bitAnd(lhs: Value, rhs: Value, comp: *Compilation) !Value {
var lhs_space: BigIntSpace = undefined;
var rhs_space: BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
const limbs = try comp.gpa.alloc(
std.math.big.Limb,
@max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
);
defer comp.gpa.free(limbs);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
result_bigint.bitAnd(lhs_bigint, rhs_bigint);
return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
}
pub fn bitNot(val: Value, ty: Type, comp: *Compilation) !Value {
const bits: usize = @intCast(ty.bitSizeof(comp).?);
var val_space: Value.BigIntSpace = undefined;
const val_bigint = val.toBigInt(&val_space, comp);
const limbs = try comp.gpa.alloc(
std.math.big.Limb,
std.math.big.int.calcTwosCompLimbCount(bits),
);
defer comp.gpa.free(limbs);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
result_bigint.bitNotWrap(val_bigint, ty.signedness(comp), bits);
return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
}
pub fn shl(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
var lhs_space: Value.BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
const shift = rhs.toInt(usize, comp) orelse std.math.maxInt(usize);
const bits: usize = @intCast(ty.bitSizeof(comp).?);
if (shift > bits) {
if (lhs_bigint.positive) {
res.* = try intern(comp, .{ .int = .{ .u64 = ty.maxInt(comp) } });
} else {
res.* = try intern(comp, .{ .int = .{ .i64 = ty.minInt(comp) } });
}
return true;
}
const limbs = try comp.gpa.alloc(
std.math.big.Limb,
lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1,
);
defer comp.gpa.free(limbs);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
result_bigint.shiftLeft(lhs_bigint, shift);
const signedness = ty.signedness(comp);
const overflowed = !result_bigint.toConst().fitsInTwosComp(signedness, bits);
if (overflowed) {
result_bigint.truncate(result_bigint.toConst(), signedness, bits);
}
res.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
return overflowed;
}
pub fn shr(lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !Value {
var lhs_space: Value.BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
const shift = rhs.toInt(usize, comp) orelse return zero;
const result_limbs = lhs_bigint.limbs.len -| (shift / (@sizeOf(std.math.big.Limb) * 8));
if (result_limbs == 0) {
// The shift is enough to remove all the bits from the number, which means the
// result is 0 or -1 depending on the sign.
if (lhs_bigint.positive) {
return zero;
} else {
return intern(comp, .{ .int = .{ .i64 = -1 } });
}
}
const bits: usize = @intCast(ty.bitSizeof(comp).?);
const limbs = try comp.gpa.alloc(
std.math.big.Limb,
std.math.big.int.calcTwosCompLimbCount(bits),
);
defer comp.gpa.free(limbs);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
result_bigint.shiftRight(lhs_bigint, shift);
return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
}
pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *const Compilation) bool {
if (op == .eq) {
return lhs.opt_ref == rhs.opt_ref;
} else if (lhs.opt_ref == rhs.opt_ref) {
return std.math.Order.eq.compare(op);
}
const lhs_key = comp.interner.get(lhs.ref());
const rhs_key = comp.interner.get(rhs.ref());
if (lhs_key == .float or rhs_key == .float) {
const lhs_f128 = lhs.toFloat(f128, comp);
const rhs_f128 = rhs.toFloat(f128, comp);
return std.math.compare(lhs_f128, op, rhs_f128);
}
var lhs_bigint_space: BigIntSpace = undefined;
var rhs_bigint_space: BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_bigint_space, comp);
const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, comp);
return lhs_bigint.order(rhs_bigint).compare(op);
}
pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {
if (ty.is(.bool)) {
return w.writeAll(if (v.isZero(comp)) "false" else "true");
}
const key = comp.interner.get(v.ref());
switch (key) {
.null => return w.writeAll("nullptr_t"),
.int => |repr| switch (repr) {
inline else => |x| return w.print("{d}", .{x}),
},
.float => |repr| switch (repr) {
.f16 => |x| return w.print("{d}", .{@round(@as(f64, @floatCast(x)) * 1000) / 1000}),
.f32 => |x| return w.print("{d}", .{@round(@as(f64, @floatCast(x)) * 1000000) / 1000000}),
inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}),
},
.bytes => |b| return printString(b, ty, comp, w),
else => unreachable, // not a value
}
}
pub fn printString(bytes: []const u8, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {
const size: Compilation.CharUnitSize = @enumFromInt(ty.elemType().sizeof(comp).?);
const without_null = bytes[0 .. bytes.len - @intFromEnum(size)];
switch (size) {
inline .@"1", .@"2" => |sz| {
const data_slice: []const sz.Type() = @alignCast(std.mem.bytesAsSlice(sz.Type(), without_null));
const formatter = if (sz == .@"1") std.zig.fmtEscapes(data_slice) else std.unicode.fmtUtf16le(data_slice);
try w.print("\"{}\"", .{formatter});
},
.@"4" => {
try w.writeByte('"');
const data_slice = std.mem.bytesAsSlice(u32, without_null);
var buf: [4]u8 = undefined;
for (data_slice) |item| {
if (item <= std.math.maxInt(u21) and std.unicode.utf8ValidCodepoint(@intCast(item))) {
const codepoint: u21 = @intCast(item);
const written = std.unicode.utf8Encode(codepoint, &buf) catch unreachable;
try w.print("{s}", .{buf[0..written]});
} else {
try w.print("\\x{x}", .{item});
}
}
try w.writeByte('"');
},
}
}

1111
deps/aro/aro/char_info.zig vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,627 @@
//! Adapted from the `unicode-ident` crate: https://github.com/dtolnay/unicode-ident
//! and Unicode Standard Annex #31 https://www.unicode.org/reports/tr31/
//! Licensed under the MIT License and the Unicode license
pub const chunk = 64;
pub const trie_start: [402]u8 align(8) = .{
0x04, 0x0B, 0x0F, 0x13, 0x17, 0x1B, 0x1F, 0x23, 0x27, 0x2D, 0x31, 0x34, 0x38, 0x3C, 0x40, 0x02,
0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x4D, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x51, 0x54, 0x58, 0x5C, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x60, 0x64, 0x66,
0x6A, 0x6E, 0x72, 0x28, 0x76, 0x78, 0x7C, 0x80, 0x84, 0x88, 0x8C, 0x90, 0x94, 0x98, 0x9E, 0xA2,
0x05, 0x2B, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x99, 0x05, 0x05, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0xB1, 0x00, 0xB5, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x32, 0x05, 0x05, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x43, 0xBB, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC8, 0x00, 0x00, 0x00, 0xAF,
0xCE, 0xD2, 0xD6, 0xBC, 0xDA, 0x00, 0x00, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0xE0, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x52, 0xE3, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0xE6, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0xE1, 0x05, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x05, 0xEB, 0x00, 0x00,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0xE4, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0xE7,
};
pub const trie_continue: [1793]u8 align(8) = .{
0x08, 0x0D, 0x11, 0x15, 0x19, 0x1D, 0x21, 0x25, 0x2A, 0x2F, 0x31, 0x36, 0x3A, 0x3E, 0x42, 0x02,
0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x4F, 0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x51, 0x56, 0x5A, 0x5E, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, 0x64, 0x68,
0x6C, 0x70, 0x74, 0x28, 0x76, 0x7A, 0x7E, 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9B, 0xA0, 0xA4,
0x05, 0x2B, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x99, 0x05, 0x05, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0xB3, 0x00, 0xB7, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x32, 0x05, 0x05, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x43, 0xBB, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA9, 0xAC, 0xC4, 0xC6, 0xCA, 0x00, 0xCC, 0x00, 0xAF,
0xD0, 0xD4, 0xD8, 0xBC, 0xDC, 0x00, 0x00, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0xE0, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x52, 0xE3, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0xE6, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0xE1, 0x05, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x05, 0xEB, 0x00, 0x00,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0xE4, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC2,
};
pub const leaf: [7584]u8 align(64) = .{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xAA, 0xFF, 0xFF, 0xFF, 0x3F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x5F, 0xDC, 0x1F, 0xCF, 0x0F, 0xFF, 0x1F, 0xDC, 0x1F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x04, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xA0, 0x04, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x7F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0x03, 0x00, 0x1F, 0x50, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xB8,
0x40, 0xD7, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0x03, 0x00, 0x1F, 0x50, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xB8,
0xC0, 0xD7, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x02, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x87, 0x07, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFB, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x02, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xB6, 0x00, 0xFF, 0xFF, 0xFF, 0x87, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xC0, 0xFE, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F, 0x00, 0x60, 0xC0, 0x00, 0x9C,
0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x02, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x07, 0x30, 0x04,
0x00, 0x00, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x9F, 0xFF, 0xFD, 0xFF, 0x9F,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x24,
0xFF, 0xFF, 0x3F, 0x04, 0x10, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0x07, 0xFF, 0xFF,
0xFF, 0x7E, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x23, 0x00, 0x00, 0x01, 0xFF, 0x03, 0x00, 0xFE, 0xFF,
0xE1, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xC5, 0x23, 0x00, 0x40, 0x00, 0xB0, 0x03, 0x00, 0x03, 0x10,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0x07, 0xFF, 0xFF,
0xFF, 0x7E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0xFF,
0xEF, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xC5, 0xF3, 0x9F, 0x79, 0x80, 0xB0, 0xCF, 0xFF, 0x03, 0x50,
0xE0, 0x87, 0xF9, 0xFF, 0xFF, 0xFD, 0x6D, 0x03, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x1C, 0x00,
0xE0, 0xBF, 0xFB, 0xFF, 0xFF, 0xFD, 0xED, 0x23, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x02,
0xE0, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xED, 0x23, 0x00, 0x00, 0x00, 0xB0, 0x03, 0x00, 0x02, 0x00,
0xE8, 0xC7, 0x3D, 0xD6, 0x18, 0xC7, 0xFF, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0xEE, 0x87, 0xF9, 0xFF, 0xFF, 0xFD, 0x6D, 0xD3, 0x87, 0x39, 0x02, 0x5E, 0xC0, 0xFF, 0x3F, 0x00,
0xEE, 0xBF, 0xFB, 0xFF, 0xFF, 0xFD, 0xED, 0xF3, 0xBF, 0x3B, 0x01, 0x00, 0xCF, 0xFF, 0x00, 0xFE,
0xEE, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xED, 0xF3, 0x9F, 0x39, 0xE0, 0xB0, 0xCF, 0xFF, 0x02, 0x00,
0xEC, 0xC7, 0x3D, 0xD6, 0x18, 0xC7, 0xFF, 0xC3, 0xC7, 0x3D, 0x81, 0x00, 0xC0, 0xFF, 0x00, 0x00,
0xE0, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xFF, 0x23, 0x00, 0x00, 0x00, 0x27, 0x03, 0x00, 0x00, 0x00,
0xE1, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xEF, 0x23, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x06, 0x00,
0xF0, 0xDF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0x27, 0x00, 0x40, 0x70, 0x80, 0x03, 0x00, 0x00, 0xFC,
0xE0, 0xFF, 0x7F, 0xFC, 0xFF, 0xFF, 0xFB, 0x2F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xFF, 0xF3, 0xDF, 0x3D, 0x60, 0x27, 0xCF, 0xFF, 0x00, 0x00,
0xEF, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xEF, 0xF3, 0xDF, 0x3D, 0x60, 0x60, 0xCF, 0xFF, 0x0E, 0x00,
0xFF, 0xDF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x7D, 0xF0, 0x80, 0xCF, 0xFF, 0x00, 0xFC,
0xEE, 0xFF, 0x7F, 0xFC, 0xFF, 0xFF, 0xFB, 0x2F, 0x7F, 0x84, 0x5F, 0xFF, 0xC0, 0xFF, 0x0C, 0x00,
0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xD6, 0xF7, 0xFF, 0xFF, 0xAF, 0xFF, 0x05, 0x20, 0x5F, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00,
0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0x7F, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
0xD6, 0xF7, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0x3F, 0x5F, 0x7F, 0xFF, 0xF3, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x03, 0xFF, 0x03, 0xA0, 0xC2, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF,
0xDF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x1F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x80, 0x00, 0x00, 0x3F, 0x3C, 0x62, 0xC0, 0xE1, 0xFF,
0x03, 0x40, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0x00, 0x00, 0x00,
0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3D, 0x7F, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0x3D, 0x7F, 0x3D, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3D, 0x7F, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0x3D, 0x7F, 0x3D, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x00, 0xFE, 0x03, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F,
0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF,
0xFE, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0x01,
0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xDF, 0x01, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF,
0xFE, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0x01,
0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF, 0x1F, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xDF, 0x0D, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x30, 0xFF, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00,
0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xB8, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00,
0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x0F, 0xFF, 0x0F, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF8, 0xFF, 0xFF, 0xFF, 0x01, 0xC0, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x9F,
0xFF, 0x03, 0xFF, 0x03, 0x80, 0x00, 0xFF, 0xBF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0x03, 0x00, 0xF8, 0x0F, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x3F,
0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0x6F, 0x04,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F,
0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0x07,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x27, 0x00, 0xF0, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80,
0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x84, 0xFC, 0x2F, 0x3F, 0x50, 0xFD, 0xFF, 0xF3, 0xE0, 0x43, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x80,
0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x1F, 0xE2, 0xFF, 0x01, 0x00,
0x84, 0xFC, 0x2F, 0x3F, 0x50, 0xFD, 0xFF, 0xF3, 0xE0, 0x43, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x78, 0x0C, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00,
0xFF, 0xFF, 0x7F, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xF8, 0x0F, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x80,
0xFF, 0xFF, 0x7F, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF,
0xE0, 0x00, 0x00, 0x00, 0xFE, 0x03, 0x3E, 0x1F, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x7F, 0xE0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7,
0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xE0, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x3E, 0x1F, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x7F, 0xE6, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x1F, 0xFF, 0xFF, 0x00, 0x0C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x80,
0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x80, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xEB, 0x03, 0x00, 0x00, 0xFC, 0xFF,
0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xBF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00,
0x00, 0x00, 0x80, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xEB, 0x03, 0x00, 0x00, 0xFC, 0xFF,
0xBB, 0xF7, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00,
0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x68,
0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x1F,
0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x80, 0x00, 0x00, 0xDF, 0xFF, 0x00, 0x7C,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xE8,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0x1F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x7F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF7, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0xC4,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x3E, 0x05, 0x00, 0x00, 0x38, 0xFF, 0x07, 0x1C, 0x00,
0x7E, 0x7E, 0x7E, 0x00, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x03, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0x3F, 0xFF, 0x03, 0xFF, 0xFF, 0x7F, 0xFC,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x38, 0xFF, 0xFF, 0x7C, 0x00,
0x7E, 0x7E, 0x7E, 0x00, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x03, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x37, 0xFF, 0x03,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
0x7F, 0x00, 0xF8, 0xA0, 0xFF, 0xFD, 0x7F, 0x5F, 0xDB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
0x7F, 0x00, 0xF8, 0xE0, 0xFF, 0xFD, 0x7F, 0x5F, 0xDB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xF0, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xAA,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xC0, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC, 0xFC, 0xFC, 0x1C, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xAA,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
0x00, 0x00, 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC, 0xFC, 0xFC, 0x1C, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xEF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xB7, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xEF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xB7, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00,
0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07,
0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xF7,
0xFF, 0xF7, 0xB7, 0xFF, 0xFB, 0xFF, 0xFB, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xF7,
0xFF, 0xF7, 0xB7, 0xFF, 0xFB, 0xFF, 0xFB, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x91, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x7F, 0x00,
0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x37, 0x00,
0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0xEF, 0xFE, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x1F,
0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x07, 0x00,
0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6F, 0xF0, 0xEF, 0xFE, 0xFF, 0xFF, 0x3F, 0x87, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x1F,
0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x07, 0x00,
0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x1F, 0x80, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0,
0xFF, 0xFF, 0xFF, 0x1F, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00,
0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00,
0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
0xF8, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x90, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0x00,
0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x1E, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x3F, 0x80,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x04, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0x03,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xDE, 0xFF, 0x17, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0x0F, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7F, 0xBD, 0xFF, 0xBF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00,
0xE0, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xED, 0x23, 0x00, 0x00, 0x01, 0xE0, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7F, 0xBD, 0xFF, 0xBF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0x03,
0xEF, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xED, 0xFB, 0x9F, 0x39, 0x81, 0xE0, 0xCF, 0x1F, 0x1F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x80, 0x07, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xC3, 0x03, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0x01, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x11, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0x0F, 0xFF, 0x03, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80,
0x7F, 0xF2, 0x6F, 0xFF, 0xFF, 0xFF, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x80,
0x7F, 0xF2, 0x6F, 0xFF, 0xFF, 0xFF, 0xBF, 0xF9, 0x0F, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x1B, 0x00, 0x00, 0x00,
0x01, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x04, 0x00, 0x00, 0x01, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x03, 0x00, 0x20, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x23, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x6F,
0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7F, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0xBF, 0xFD, 0xFF, 0xFF,
0xFF, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x01, 0x00, 0xFF, 0x03, 0x00, 0x00, 0xFC, 0xFF,
0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7F, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xB4, 0xFF, 0x00, 0xFF, 0x03, 0xBF, 0xFD, 0xFF, 0xFF,
0xFF, 0x7F, 0xFB, 0x01, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x07, 0x00,
0xF4, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00,
0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x07, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE3, 0x07, 0xF8,
0xE7, 0x0F, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x7F, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xE0,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x03, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x0F, 0x00, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0xE0,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x6F, 0xFF, 0x7F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0x1F,
0xFF, 0x01, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0x1F,
0xFF, 0x01, 0xFF, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xDF, 0x64, 0xDE, 0xFF, 0xEB, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xBF, 0xE7, 0xDF, 0xDF, 0xFF, 0xFF, 0xFF, 0x7B, 0x5F, 0xFC, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xF7,
0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF,
0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xF7,
0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF,
0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x20, 0x00,
0x10, 0x00, 0x00, 0xF8, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x80, 0x3F, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7F, 0xFF, 0xFF, 0xF9, 0xDB, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0x3F, 0xFF, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xEF, 0xFF, 0xFF, 0xFF, 0x96, 0xFE, 0xF7, 0x0A, 0x84, 0xEA, 0x96, 0xAA, 0x96, 0xF7, 0xF7, 0x5E,
0xFF, 0xFB, 0xFF, 0x0F, 0xEE, 0xFB, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

View File

@ -38,18 +38,18 @@ const Directive = enum {
fn beforePreprocess(pragma: *Pragma, comp: *Compilation) void {
var self = @fieldParentPtr(GCC, "pragma", pragma);
self.original_options = comp.diag.options;
self.original_options = comp.diagnostics.options;
}
fn beforeParse(pragma: *Pragma, comp: *Compilation) void {
var self = @fieldParentPtr(GCC, "pragma", pragma);
comp.diag.options = self.original_options;
comp.diagnostics.options = self.original_options;
self.options_stack.items.len = 0;
}
fn afterParse(pragma: *Pragma, comp: *Compilation) void {
var self = @fieldParentPtr(GCC, "pragma", pragma);
comp.diag.options = self.original_options;
comp.diagnostics.options = self.original_options;
self.options_stack.items.len = 0;
}
@ -76,7 +76,7 @@ fn diagnosticHandler(self: *GCC, pp: *Preprocessor, start_idx: TokenIndex) Pragm
.ignored, .warning, .@"error", .fatal => {
const str = Pragma.pasteTokens(pp, start_idx + 1) catch |err| switch (err) {
error.ExpectedStringLiteral => {
return pp.comp.diag.add(.{
return pp.comp.addDiagnostic(.{
.tag = .pragma_requires_string_literal,
.loc = diagnostic_tok.loc,
.extra = .{ .str = "GCC diagnostic" },
@ -86,24 +86,24 @@ fn diagnosticHandler(self: *GCC, pp: *Preprocessor, start_idx: TokenIndex) Pragm
};
if (!mem.startsWith(u8, str, "-W")) {
const next = pp.tokens.get(start_idx + 1);
return pp.comp.diag.add(.{
return pp.comp.addDiagnostic(.{
.tag = .malformed_warning_check,
.loc = next.loc,
.extra = .{ .str = "GCC diagnostic" },
}, next.expansionSlice());
}
const new_kind = switch (diagnostic) {
.ignored => Diagnostics.Kind.off,
.warning => Diagnostics.Kind.warning,
.@"error" => Diagnostics.Kind.@"error",
.fatal => Diagnostics.Kind.@"fatal error",
const new_kind: Diagnostics.Kind = switch (diagnostic) {
.ignored => .off,
.warning => .warning,
.@"error" => .@"error",
.fatal => .@"fatal error",
else => unreachable,
};
try pp.comp.diag.set(str[2..], new_kind);
try pp.comp.diagnostics.set(str[2..], new_kind);
},
.push => try self.options_stack.append(pp.comp.gpa, pp.comp.diag.options),
.pop => pp.comp.diag.options = self.options_stack.popOrNull() orelse self.original_options,
.push => try self.options_stack.append(pp.comp.gpa, pp.comp.diagnostics.options),
.pop => pp.comp.diagnostics.options = self.options_stack.popOrNull() orelse self.original_options,
}
}
@ -113,7 +113,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
if (directive_tok.id == .nl) return;
const gcc_pragma = std.meta.stringToEnum(Directive, pp.expandedSlice(directive_tok)) orelse
return pp.comp.diag.add(.{
return pp.comp.addDiagnostic(.{
.tag = .unknown_gcc_pragma,
.loc = directive_tok.loc,
}, directive_tok.expansionSlice());
@ -122,7 +122,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
.warning, .@"error" => {
const text = Pragma.pasteTokens(pp, start_idx + 2) catch |err| switch (err) {
error.ExpectedStringLiteral => {
return pp.comp.diag.add(.{
return pp.comp.addDiagnostic(.{
.tag = .pragma_requires_string_literal,
.loc = directive_tok.loc,
.extra = .{ .str = @tagName(gcc_pragma) },
@ -130,9 +130,9 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
},
else => |e| return e,
};
const extra = Diagnostics.Message.Extra{ .str = try pp.comp.diag.arena.allocator().dupe(u8, text) };
const extra = Diagnostics.Message.Extra{ .str = try pp.comp.diagnostics.arena.allocator().dupe(u8, text) };
const diagnostic_tag: Diagnostics.Tag = if (gcc_pragma == .warning) .pragma_warning_message else .pragma_error_message;
return pp.comp.diag.add(
return pp.comp.addDiagnostic(
.{ .tag = diagnostic_tag, .loc = directive_tok.loc, .extra = extra },
directive_tok.expansionSlice(),
);
@ -140,7 +140,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
.diagnostic => return self.diagnosticHandler(pp, start_idx + 2) catch |err| switch (err) {
error.UnknownPragma => {
const tok = pp.tokens.get(start_idx + 2);
return pp.comp.diag.add(.{
return pp.comp.addDiagnostic(.{
.tag = .unknown_gcc_pragma_directive,
.loc = tok.loc,
}, tok.expansionSlice());
@ -154,14 +154,14 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
if (tok.id == .nl) break;
if (!tok.id.isMacroIdentifier()) {
return pp.comp.diag.add(.{
return pp.comp.addDiagnostic(.{
.tag = .pragma_poison_identifier,
.loc = tok.loc,
}, tok.expansionSlice());
}
const str = pp.expandedSlice(tok);
if (pp.defines.get(str) != null) {
try pp.comp.diag.add(.{
try pp.comp.addDiagnostic(.{
.tag = .pragma_poison_macro,
.loc = tok.loc,
}, tok.expansionSlice());

View File

@ -22,7 +22,7 @@ pub fn init(allocator: mem.Allocator) !*Pragma {
}
fn deinit(pragma: *Pragma, comp: *Compilation) void {
var self = @fieldParentPtr(Message, "pragma", pragma);
const self = @fieldParentPtr(Message, "pragma", pragma);
comp.gpa.destroy(self);
}
@ -32,7 +32,7 @@ fn preprocessorHandler(_: *Pragma, pp: *Preprocessor, start_idx: TokenIndex) Pra
const str = Pragma.pasteTokens(pp, start_idx + 1) catch |err| switch (err) {
error.ExpectedStringLiteral => {
return pp.comp.diag.add(.{
return pp.comp.addDiagnostic(.{
.tag = .pragma_requires_string_literal,
.loc = message_tok.loc,
.extra = .{ .str = "message" },
@ -45,6 +45,6 @@ fn preprocessorHandler(_: *Pragma, pp: *Preprocessor, start_idx: TokenIndex) Pra
message_expansion_locs[message_expansion_locs.len - 1]
else
message_tok.loc;
const extra = Diagnostics.Message.Extra{ .str = try pp.comp.diag.arena.allocator().dupe(u8, str) };
return pp.comp.diag.add(.{ .tag = .pragma_message, .loc = loc, .extra = extra }, &.{});
const extra = Diagnostics.Message.Extra{ .str = try pp.comp.diagnostics.arena.allocator().dupe(u8, str) };
return pp.comp.addDiagnostic(.{ .tag = .pragma_message, .loc = loc, .extra = extra }, &.{});
}

View File

@ -42,7 +42,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
const name_tok = pp.tokens.get(start_idx);
const next = pp.tokens.get(start_idx + 1);
if (next.id != .nl) {
try pp.comp.diag.add(.{
try pp.comp.addDiagnostic(.{
.tag = .extra_tokens_directive_end,
.loc = name_tok.loc,
}, next.expansionSlice());

View File

@ -34,7 +34,7 @@ fn parserHandler(pragma: *Pragma, p: *Parser, start_idx: TokenIndex) Compilation
var idx = start_idx + 1;
const l_paren = p.pp.tokens.get(idx);
if (l_paren.id != .l_paren) {
return p.comp.diag.add(.{
return p.comp.addDiagnostic(.{
.tag = .pragma_pack_lparen,
.loc = l_paren.loc,
}, l_paren.expansionSlice());
@ -127,7 +127,7 @@ fn packInt(p: *Parser, tok_i: TokenIndex) Compilation.Error!?u8 {
},
else => |e| return e,
};
const int = if (res.val.tag == .int) res.val.getInt(u64) else 99;
const int = res.val.toInt(u64, p.comp) orelse 99;
switch (int) {
1, 2, 4, 8, 16 => return @intCast(int),
else => {

View File

@ -57,6 +57,7 @@ const SysVContext = struct {
fn layoutFields(self: *SysVContext, rec: *const Record) void {
for (rec.fields, 0..) |*fld, fld_indx| {
if (fld.ty.specifier == .invalid) continue;
const type_layout = computeLayout(fld.ty, self.comp);
var field_attrs: ?[]const Attribute = null;
@ -587,6 +588,7 @@ pub fn compute(rec: *Type.Record, ty: Type, comp: *const Compilation, pragma_pac
.msvc => {
var context = MsvcContext.init(ty, comp, pragma_pack);
for (rec.fields, 0..) |*fld, fld_indx| {
if (fld.ty.specifier == .invalid) continue;
var field_attrs: ?[]const Attribute = null;
if (rec.field_attributes) |attrs| {
field_attrs = attrs[fld_indx];

View File

@ -1,7 +1,7 @@
const std = @import("std");
const LangOpts = @import("LangOpts.zig");
const Type = @import("Type.zig");
const llvm = @import("zig").codegen.llvm;
const llvm = @import("root").codegen.llvm;
const TargetSet = @import("Builtins/Properties.zig").TargetSet;
/// intmax_t for this target
@ -258,6 +258,21 @@ pub fn systemCompiler(target: std.Target) LangOpts.Compiler {
return .clang;
}
pub fn hasFloat128(target: std.Target) bool {
if (target.cpu.arch.isWasm()) return true;
if (target.isDarwin()) return false;
if (target.cpu.arch.isPPC() or target.cpu.arch.isPPC64()) return std.Target.powerpc.featureSetHas(target.cpu.features, .float128);
return switch (target.os.tag) {
.dragonfly,
.haiku,
.linux,
.openbsd,
.solaris,
=> target.cpu.arch.isX86(),
else => false,
};
}
pub fn hasInt128(target: std.Target) bool {
if (target.cpu.arch == .wasm32) return true;
if (target.cpu.arch == .x86_64) return true;
@ -809,3 +824,8 @@ test "target size/align tests" {
try std.testing.expectEqual(@as(u64, 1), ct.alignof(&comp));
try std.testing.expectEqual(true, ignoreNonZeroSizedBitfieldTypeAlignment(comp.target));
}
/// The canonical integer representation of nullptr_t.
pub fn nullRepr(_: std.Target) u64 {
return 0;
}

View File

@ -132,7 +132,7 @@ pub const Kind = enum {
};
}
/// Required alignment within aro (on compiler host) for writing to retained_strings
/// Required alignment within aro (on compiler host) for writing to Interner.strings.
pub fn internalStorageAlignment(kind: Kind, comp: *const Compilation) usize {
return switch (kind.charUnitSize(comp)) {
inline else => |size| @alignOf(size.Type()),
@ -250,7 +250,7 @@ pub const Parser = struct {
self.i += expected_len;
if (overflowed) {
self.err(.escape_sequence_overflow, .{ .unsigned = start + self.prefixLen() });
self.err(.escape_sequence_overflow, .{ .offset = start + self.prefixLen() });
return null;
}
@ -260,7 +260,7 @@ pub const Parser = struct {
}
if (val > std.math.maxInt(u21) or !std.unicode.utf8ValidCodepoint(@intCast(val))) {
self.err(.invalid_universal_character, .{ .unsigned = start + self.prefixLen() });
self.err(.invalid_universal_character, .{ .offset = start + self.prefixLen() });
return null;
}
@ -270,7 +270,7 @@ pub const Parser = struct {
}
if (val < 0xA0 and (val != '$' and val != '@' and val != '`')) {
const is_error = !self.comp.langopts.standard.atLeast(.c2x);
const is_error = !self.comp.langopts.standard.atLeast(.c23);
if (val >= 0x20 and val <= 0x7F) {
if (is_error) {
self.err(.ucn_basic_char_error, .{ .ascii = @intCast(val) });
@ -347,7 +347,7 @@ pub const Parser = struct {
count += 1;
}
if (overflowed or val > self.kind.maxInt(self.comp)) {
self.err(.escape_sequence_overflow, .{ .unsigned = start + self.prefixLen() });
self.err(.escape_sequence_overflow, .{ .offset = start + self.prefixLen() });
return 0;
}
if (count == 0) {

View File

@ -385,6 +385,7 @@ test Linux {
comp.environment = .{
.path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
};
defer comp.environment = .{};
const raw_triple = "x86_64-linux-gnu";
const cross = std.zig.CrossTarget.parse(.{ .arch_os_abi = raw_triple }) catch unreachable;

310
deps/aro/aro/tracy.zig vendored Normal file
View File

@ -0,0 +1,310 @@
//! Copied from https://github.com/ziglang/zig/blob/c9006d9479c619d9ed555164831e11a04d88d382/src/tracy.zig
const std = @import("std");
const builtin = @import("builtin");
const build_options = @import("build_options");
pub const enable = if (builtin.is_test) false else build_options.enable_tracy;
pub const enable_allocation = enable and build_options.enable_tracy_allocation;
pub const enable_callstack = enable and build_options.enable_tracy_callstack;
// TODO: make this configurable
const callstack_depth = 10;
const ___tracy_c_zone_context = extern struct {
id: u32,
active: c_int,
pub inline fn end(self: @This()) void {
___tracy_emit_zone_end(self);
}
pub inline fn addText(self: @This(), text: []const u8) void {
___tracy_emit_zone_text(self, text.ptr, text.len);
}
pub inline fn setName(self: @This(), name: []const u8) void {
___tracy_emit_zone_name(self, name.ptr, name.len);
}
pub inline fn setColor(self: @This(), color: u32) void {
___tracy_emit_zone_color(self, color);
}
pub inline fn setValue(self: @This(), value: u64) void {
___tracy_emit_zone_value(self, value);
}
};
pub const Ctx = if (enable) ___tracy_c_zone_context else struct {
pub inline fn end(self: @This()) void {
_ = self;
}
pub inline fn addText(self: @This(), text: []const u8) void {
_ = self;
_ = text;
}
pub inline fn setName(self: @This(), name: []const u8) void {
_ = self;
_ = name;
}
pub inline fn setColor(self: @This(), color: u32) void {
_ = self;
_ = color;
}
pub inline fn setValue(self: @This(), value: u64) void {
_ = self;
_ = value;
}
};
pub inline fn trace(comptime src: std.builtin.SourceLocation) Ctx {
if (!enable) return .{};
if (enable_callstack) {
return ___tracy_emit_zone_begin_callstack(&.{
.name = null,
.function = src.fn_name.ptr,
.file = src.file.ptr,
.line = src.line,
.color = 0,
}, callstack_depth, 1);
} else {
return ___tracy_emit_zone_begin(&.{
.name = null,
.function = src.fn_name.ptr,
.file = src.file.ptr,
.line = src.line,
.color = 0,
}, 1);
}
}
pub inline fn traceNamed(comptime src: std.builtin.SourceLocation, comptime name: [:0]const u8) Ctx {
if (!enable) return .{};
if (enable_callstack) {
return ___tracy_emit_zone_begin_callstack(&.{
.name = name.ptr,
.function = src.fn_name.ptr,
.file = src.file.ptr,
.line = src.line,
.color = 0,
}, callstack_depth, 1);
} else {
return ___tracy_emit_zone_begin(&.{
.name = name.ptr,
.function = src.fn_name.ptr,
.file = src.file.ptr,
.line = src.line,
.color = 0,
}, 1);
}
}
pub fn tracyAllocator(allocator: std.mem.Allocator) TracyAllocator(null) {
return TracyAllocator(null).init(allocator);
}
pub fn TracyAllocator(comptime name: ?[:0]const u8) type {
return struct {
parent_allocator: std.mem.Allocator,
const Self = @This();
pub fn init(parent_allocator: std.mem.Allocator) Self {
return .{
.parent_allocator = parent_allocator,
};
}
pub fn allocator(self: *Self) std.mem.Allocator {
return std.mem.Allocator.init(self, allocFn, resizeFn, freeFn);
}
fn allocFn(self: *Self, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) std.mem.Allocator.Error![]u8 {
const result = self.parent_allocator.rawAlloc(len, ptr_align, len_align, ret_addr);
if (result) |data| {
if (data.len != 0) {
if (name) |n| {
allocNamed(data.ptr, data.len, n);
} else {
alloc(data.ptr, data.len);
}
}
} else |_| {
messageColor("allocation failed", 0xFF0000);
}
return result;
}
fn resizeFn(self: *Self, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize {
if (self.parent_allocator.rawResize(buf, buf_align, new_len, len_align, ret_addr)) |resized_len| {
if (name) |n| {
freeNamed(buf.ptr, n);
allocNamed(buf.ptr, resized_len, n);
} else {
free(buf.ptr);
alloc(buf.ptr, resized_len);
}
return resized_len;
}
// during normal operation the compiler hits this case thousands of times due to this
// emitting messages for it is both slow and causes clutter
return null;
}
fn freeFn(self: *Self, buf: []u8, buf_align: u29, ret_addr: usize) void {
self.parent_allocator.rawFree(buf, buf_align, ret_addr);
// this condition is to handle free being called on an empty slice that was never even allocated
// example case: `std.process.getSelfExeSharedLibPaths` can return `&[_][:0]u8{}`
if (buf.len != 0) {
if (name) |n| {
freeNamed(buf.ptr, n);
} else {
free(buf.ptr);
}
}
}
};
}
// This function only accepts comptime known strings, see `messageCopy` for runtime strings
pub inline fn message(comptime msg: [:0]const u8) void {
if (!enable) return;
___tracy_emit_messageL(msg.ptr, if (enable_callstack) callstack_depth else 0);
}
// This function only accepts comptime known strings, see `messageColorCopy` for runtime strings
pub inline fn messageColor(comptime msg: [:0]const u8, color: u32) void {
if (!enable) return;
___tracy_emit_messageLC(msg.ptr, color, if (enable_callstack) callstack_depth else 0);
}
pub inline fn messageCopy(msg: []const u8) void {
if (!enable) return;
___tracy_emit_message(msg.ptr, msg.len, if (enable_callstack) callstack_depth else 0);
}
pub inline fn messageColorCopy(msg: [:0]const u8, color: u32) void {
if (!enable) return;
___tracy_emit_messageC(msg.ptr, msg.len, color, if (enable_callstack) callstack_depth else 0);
}
pub inline fn frameMark() void {
if (!enable) return;
___tracy_emit_frame_mark(null);
}
pub inline fn frameMarkNamed(comptime name: [:0]const u8) void {
if (!enable) return;
___tracy_emit_frame_mark(name.ptr);
}
pub inline fn namedFrame(comptime name: [:0]const u8) Frame(name) {
frameMarkStart(name);
return .{};
}
pub fn Frame(comptime name: [:0]const u8) type {
return struct {
pub fn end(_: @This()) void {
frameMarkEnd(name);
}
};
}
inline fn frameMarkStart(comptime name: [:0]const u8) void {
if (!enable) return;
___tracy_emit_frame_mark_start(name.ptr);
}
inline fn frameMarkEnd(comptime name: [:0]const u8) void {
if (!enable) return;
___tracy_emit_frame_mark_end(name.ptr);
}
extern fn ___tracy_emit_frame_mark_start(name: [*:0]const u8) void;
extern fn ___tracy_emit_frame_mark_end(name: [*:0]const u8) void;
inline fn alloc(ptr: [*]u8, len: usize) void {
if (!enable) return;
if (enable_callstack) {
___tracy_emit_memory_alloc_callstack(ptr, len, callstack_depth, 0);
} else {
___tracy_emit_memory_alloc(ptr, len, 0);
}
}
inline fn allocNamed(ptr: [*]u8, len: usize, comptime name: [:0]const u8) void {
if (!enable) return;
if (enable_callstack) {
___tracy_emit_memory_alloc_callstack_named(ptr, len, callstack_depth, 0, name.ptr);
} else {
___tracy_emit_memory_alloc_named(ptr, len, 0, name.ptr);
}
}
inline fn free(ptr: [*]u8) void {
if (!enable) return;
if (enable_callstack) {
___tracy_emit_memory_free_callstack(ptr, callstack_depth, 0);
} else {
___tracy_emit_memory_free(ptr, 0);
}
}
inline fn freeNamed(ptr: [*]u8, comptime name: [:0]const u8) void {
if (!enable) return;
if (enable_callstack) {
___tracy_emit_memory_free_callstack_named(ptr, callstack_depth, 0, name.ptr);
} else {
___tracy_emit_memory_free_named(ptr, 0, name.ptr);
}
}
extern fn ___tracy_emit_zone_begin(
srcloc: *const ___tracy_source_location_data,
active: c_int,
) ___tracy_c_zone_context;
extern fn ___tracy_emit_zone_begin_callstack(
srcloc: *const ___tracy_source_location_data,
depth: c_int,
active: c_int,
) ___tracy_c_zone_context;
extern fn ___tracy_emit_zone_text(ctx: ___tracy_c_zone_context, txt: [*]const u8, size: usize) void;
extern fn ___tracy_emit_zone_name(ctx: ___tracy_c_zone_context, txt: [*]const u8, size: usize) void;
extern fn ___tracy_emit_zone_color(ctx: ___tracy_c_zone_context, color: u32) void;
extern fn ___tracy_emit_zone_value(ctx: ___tracy_c_zone_context, value: u64) void;
extern fn ___tracy_emit_zone_end(ctx: ___tracy_c_zone_context) void;
extern fn ___tracy_emit_memory_alloc(ptr: *const anyopaque, size: usize, secure: c_int) void;
extern fn ___tracy_emit_memory_alloc_callstack(ptr: *const anyopaque, size: usize, depth: c_int, secure: c_int) void;
extern fn ___tracy_emit_memory_free(ptr: *const anyopaque, secure: c_int) void;
extern fn ___tracy_emit_memory_free_callstack(ptr: *const anyopaque, depth: c_int, secure: c_int) void;
extern fn ___tracy_emit_memory_alloc_named(ptr: *const anyopaque, size: usize, secure: c_int, name: [*:0]const u8) void;
extern fn ___tracy_emit_memory_alloc_callstack_named(ptr: *const anyopaque, size: usize, depth: c_int, secure: c_int, name: [*:0]const u8) void;
extern fn ___tracy_emit_memory_free_named(ptr: *const anyopaque, secure: c_int, name: [*:0]const u8) void;
extern fn ___tracy_emit_memory_free_callstack_named(ptr: *const anyopaque, depth: c_int, secure: c_int, name: [*:0]const u8) void;
extern fn ___tracy_emit_message(txt: [*]const u8, size: usize, callstack: c_int) void;
extern fn ___tracy_emit_messageL(txt: [*:0]const u8, callstack: c_int) void;
extern fn ___tracy_emit_messageC(txt: [*]const u8, size: usize, color: u32, callstack: c_int) void;
extern fn ___tracy_emit_messageLC(txt: [*:0]const u8, color: u32, callstack: c_int) void;
extern fn ___tracy_emit_frame_mark(name: ?[*:0]const u8) void;
const ___tracy_source_location_data = extern struct {
name: ?[*:0]const u8,
function: [*:0]const u8,
file: [*:0]const u8,
line: u32,
color: u32,
};

13
deps/aro/backend.zig vendored Normal file
View File

@ -0,0 +1,13 @@
pub const Interner = @import("backend/Interner.zig");
pub const Ir = @import("backend/Ir.zig");
pub const Object = @import("backend/Object.zig");
pub const CallingConvention = enum {
C,
stdcall,
thiscall,
vectorcall,
};
pub const version_str = @import("build_options").version_str;
pub const version = @import("std").SemanticVersion.parse(version_str) catch unreachable;

647
deps/aro/backend/Interner.zig vendored Normal file
View File

@ -0,0 +1,647 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const BigIntConst = std.math.big.int.Const;
const BigIntMutable = std.math.big.int.Mutable;
const Hash = std.hash.Wyhash;
const Limb = std.math.big.Limb;
const Interner = @This();
map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
items: std.MultiArrayList(struct {
tag: Tag,
data: u32,
}) = .{},
extra: std.ArrayListUnmanaged(u32) = .{},
limbs: std.ArrayListUnmanaged(Limb) = .{},
strings: std.ArrayListUnmanaged(u8) = .{},
const KeyAdapter = struct {
interner: *const Interner,
pub fn eql(adapter: KeyAdapter, a: Key, b_void: void, b_map_index: usize) bool {
_ = b_void;
return adapter.interner.get(@as(Ref, @enumFromInt(b_map_index))).eql(a);
}
pub fn hash(adapter: KeyAdapter, a: Key) u32 {
_ = adapter;
return a.hash();
}
};
pub const Key = union(enum) {
int_ty: u16,
float_ty: u16,
ptr_ty,
noreturn_ty,
void_ty,
func_ty,
array_ty: struct {
len: u64,
child: Ref,
},
vector_ty: struct {
len: u32,
child: Ref,
},
record_ty: []const Ref,
/// May not be zero
null,
int: union(enum) {
u64: u64,
i64: i64,
big_int: BigIntConst,
pub fn toBigInt(repr: @This(), space: *Tag.Int.BigIntSpace) BigIntConst {
return switch (repr) {
.big_int => |x| x,
inline .u64, .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(),
};
}
},
float: Float,
bytes: []const u8,
pub const Float = union(enum) {
f16: f16,
f32: f32,
f64: f64,
f80: f80,
f128: f128,
};
pub fn hash(key: Key) u32 {
var hasher = Hash.init(0);
const tag = std.meta.activeTag(key);
std.hash.autoHash(&hasher, tag);
switch (key) {
.bytes => |bytes| {
hasher.update(bytes);
},
.record_ty => |elems| for (elems) |elem| {
std.hash.autoHash(&hasher, elem);
},
.float => |repr| switch (repr) {
inline else => |data| std.hash.autoHash(
&hasher,
@as(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(data))), @bitCast(data)),
),
},
.int => |repr| {
var space: Tag.Int.BigIntSpace = undefined;
const big = repr.toBigInt(&space);
std.hash.autoHash(&hasher, big.positive);
for (big.limbs) |limb| std.hash.autoHash(&hasher, limb);
},
inline else => |info| {
std.hash.autoHash(&hasher, info);
},
}
return @truncate(hasher.final());
}
pub fn eql(a: Key, b: Key) bool {
const KeyTag = std.meta.Tag(Key);
const a_tag: KeyTag = a;
const b_tag: KeyTag = b;
if (a_tag != b_tag) return false;
switch (a) {
.record_ty => |a_elems| {
const b_elems = b.record_ty;
if (a_elems.len != b_elems.len) return false;
for (a_elems, b_elems) |a_elem, b_elem| {
if (a_elem != b_elem) return false;
}
return true;
},
.bytes => |a_bytes| {
const b_bytes = b.bytes;
return std.mem.eql(u8, a_bytes, b_bytes);
},
.int => |a_repr| {
var a_space: Tag.Int.BigIntSpace = undefined;
const a_big = a_repr.toBigInt(&a_space);
var b_space: Tag.Int.BigIntSpace = undefined;
const b_big = b.int.toBigInt(&b_space);
return a_big.eql(b_big);
},
inline else => |a_info, tag| {
const b_info = @field(b, @tagName(tag));
return std.meta.eql(a_info, b_info);
},
}
}
fn toRef(key: Key) ?Ref {
switch (key) {
.int_ty => |bits| switch (bits) {
1 => return .i1,
8 => return .i8,
16 => return .i16,
32 => return .i32,
64 => return .i64,
128 => return .i128,
else => {},
},
.float_ty => |bits| switch (bits) {
16 => return .f16,
32 => return .f32,
64 => return .f64,
80 => return .f80,
128 => return .f128,
else => unreachable,
},
.ptr_ty => return .ptr,
.func_ty => return .func,
.noreturn_ty => return .noreturn,
.void_ty => return .void,
.int => |repr| {
var space: Tag.Int.BigIntSpace = undefined;
const big = repr.toBigInt(&space);
if (big.eqlZero()) return .zero;
const big_one = BigIntConst{ .limbs = &.{1}, .positive = true };
if (big.eql(big_one)) return .one;
},
.float => |repr| switch (repr) {
inline else => |data| {
if (std.math.isPositiveZero(data)) return .zero;
if (data == 1) return .one;
},
},
.null => return .null,
else => {},
}
return null;
}
};
pub const Ref = enum(u32) {
const max = std.math.maxInt(u32);
ptr = max - 1,
noreturn = max - 2,
void = max - 3,
i1 = max - 4,
i8 = max - 5,
i16 = max - 6,
i32 = max - 7,
i64 = max - 8,
i128 = max - 9,
f16 = max - 10,
f32 = max - 11,
f64 = max - 12,
f80 = max - 13,
f128 = max - 14,
func = max - 15,
zero = max - 16,
one = max - 17,
null = max - 18,
_,
};
pub const OptRef = enum(u32) {
const max = std.math.maxInt(u32);
none = max - 0,
ptr = max - 1,
noreturn = max - 2,
void = max - 3,
i1 = max - 4,
i8 = max - 5,
i16 = max - 6,
i32 = max - 7,
i64 = max - 8,
i128 = max - 9,
f16 = max - 10,
f32 = max - 11,
f64 = max - 12,
f80 = max - 13,
f128 = max - 14,
func = max - 15,
zero = max - 16,
one = max - 17,
null = max - 18,
_,
};
pub const Tag = enum(u8) {
/// `data` is `u16`
int_ty,
/// `data` is `u16`
float_ty,
/// `data` is index to `Array`
array_ty,
/// `data` is index to `Vector`
vector_ty,
/// `data` is `u32`
u32,
/// `data` is `i32`
i32,
/// `data` is `Int`
int_positive,
/// `data` is `Int`
int_negative,
/// `data` is `f16`
f16,
/// `data` is `f32`
f32,
/// `data` is `F64`
f64,
/// `data` is `F80`
f80,
/// `data` is `F128`
f128,
/// `data` is `Bytes`
bytes,
/// `data` is `Record`
record_ty,
pub const Array = struct {
len0: u32,
len1: u32,
child: Ref,
pub fn getLen(a: Array) u64 {
return (PackedU64{
.a = a.len0,
.b = a.len1,
}).get();
}
};
pub const Vector = struct {
len: u32,
child: Ref,
};
pub const Int = struct {
limbs_index: u32,
limbs_len: u32,
/// Big enough to fit any non-BigInt value
pub const BigIntSpace = struct {
/// The +1 is headroom so that operations such as incrementing once
/// or decrementing once are possible without using an allocator.
limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb,
};
};
pub const F64 = struct {
piece0: u32,
piece1: u32,
pub fn get(self: F64) f64 {
const int_bits = @as(u64, self.piece0) | (@as(u64, self.piece1) << 32);
return @bitCast(int_bits);
}
fn pack(val: f64) F64 {
const bits = @as(u64, @bitCast(val));
return .{
.piece0 = @as(u32, @truncate(bits)),
.piece1 = @as(u32, @truncate(bits >> 32)),
};
}
};
pub const F80 = struct {
piece0: u32,
piece1: u32,
piece2: u32, // u16 part, top bits
pub fn get(self: F80) f80 {
const int_bits = @as(u80, self.piece0) |
(@as(u80, self.piece1) << 32) |
(@as(u80, self.piece2) << 64);
return @bitCast(int_bits);
}
fn pack(val: f80) F80 {
const bits = @as(u80, @bitCast(val));
return .{
.piece0 = @as(u32, @truncate(bits)),
.piece1 = @as(u32, @truncate(bits >> 32)),
.piece2 = @as(u16, @truncate(bits >> 64)),
};
}
};
pub const F128 = struct {
piece0: u32,
piece1: u32,
piece2: u32,
piece3: u32,
pub fn get(self: F128) f128 {
const int_bits = @as(u128, self.piece0) |
(@as(u128, self.piece1) << 32) |
(@as(u128, self.piece2) << 64) |
(@as(u128, self.piece3) << 96);
return @bitCast(int_bits);
}
fn pack(val: f128) F128 {
const bits = @as(u128, @bitCast(val));
return .{
.piece0 = @as(u32, @truncate(bits)),
.piece1 = @as(u32, @truncate(bits >> 32)),
.piece2 = @as(u32, @truncate(bits >> 64)),
.piece3 = @as(u32, @truncate(bits >> 96)),
};
}
};
pub const Bytes = struct {
strings_index: u32,
len: u32,
};
pub const Record = struct {
elements_len: u32,
// trailing
// [elements_len]Ref
};
};
pub const PackedU64 = packed struct(u64) {
a: u32,
b: u32,
pub fn get(x: PackedU64) u64 {
return @bitCast(x);
}
pub fn init(x: u64) PackedU64 {
return @bitCast(x);
}
};
pub fn deinit(i: *Interner, gpa: Allocator) void {
i.map.deinit(gpa);
i.items.deinit(gpa);
i.extra.deinit(gpa);
i.limbs.deinit(gpa);
i.strings.deinit(gpa);
}
pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {
if (key.toRef()) |some| return some;
const adapter: KeyAdapter = .{ .interner = i };
const gop = try i.map.getOrPutAdapted(gpa, key, adapter);
if (gop.found_existing) return @enumFromInt(gop.index);
try i.items.ensureUnusedCapacity(gpa, 1);
switch (key) {
.int_ty => |bits| {
i.items.appendAssumeCapacity(.{
.tag = .int_ty,
.data = bits,
});
},
.float_ty => |bits| {
i.items.appendAssumeCapacity(.{
.tag = .float_ty,
.data = bits,
});
},
.array_ty => |info| {
const split_len = PackedU64.init(info.len);
i.items.appendAssumeCapacity(.{
.tag = .array_ty,
.data = try i.addExtra(gpa, Tag.Array{
.len0 = split_len.a,
.len1 = split_len.b,
.child = info.child,
}),
});
},
.vector_ty => |info| {
i.items.appendAssumeCapacity(.{
.tag = .vector_ty,
.data = try i.addExtra(gpa, Tag.Vector{
.len = info.len,
.child = info.child,
}),
});
},
.int => |repr| int: {
var space: Tag.Int.BigIntSpace = undefined;
const big = repr.toBigInt(&space);
switch (repr) {
.u64 => |data| if (std.math.cast(u32, data)) |small| {
i.items.appendAssumeCapacity(.{
.tag = .u32,
.data = small,
});
break :int;
},
.i64 => |data| if (std.math.cast(i32, data)) |small| {
i.items.appendAssumeCapacity(.{
.tag = .i32,
.data = @bitCast(small),
});
break :int;
},
.big_int => |data| {
if (data.fitsInTwosComp(.unsigned, 32)) {
i.items.appendAssumeCapacity(.{
.tag = .u32,
.data = data.to(u32) catch unreachable,
});
break :int;
} else if (data.fitsInTwosComp(.signed, 32)) {
i.items.appendAssumeCapacity(.{
.tag = .i32,
.data = @bitCast(data.to(i32) catch unreachable),
});
break :int;
}
},
}
const limbs_index: u32 = @intCast(i.limbs.items.len);
try i.limbs.appendSlice(gpa, big.limbs);
i.items.appendAssumeCapacity(.{
.tag = if (big.positive) .int_positive else .int_negative,
.data = try i.addExtra(gpa, Tag.Int{
.limbs_index = limbs_index,
.limbs_len = @intCast(big.limbs.len),
}),
});
},
.float => |repr| switch (repr) {
.f16 => |data| i.items.appendAssumeCapacity(.{
.tag = .f16,
.data = @as(u16, @bitCast(data)),
}),
.f32 => |data| i.items.appendAssumeCapacity(.{
.tag = .f32,
.data = @as(u32, @bitCast(data)),
}),
.f64 => |data| i.items.appendAssumeCapacity(.{
.tag = .f64,
.data = try i.addExtra(gpa, Tag.F64.pack(data)),
}),
.f80 => |data| i.items.appendAssumeCapacity(.{
.tag = .f64,
.data = try i.addExtra(gpa, Tag.F80.pack(data)),
}),
.f128 => |data| i.items.appendAssumeCapacity(.{
.tag = .f64,
.data = try i.addExtra(gpa, Tag.F128.pack(data)),
}),
},
.bytes => |bytes| {
const strings_index: u32 = @intCast(i.strings.items.len);
try i.strings.appendSlice(gpa, bytes);
i.items.appendAssumeCapacity(.{
.tag = .bytes,
.data = try i.addExtra(gpa, Tag.Bytes{
.strings_index = strings_index,
.len = @intCast(bytes.len),
}),
});
},
.record_ty => |elems| {
try i.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.Record).Struct.fields.len +
elems.len);
i.items.appendAssumeCapacity(.{
.tag = .record_ty,
.data = i.addExtraAssumeCapacity(Tag.Record{
.elements_len = @intCast(elems.len),
}),
});
i.extra.appendSliceAssumeCapacity(@ptrCast(elems));
},
.ptr_ty,
.noreturn_ty,
.void_ty,
.func_ty,
.null,
=> unreachable,
}
return @enumFromInt(gop.index);
}
fn addExtra(i: *Interner, gpa: Allocator, extra: anytype) Allocator.Error!u32 {
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
try i.extra.ensureUnusedCapacity(gpa, fields.len);
return i.addExtraAssumeCapacity(extra);
}
fn addExtraAssumeCapacity(i: *Interner, extra: anytype) u32 {
const result = @as(u32, @intCast(i.extra.items.len));
inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
i.extra.appendAssumeCapacity(switch (field.type) {
Ref => @intFromEnum(@field(extra, field.name)),
u32 => @field(extra, field.name),
else => @compileError("bad field type: " ++ @typeName(field.type)),
});
}
return result;
}
pub fn get(i: *const Interner, ref: Ref) Key {
switch (ref) {
.ptr => return .ptr_ty,
.func => return .func_ty,
.noreturn => return .noreturn_ty,
.void => return .void_ty,
.i1 => return .{ .int_ty = 1 },
.i8 => return .{ .int_ty = 8 },
.i16 => return .{ .int_ty = 16 },
.i32 => return .{ .int_ty = 32 },
.i64 => return .{ .int_ty = 64 },
.i128 => return .{ .int_ty = 128 },
.f16 => return .{ .float_ty = 16 },
.f32 => return .{ .float_ty = 32 },
.f64 => return .{ .float_ty = 64 },
.f80 => return .{ .float_ty = 80 },
.f128 => return .{ .float_ty = 128 },
.zero => return .{ .int = .{ .u64 = 0 } },
.one => return .{ .int = .{ .u64 = 1 } },
.null => return .null,
else => {},
}
const item = i.items.get(@intFromEnum(ref));
const data = item.data;
return switch (item.tag) {
.int_ty => .{ .int_ty = @intCast(data) },
.float_ty => .{ .float_ty = @intCast(data) },
.array_ty => {
const array_ty = i.extraData(Tag.Array, data);
return .{ .array_ty = .{
.len = array_ty.getLen(),
.child = array_ty.child,
} };
},
.vector_ty => {
const vector_ty = i.extraData(Tag.Vector, data);
return .{ .vector_ty = .{
.len = vector_ty.len,
.child = vector_ty.child,
} };
},
.u32 => .{ .int = .{ .u64 = data } },
.i32 => .{ .int = .{ .i64 = @as(i32, @bitCast(data)) } },
.int_positive, .int_negative => {
const int_info = i.extraData(Tag.Int, data);
const limbs = i.limbs.items[int_info.limbs_index..][0..int_info.limbs_len];
return .{ .int = .{
.big_int = .{
.positive = item.tag == .int_positive,
.limbs = limbs,
},
} };
},
.f16 => .{ .float = .{ .f16 = @bitCast(@as(u16, @intCast(data))) } },
.f32 => .{ .float = .{ .f32 = @bitCast(data) } },
.f64 => {
const float = i.extraData(Tag.F64, data);
return .{ .float = .{ .f64 = float.get() } };
},
.f80 => {
const float = i.extraData(Tag.F80, data);
return .{ .float = .{ .f80 = float.get() } };
},
.f128 => {
const float = i.extraData(Tag.F128, data);
return .{ .float = .{ .f128 = float.get() } };
},
.bytes => {
const bytes = i.extraData(Tag.Bytes, data);
return .{ .bytes = i.strings.items[bytes.strings_index..][0..bytes.len] };
},
.record_ty => {
const extra = i.extraDataTrail(Tag.Record, data);
return .{
.record_ty = @ptrCast(i.extra.items[extra.end..][0..extra.data.elements_len]),
};
},
};
}
fn extraData(i: *const Interner, comptime T: type, index: usize) T {
return i.extraDataTrail(T, index).data;
}
fn extraDataTrail(i: *const Interner, comptime T: type, index: usize) struct { data: T, end: u32 } {
var result: T = undefined;
const fields = @typeInfo(T).Struct.fields;
inline for (fields, 0..) |field, field_i| {
const int32 = i.extra.items[field_i + index];
@field(result, field.name) = switch (field.type) {
Ref => @enumFromInt(int32),
u32 => int32,
else => @compileError("bad field type: " ++ @typeName(field.type)),
};
}
return .{
.data = result,
.end = @intCast(index + fields.len),
};
}

View File

@ -1,51 +1,79 @@
const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Compilation = @import("Compilation.zig");
const assert = std.debug.assert;
const Interner = @import("Interner.zig");
const StringId = @import("StringInterner.zig").StringId;
const Value = @import("Value.zig");
const Object = @import("Object.zig");
const Ir = @This();
pool: Interner,
strings: []const u8,
// decls: std.StringArrayHashMapUnmanaged(Decl),
interner: *Interner,
decls: std.StringArrayHashMapUnmanaged(Decl),
// pub const Decl = struct {
instructions: std.MultiArrayList(Inst),
body: std.ArrayListUnmanaged(Ref),
arena: std.heap.ArenaAllocator.State,
// };
pub const Decl = struct {
instructions: std.MultiArrayList(Inst),
body: std.ArrayListUnmanaged(Ref),
arena: std.heap.ArenaAllocator.State,
pub fn deinit(decl: *Decl, gpa: Allocator) void {
decl.instructions.deinit(gpa);
decl.body.deinit(gpa);
decl.arena.promote(gpa).deinit();
}
};
pub const Builder = struct {
gpa: Allocator,
arena: std.heap.ArenaAllocator,
interner: *Interner,
decls: std.StringArrayHashMapUnmanaged(Decl) = .{},
instructions: std.MultiArrayList(Ir.Inst) = .{},
body: std.ArrayListUnmanaged(Ref) = .{},
alloc_count: u32 = 0,
arg_count: u32 = 0,
pool: Interner = .{},
current_label: Ref = undefined,
pub fn deinit(b: *Builder) void {
for (b.decls.values()) |*decl| {
decl.deinit(b.gpa);
}
b.arena.deinit();
b.instructions.deinit(b.gpa);
b.body.deinit(b.gpa);
b.pool.deinit(b.gpa);
b.* = undefined;
}
pub fn finish(b: *Builder) Ir {
return .{
.interner = b.interner,
.decls = b.decls.move(),
};
}
pub fn startFn(b: *Builder) Allocator.Error!void {
b.alloc_count = 0;
b.arg_count = 0;
b.instructions.len = 0;
b.body.items.len = 0;
const entry = try b.makeLabel("entry");
try b.body.append(b.gpa, entry);
b.current_label = entry;
}
pub fn finishFn(b: *Builder, name: []const u8) !void {
var duped_instructions = try b.instructions.clone(b.gpa);
errdefer duped_instructions.deinit(b.gpa);
var duped_body = try b.body.clone(b.gpa);
errdefer duped_body.deinit(b.gpa);
try b.decls.put(b.gpa, name, .{
.instructions = duped_instructions,
.body = duped_body,
.arena = b.arena.state,
});
b.instructions.shrinkRetainingCapacity(0);
b.body.shrinkRetainingCapacity(0);
b.arena = std.heap.ArenaAllocator.init(b.gpa);
b.alloc_count = 0;
b.arg_count = 0;
}
pub fn startBlock(b: *Builder, label: Ref) !void {
try b.body.append(b.gpa, label);
b.current_label = label;
@ -116,15 +144,13 @@ pub const Builder = struct {
_ = try b.addInst(.store, .{ .bin = .{ .lhs = ptr, .rhs = val } }, .void);
}
pub fn addConstant(b: *Builder, val: Value, ty: Interner.Ref) Allocator.Error!Ref {
pub fn addConstant(b: *Builder, val: Interner.Ref, ty: Interner.Ref) Allocator.Error!Ref {
const ref: Ref = @enumFromInt(b.instructions.len);
const key: Interner.Key = .{
.value = val,
};
const val_ref = try b.pool.put(b.gpa, key);
try b.instructions.append(b.gpa, .{ .tag = .constant, .data = .{
.constant = val_ref,
}, .ty = ty });
try b.instructions.append(b.gpa, .{
.tag = .constant,
.data = .{ .constant = val },
.ty = ty,
});
return ref;
}
@ -148,6 +174,65 @@ pub const Builder = struct {
}
};
pub const Renderer = struct {
gpa: Allocator,
obj: *Object,
ir: *const Ir,
errors: ErrorList = .{},
pub const ErrorList = std.StringArrayHashMapUnmanaged([]const u8);
pub const Error = Allocator.Error || error{LowerFail};
pub fn deinit(r: *Renderer) void {
for (r.errors.values()) |msg| r.gpa.free(msg);
r.errors.deinit(r.gpa);
}
pub fn render(r: *Renderer) !void {
switch (r.obj.target.cpu.arch) {
.x86, .x86_64 => return @import("Ir/x86/Renderer.zig").render(r),
else => unreachable,
}
}
pub fn fail(
r: *Renderer,
name: []const u8,
comptime format: []const u8,
args: anytype,
) Error {
try r.errors.ensureUnusedCapacity(r.gpa, 1);
r.errors.putAssumeCapacity(name, try std.fmt.allocPrint(r.gpa, format, args));
return error.LowerFail;
}
};
pub fn render(
ir: *const Ir,
gpa: Allocator,
target: std.Target,
errors: ?*Renderer.ErrorList,
) !*Object {
const obj = try Object.create(gpa, target);
errdefer obj.deinit();
var renderer: Renderer = .{
.gpa = gpa,
.obj = obj,
.ir = ir,
};
defer {
if (errors) |some| {
some.* = renderer.errors.move();
}
renderer.deinit();
}
try renderer.render();
return obj;
}
pub const Ref = enum(u32) { none = std.math.maxInt(u32), _ };
pub const Inst = struct {
@ -281,23 +366,30 @@ pub const Inst = struct {
};
pub fn deinit(ir: *Ir, gpa: std.mem.Allocator) void {
ir.arena.promote(gpa).deinit();
ir.instructions.deinit(gpa);
for (ir.decls.values()) |*decl| {
decl.deinit(gpa);
}
ir.decls.deinit(gpa);
ir.* = undefined;
}
const util = @import("util.zig");
const TYPE = util.Color.purple;
const INST = util.Color.cyan;
const REF = util.Color.blue;
const LITERAL = util.Color.green;
const ATTRIBUTE = util.Color.yellow;
const TYPE = std.io.tty.Color.bright_magenta;
const INST = std.io.tty.Color.bright_cyan;
const REF = std.io.tty.Color.bright_blue;
const LITERAL = std.io.tty.Color.bright_green;
const ATTRIBUTE = std.io.tty.Color.bright_yellow;
const RefMap = std.AutoArrayHashMap(Ref, void);
pub fn dump(ir: Ir, gpa: Allocator, name: []const u8, color: bool, w: anytype) !void {
const tags = ir.instructions.items(.tag);
const data = ir.instructions.items(.data);
pub fn dump(ir: *const Ir, gpa: Allocator, config: std.io.tty.Config, w: anytype) !void {
for (ir.decls.keys(), ir.decls.values()) |name, *decl| {
try ir.dumpDecl(decl, gpa, name, config, w);
}
}
fn dumpDecl(ir: *const Ir, decl: *const Decl, gpa: Allocator, name: []const u8, config: std.io.tty.Config, w: anytype) !void {
const tags = decl.instructions.items(.tag);
const data = decl.instructions.items(.data);
var ref_map = RefMap.init(gpa);
defer ref_map.deinit();
@ -305,40 +397,40 @@ pub fn dump(ir: Ir, gpa: Allocator, name: []const u8, color: bool, w: anytype) !
var label_map = RefMap.init(gpa);
defer label_map.deinit();
const ret_inst = ir.body.items[ir.body.items.len - 1];
const ret_inst = decl.body.items[decl.body.items.len - 1];
const ret_operand = data[@intFromEnum(ret_inst)].un;
const ret_ty = ir.instructions.items(.ty)[@intFromEnum(ret_operand)];
try ir.writeType(ret_ty, color, w);
if (color) util.setColor(REF, w);
const ret_ty = decl.instructions.items(.ty)[@intFromEnum(ret_operand)];
try ir.writeType(ret_ty, config, w);
try config.setColor(w, REF);
try w.print(" @{s}", .{name});
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
try w.writeAll("(");
var arg_count: u32 = 0;
while (true) : (arg_count += 1) {
const ref = ir.body.items[arg_count];
const ref = decl.body.items[arg_count];
if (tags[@intFromEnum(ref)] != .arg) break;
if (arg_count != 0) try w.writeAll(", ");
try ref_map.put(ref, {});
try ir.writeRef(&ref_map, ref, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, &ref_map, ref, config, w);
try config.setColor(w, .reset);
}
try w.writeAll(") {\n");
for (ir.body.items[arg_count..]) |ref| {
for (decl.body.items[arg_count..]) |ref| {
switch (tags[@intFromEnum(ref)]) {
.label => try label_map.put(ref, {}),
else => {},
}
}
for (ir.body.items[arg_count..]) |ref| {
for (decl.body.items[arg_count..]) |ref| {
const i = @intFromEnum(ref);
const tag = tags[i];
switch (tag) {
.arg, .constant, .symbol => unreachable,
.label => {
const label_index = label_map.getIndex(ref).?;
if (color) util.setColor(REF, w);
try config.setColor(w, REF);
try w.print("{s}.{d}:\n", .{ data[i].label, label_index });
},
// .label_val => {
@ -347,35 +439,35 @@ pub fn dump(ir: Ir, gpa: Allocator, name: []const u8, color: bool, w: anytype) !
// },
.jmp => {
const un = data[i].un;
if (color) util.setColor(INST, w);
try config.setColor(w, INST);
try w.writeAll(" jmp ");
try ir.writeLabel(&label_map, un, color, w);
try writeLabel(decl, &label_map, un, config, w);
try w.writeByte('\n');
},
.branch => {
const br = data[i].branch;
if (color) util.setColor(INST, w);
try config.setColor(w, INST);
try w.writeAll(" branch ");
try ir.writeRef(&ref_map, br.cond, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, &ref_map, br.cond, config, w);
try config.setColor(w, .reset);
try w.writeAll(", ");
try ir.writeLabel(&label_map, br.then, color, w);
if (color) util.setColor(.reset, w);
try writeLabel(decl, &label_map, br.then, config, w);
try config.setColor(w, .reset);
try w.writeAll(", ");
try ir.writeLabel(&label_map, br.@"else", color, w);
try writeLabel(decl, &label_map, br.@"else", config, w);
try w.writeByte('\n');
},
.select => {
const br = data[i].branch;
try ir.writeNewRef(&ref_map, ref, color, w);
try ir.writeNewRef(decl, &ref_map, ref, config, w);
try w.writeAll("select ");
try ir.writeRef(&ref_map, br.cond, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, &ref_map, br.cond, config, w);
try config.setColor(w, .reset);
try w.writeAll(", ");
try ir.writeRef(&ref_map, br.then, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, &ref_map, br.then, config, w);
try config.setColor(w, .reset);
try w.writeAll(", ");
try ir.writeRef(&ref_map, br.@"else", color, w);
try ir.writeRef(decl, &ref_map, br.@"else", config, w);
try w.writeByte('\n');
},
// .jmp_val => {
@ -384,91 +476,91 @@ pub fn dump(ir: Ir, gpa: Allocator, name: []const u8, color: bool, w: anytype) !
// },
.@"switch" => {
const @"switch" = data[i].@"switch";
if (color) util.setColor(INST, w);
try config.setColor(w, INST);
try w.writeAll(" switch ");
try ir.writeRef(&ref_map, @"switch".target, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, &ref_map, @"switch".target, config, w);
try config.setColor(w, .reset);
try w.writeAll(" {");
for (@"switch".case_vals[0..@"switch".cases_len], @"switch".case_labels) |val_ref, label_ref| {
try w.writeAll("\n ");
try ir.writeValue(val_ref, color, w);
if (color) util.setColor(.reset, w);
try ir.writeValue(val_ref, config, w);
try config.setColor(w, .reset);
try w.writeAll(" => ");
try ir.writeLabel(&label_map, label_ref, color, w);
if (color) util.setColor(.reset, w);
try writeLabel(decl, &label_map, label_ref, config, w);
try config.setColor(w, .reset);
}
if (color) util.setColor(LITERAL, w);
try config.setColor(w, LITERAL);
try w.writeAll("\n default ");
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
try w.writeAll("=> ");
try ir.writeLabel(&label_map, @"switch".default, color, w);
if (color) util.setColor(.reset, w);
try writeLabel(decl, &label_map, @"switch".default, config, w);
try config.setColor(w, .reset);
try w.writeAll("\n }\n");
},
.call => {
const call = data[i].call;
try ir.writeNewRef(&ref_map, ref, color, w);
try ir.writeNewRef(decl, &ref_map, ref, config, w);
try w.writeAll("call ");
try ir.writeRef(&ref_map, call.func, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, &ref_map, call.func, config, w);
try config.setColor(w, .reset);
try w.writeAll("(");
for (call.args(), 0..) |arg, arg_i| {
if (arg_i != 0) try w.writeAll(", ");
try ir.writeRef(&ref_map, arg, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, &ref_map, arg, config, w);
try config.setColor(w, .reset);
}
try w.writeAll(")\n");
},
.alloc => {
const alloc = data[i].alloc;
try ir.writeNewRef(&ref_map, ref, color, w);
try ir.writeNewRef(decl, &ref_map, ref, config, w);
try w.writeAll("alloc ");
if (color) util.setColor(ATTRIBUTE, w);
try config.setColor(w, ATTRIBUTE);
try w.writeAll("size ");
if (color) util.setColor(LITERAL, w);
try config.setColor(w, LITERAL);
try w.print("{d}", .{alloc.size});
if (color) util.setColor(ATTRIBUTE, w);
try config.setColor(w, ATTRIBUTE);
try w.writeAll(" align ");
if (color) util.setColor(LITERAL, w);
try config.setColor(w, LITERAL);
try w.print("{d}", .{alloc.@"align"});
try w.writeByte('\n');
},
.phi => {
try ir.writeNewRef(&ref_map, ref, color, w);
try ir.writeNewRef(decl, &ref_map, ref, config, w);
try w.writeAll("phi");
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
try w.writeAll(" {");
for (data[i].phi.inputs()) |input| {
try w.writeAll("\n ");
try ir.writeLabel(&label_map, input.label, color, w);
if (color) util.setColor(.reset, w);
try writeLabel(decl, &label_map, input.label, config, w);
try config.setColor(w, .reset);
try w.writeAll(" => ");
try ir.writeRef(&ref_map, input.value, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, &ref_map, input.value, config, w);
try config.setColor(w, .reset);
}
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
try w.writeAll("\n }\n");
},
.store => {
const bin = data[i].bin;
if (color) util.setColor(INST, w);
try config.setColor(w, INST);
try w.writeAll(" store ");
try ir.writeRef(&ref_map, bin.lhs, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, &ref_map, bin.lhs, config, w);
try config.setColor(w, .reset);
try w.writeAll(", ");
try ir.writeRef(&ref_map, bin.rhs, color, w);
try ir.writeRef(decl, &ref_map, bin.rhs, config, w);
try w.writeByte('\n');
},
.ret => {
if (color) util.setColor(INST, w);
try config.setColor(w, INST);
try w.writeAll(" ret ");
if (data[i].un != .none) try ir.writeRef(&ref_map, data[i].un, color, w);
if (data[i].un != .none) try ir.writeRef(decl, &ref_map, data[i].un, config, w);
try w.writeByte('\n');
},
.load => {
try ir.writeNewRef(&ref_map, ref, color, w);
try ir.writeNewRef(decl, &ref_map, ref, config, w);
try w.writeAll("load ");
try ir.writeRef(&ref_map, data[i].un, color, w);
try ir.writeRef(decl, &ref_map, data[i].un, config, w);
try w.writeByte('\n');
},
.bit_or,
@ -489,12 +581,12 @@ pub fn dump(ir: Ir, gpa: Allocator, name: []const u8, color: bool, w: anytype) !
.mod,
=> {
const bin = data[i].bin;
try ir.writeNewRef(&ref_map, ref, color, w);
try ir.writeNewRef(decl, &ref_map, ref, config, w);
try w.print("{s} ", .{@tagName(tag)});
try ir.writeRef(&ref_map, bin.lhs, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, &ref_map, bin.lhs, config, w);
try config.setColor(w, .reset);
try w.writeAll(", ");
try ir.writeRef(&ref_map, bin.rhs, color, w);
try ir.writeRef(decl, &ref_map, bin.rhs, config, w);
try w.writeByte('\n');
},
.bit_not,
@ -504,98 +596,101 @@ pub fn dump(ir: Ir, gpa: Allocator, name: []const u8, color: bool, w: anytype) !
.sext,
=> {
const un = data[i].un;
try ir.writeNewRef(&ref_map, ref, color, w);
try ir.writeNewRef(decl, &ref_map, ref, config, w);
try w.print("{s} ", .{@tagName(tag)});
try ir.writeRef(&ref_map, un, color, w);
try ir.writeRef(decl, &ref_map, un, config, w);
try w.writeByte('\n');
},
.label_addr, .jmp_val => {},
}
}
if (color) util.setColor(.reset, w);
try config.setColor(w, .reset);
try w.writeAll("}\n\n");
}
fn writeType(ir: Ir, ty_ref: Interner.Ref, color: bool, w: anytype) !void {
const ty = ir.pool.get(ty_ref);
if (color) util.setColor(TYPE, w);
fn writeType(ir: Ir, ty_ref: Interner.Ref, config: std.io.tty.Config, w: anytype) !void {
const ty = ir.interner.get(ty_ref);
try config.setColor(w, TYPE);
switch (ty) {
.value => unreachable,
.ptr, .noreturn, .void, .func => try w.writeAll(@tagName(ty)),
.int => |bits| try w.print("i{d}", .{bits}),
.float => |bits| try w.print("f{d}", .{bits}),
.array => |info| {
.ptr_ty, .noreturn_ty, .void_ty, .func_ty => try w.writeAll(@tagName(ty)),
.int_ty => |bits| try w.print("i{d}", .{bits}),
.float_ty => |bits| try w.print("f{d}", .{bits}),
.array_ty => |info| {
try w.print("[{d} * ", .{info.len});
try ir.writeType(info.child, false, w);
try ir.writeType(info.child, .no_color, w);
try w.writeByte(']');
},
.vector => |info| {
.vector_ty => |info| {
try w.print("<{d} * ", .{info.len});
try ir.writeType(info.child, false, w);
try ir.writeType(info.child, .no_color, w);
try w.writeByte('>');
},
.record => |info| {
.record_ty => |elems| {
// TODO collect into buffer and only print once
try w.writeAll("{ ");
for (info.elements, 0..) |elem, i| {
for (elems, 0..) |elem, i| {
if (i != 0) try w.writeAll(", ");
try ir.writeType(elem, color, w);
try ir.writeType(elem, config, w);
}
try w.writeAll(" }");
},
else => unreachable, // not a type
}
}
fn writeValue(ir: Ir, val_ref: Interner.Ref, color: bool, w: anytype) !void {
const v = ir.pool.get(val_ref).value;
if (color) util.setColor(LITERAL, w);
switch (v.tag) {
.unavailable => try w.writeAll(" unavailable"),
.int => try w.print("{d}", .{v.data.int}),
.bytes => try w.print("\"{s}\"", .{v.data.bytes.slice(ir.strings, .@"1")}),
// std.fmt does @as instead of @floatCast
.float => try w.print("{d}", .{@as(f64, @floatCast(v.data.float))}),
else => try w.print("({s})", .{@tagName(v.tag)}),
fn writeValue(ir: Ir, val: Interner.Ref, config: std.io.tty.Config, w: anytype) !void {
try config.setColor(w, LITERAL);
const key = ir.interner.get(val);
switch (key) {
.null => return w.writeAll("nullptr_t"),
.int => |repr| switch (repr) {
inline else => |x| return w.print("{d}", .{x}),
},
.float => |repr| switch (repr) {
inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}),
},
.bytes => |b| return std.zig.fmt.stringEscape(b, "", .{}, w),
else => unreachable, // not a value
}
}
fn writeRef(ir: Ir, ref_map: *RefMap, ref: Ref, color: bool, w: anytype) !void {
fn writeRef(ir: Ir, decl: *const Decl, ref_map: *RefMap, ref: Ref, config: std.io.tty.Config, w: anytype) !void {
assert(ref != .none);
const index = @intFromEnum(ref);
const ty_ref = ir.instructions.items(.ty)[index];
if (ir.instructions.items(.tag)[index] == .constant) {
try ir.writeType(ty_ref, color, w);
const v_ref = ir.instructions.items(.data)[index].constant;
const ty_ref = decl.instructions.items(.ty)[index];
if (decl.instructions.items(.tag)[index] == .constant) {
try ir.writeType(ty_ref, config, w);
const v_ref = decl.instructions.items(.data)[index].constant;
try w.writeByte(' ');
try ir.writeValue(v_ref, color, w);
try ir.writeValue(v_ref, config, w);
return;
} else if (ir.instructions.items(.tag)[index] == .symbol) {
const name = ir.instructions.items(.data)[index].label;
try ir.writeType(ty_ref, color, w);
if (color) util.setColor(REF, w);
} else if (decl.instructions.items(.tag)[index] == .symbol) {
const name = decl.instructions.items(.data)[index].label;
try ir.writeType(ty_ref, config, w);
try config.setColor(w, REF);
try w.print(" @{s}", .{name});
return;
}
try ir.writeType(ty_ref, color, w);
if (color) util.setColor(REF, w);
try ir.writeType(ty_ref, config, w);
try config.setColor(w, REF);
const ref_index = ref_map.getIndex(ref).?;
try w.print(" %{d}", .{ref_index});
}
fn writeNewRef(ir: Ir, ref_map: *RefMap, ref: Ref, color: bool, w: anytype) !void {
fn writeNewRef(ir: Ir, decl: *const Decl, ref_map: *RefMap, ref: Ref, config: std.io.tty.Config, w: anytype) !void {
try ref_map.put(ref, {});
try w.writeAll(" ");
try ir.writeRef(ref_map, ref, color, w);
if (color) util.setColor(.reset, w);
try ir.writeRef(decl, ref_map, ref, config, w);
try config.setColor(w, .reset);
try w.writeAll(" = ");
if (color) util.setColor(INST, w);
try config.setColor(w, INST);
}
fn writeLabel(ir: Ir, label_map: *RefMap, ref: Ref, color: bool, w: anytype) !void {
fn writeLabel(decl: *const Decl, label_map: *RefMap, ref: Ref, config: std.io.tty.Config, w: anytype) !void {
assert(ref != .none);
const index = @intFromEnum(ref);
const label = ir.instructions.items(.data)[index].label;
if (color) util.setColor(REF, w);
const label = decl.instructions.items(.data)[index].label;
try config.setColor(w, REF);
const label_index = label_map.getIndex(ref).?;
try w.print("{s}.{d}", .{ label, label_index });
}

65
deps/aro/backend/Ir/x86/Renderer.zig vendored Normal file
View File

@ -0,0 +1,65 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const Interner = @import("../../Interner.zig");
const Ir = @import("../../Ir.zig");
const BaseRenderer = Ir.Renderer;
const zig = @import("zig");
const abi = zig.arch.x86_64.abi;
const bits = zig.arch.x86_64.bits;
const Condition = bits.Condition;
const Immediate = bits.Immediate;
const Memory = bits.Memory;
const Register = bits.Register;
const RegisterLock = RegisterManager.RegisterLock;
const FrameIndex = bits.FrameIndex;
const RegisterManager = zig.RegisterManager(Renderer, Register, Ir.Ref, abi.allocatable_regs);
// Register classes
const RegisterBitSet = RegisterManager.RegisterBitSet;
const RegisterClass = struct {
const gp: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
for (abi.allocatable_regs, 0..) |reg, index| if (reg.class() == .general_purpose) set.set(index);
break :blk set;
};
const x87: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
for (abi.allocatable_regs, 0..) |reg, index| if (reg.class() == .x87) set.set(index);
break :blk set;
};
const sse: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
for (abi.allocatable_regs, 0..) |reg, index| if (reg.class() == .sse) set.set(index);
break :blk set;
};
};
const Renderer = @This();
base: *BaseRenderer,
interner: *Interner,
register_manager: RegisterManager = .{},
pub fn render(base: *BaseRenderer) !void {
var renderer: Renderer = .{
.base = base,
.interner = base.ir.interner,
};
for (renderer.base.ir.decls.keys(), renderer.base.ir.decls.values()) |name, decl| {
renderer.renderFn(name, decl) catch |e| switch (e) {
error.OutOfMemory => return e,
error.LowerFail => continue,
};
}
if (renderer.base.errors.entries.len != 0) return error.LowerFail;
}
fn renderFn(r: *Renderer, name: []const u8, decl: Ir.Decl) !void {
_ = decl;
return r.base.fail(name, "TODO implement lowering functions", .{});
}

View File

@ -1,15 +1,15 @@
const std = @import("std");
const Compilation = @import("Compilation.zig");
const Elf = @import("object/Elf.zig");
const Allocator = std.mem.Allocator;
const Elf = @import("Object/Elf.zig");
const Object = @This();
format: std.Target.ObjectFormat,
comp: *Compilation,
target: std.Target,
pub fn create(comp: *Compilation) !*Object {
switch (comp.target.ofmt) {
.elf => return Elf.create(comp),
pub fn create(gpa: Allocator, target: std.Target) !*Object {
switch (target.ofmt) {
.elf => return Elf.create(gpa, target),
else => unreachable,
}
}

View File

@ -1,9 +1,8 @@
const std = @import("std");
const Compilation = @import("../Compilation.zig");
const Allocator = std.mem.Allocator;
const Target = std.Target;
const Object = @import("../Object.zig");
const Elf = @This();
const Section = struct {
data: std.ArrayList(u8),
relocations: std.ArrayListUnmanaged(Relocation) = .{},
@ -34,6 +33,8 @@ const strtab_default = "\x00.strtab\x00.symtab\x00";
const strtab_name = 1;
const symtab_name = "\x00.strtab\x00".len;
const Elf = @This();
obj: Object,
/// The keys are owned by the Codegen.tree
sections: std.StringHashMapUnmanaged(*Section) = .{},
@ -43,11 +44,11 @@ unnamed_symbol_mangle: u32 = 0,
strtab_len: u64 = strtab_default.len,
arena: std.heap.ArenaAllocator,
pub fn create(comp: *Compilation) !*Object {
const elf = try comp.gpa.create(Elf);
pub fn create(gpa: Allocator, target: Target) !*Object {
const elf = try gpa.create(Elf);
elf.* = .{
.obj = .{ .format = .elf, .comp = comp },
.arena = std.heap.ArenaAllocator.init(comp.gpa),
.obj = .{ .format = .elf, .target = target },
.arena = std.heap.ArenaAllocator.init(gpa),
};
return &elf.obj;
}
@ -195,10 +196,10 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void {
const sh_offset = strtab_offset + elf.strtab_len;
const sh_offset_aligned = std.mem.alignForward(u64, sh_offset, 16);
var elf_header = std.elf.Elf64_Ehdr{
const elf_header = std.elf.Elf64_Ehdr{
.e_ident = .{ 0x7F, 'E', 'L', 'F', 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
.e_type = std.elf.ET.REL, // we only produce relocatables
.e_machine = elf.obj.comp.target.cpu.arch.toElfMachine(),
.e_machine = elf.obj.target.cpu.arch.toElfMachine(),
.e_version = 1,
.e_entry = 0, // linker will handle this
.e_phoff = 0, // no program header
@ -298,7 +299,7 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void {
// write strtab section header
{
var sect_header = std.elf.Elf64_Shdr{
const sect_header = std.elf.Elf64_Shdr{
.sh_name = strtab_name,
.sh_type = std.elf.SHT_STRTAB,
.sh_flags = 0,
@ -315,7 +316,7 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void {
// write symtab section header
{
var sect_header = std.elf.Elf64_Shdr{
const sect_header = std.elf.Elf64_Shdr{
.sh_name = symtab_name,
.sh_type = std.elf.SHT_SYMTAB,
.sh_flags = 0,

View File

@ -1,25 +1,31 @@
const std = @import("std");
const GenerateDef = @This();
const Step = std.Build.Step;
const Allocator = std.mem.Allocator;
const GeneratedFile = std.Build.GeneratedFile;
const GenerateDef = @This();
step: Step,
path: []const u8,
name: []const u8,
kind: Options.Kind,
generated_file: GeneratedFile,
pub const base_id: Step.Id = .custom;
pub fn add(
owner: *std.Build,
def_file_path: []const u8,
import_path: []const u8,
compile_step: *Step.Compile,
aro_module: *std.Build.Module,
) void {
const self = owner.allocator.create(GenerateDef) catch @panic("OOM");
pub const Options = struct {
name: []const u8,
src_prefix: []const u8 = "src/aro",
kind: Kind = .dafsa,
const name = owner.fmt("GenerateDef {s}", .{def_file_path});
pub const Kind = enum { dafsa, named };
};
pub fn create(owner: *std.Build, options: Options) std.Build.ModuleDependency {
const self = owner.allocator.create(GenerateDef) catch @panic("OOM");
const path = owner.pathJoin(&.{ options.src_prefix, options.name });
const name = owner.fmt("GenerateDef {s}", .{options.name});
self.* = .{
.step = Step.init(.{
.id = base_id,
@ -27,16 +33,18 @@ pub fn add(
.owner = owner,
.makeFn = make,
}),
.path = def_file_path,
.path = path,
.name = options.name,
.kind = options.kind,
.generated_file = .{ .step = &self.step },
};
const module = owner.createModule(.{
const module = self.step.owner.createModule(.{
.source_file = .{ .generated = &self.generated_file },
});
compile_step.addModule(import_path, module);
compile_step.step.dependOn(&self.step);
aro_module.dependencies.put(import_path, module) catch @panic("OOM");
return .{
.module = module,
.name = self.name,
};
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
@ -132,7 +140,7 @@ fn generate(self: *GenerateDef, input: []const u8) ![]const u8 {
}
{
var sorted_list = try arena.dupe([]const u8, values.keys());
const sorted_list = try arena.dupe([]const u8, values.keys());
defer arena.free(sorted_list);
std.mem.sort([]const u8, sorted_list, {}, struct {
pub fn lessThan(_: void, a: []const u8, b: []const u8) bool {
@ -168,15 +176,6 @@ fn generate(self: *GenerateDef, input: []const u8) ![]const u8 {
}
}
var values_array = try arena.alloc(Value, values.count());
defer arena.free(values_array);
for (values.keys(), values.values()) |name, props| {
const unique_index = builder.getUniqueIndex(name).?;
const data_index = unique_index - 1;
values_array[data_index] = .{ .name = name, .properties = props };
}
var out_buf = std.ArrayList(u8).init(arena);
defer out_buf.deinit();
const writer = out_buf.writer();
@ -193,6 +192,49 @@ fn generate(self: *GenerateDef, input: []const u8) ![]const u8 {
for (headers.items) |line| {
try writer.print("{s}\n", .{line});
}
if (self.kind == .named) {
try writer.writeAll("pub const Tag = enum {\n");
for (values.keys()) |property| {
try writer.print(" {s},\n", .{std.zig.fmtId(property)});
}
try writer.writeAll(
\\
\\ pub fn property(tag: Tag) Properties {
\\ return named_data[@intFromEnum(tag)];
\\ }
\\
\\ const named_data = [_]Properties{
\\
);
for (values.values()) |val_props| {
try writer.writeAll(" .{");
for (val_props, 0..) |val_prop, j| {
if (j != 0) try writer.writeByte(',');
try writer.writeByte(' ');
try writer.writeAll(val_prop);
}
try writer.writeAll(" },\n");
}
try writer.writeAll(
\\ };
\\};
\\};
\\}
\\
);
return out_buf.toOwnedSlice();
}
var values_array = try arena.alloc(Value, values.count());
defer arena.free(values_array);
for (values.keys(), values.values()) |name, props| {
const unique_index = builder.getUniqueIndex(name).?;
const data_index = unique_index - 1;
values_array[data_index] = .{ .name = name, .properties = props };
}
try writer.writeAll(
\\
\\tag: Tag,
@ -418,7 +460,7 @@ const DafsaBuilder = struct {
var arena = std.heap.ArenaAllocator.init(allocator);
errdefer arena.deinit();
var root = try arena.allocator().create(Node);
const root = try arena.allocator().create(Node);
root.* = .{};
return DafsaBuilder{
.root = root,
@ -498,7 +540,7 @@ const DafsaBuilder = struct {
std.debug.assert(node.children[c] == null);
var arena = self.arena.promote(self.allocator);
var child = try arena.allocator().create(Node);
const child = try arena.allocator().create(Node);
self.arena = arena.state;
child.* = .{};

View File

@ -1,221 +0,0 @@
const std = @import("std");
const Codegen = @import("../Codegen_legacy.zig");
const Tree = @import("../Tree.zig");
const NodeIndex = Tree.NodeIndex;
const x86_64 = @import("zig").codegen.x86_64;
const Register = x86_64.Register;
const RegisterManager = @import("zig").RegisterManager;
const Fn = @This();
const Value = union(enum) {
symbol: []const u8,
immediate: i64,
register: Register,
none,
};
register_manager: RegisterManager(Fn, Register, &x86_64.callee_preserved_regs) = .{},
data: *std.ArrayList(u8),
c: *Codegen,
pub fn deinit(func: *Fn) void {
func.* = undefined;
}
pub fn genFn(c: *Codegen, decl: NodeIndex, data: *std.ArrayList(u8)) Codegen.Error!void {
var func = Fn{ .data = data, .c = c };
defer func.deinit();
// function prologue
try func.data.appendSlice(&.{
0x55, // push rbp
0x48, 0x89, 0xe5, // mov rbp,rsp
});
_ = try func.genNode(c.node_data[@intFromEnum(decl)].decl.node);
// all functions are guaranteed to end in a return statement so no extra work required here
}
pub fn spillInst(f: *Fn, reg: Register, inst: u32) !void {
_ = inst;
_ = reg;
_ = f;
}
fn setReg(func: *Fn, val: Value, reg: Register) !void {
switch (val) {
.none => unreachable,
.symbol => |sym| {
// lea address with 0 and add relocation
const encoder = try x86_64.Encoder.init(func.data, 8);
encoder.rex(.{ .w = true });
encoder.opcode_1byte(0x8D);
encoder.modRm_RIPDisp32(reg.low_id());
const offset = func.data.items.len;
encoder.imm32(0);
try func.c.obj.addRelocation(sym, .func, offset, -4);
},
.immediate => |x| if (x == 0) {
// 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
// register is the fastest way to zero a register.
// The encoding for `xor r32, r32` is `0x31 /r`.
const encoder = try x86_64.Encoder.init(func.data, 3);
// If we're accessing e.g. r8d, we need to use a REX prefix before the actual operation. Since
// this is a 32-bit operation, the W flag is set to zero. X is also zero, as we're not using a SIB.
// Both R and B are set, as we're extending, in effect, the register bits *and* the operand.
encoder.rex(.{ .r = reg.isExtended(), .b = reg.isExtended() });
encoder.opcode_1byte(0x31);
// Section 3.1.1.1 of the Intel x64 Manual states that "/r indicates that the
// ModR/M byte of the instruction contains a register operand and an r/m operand."
encoder.modRm_direct(reg.low_id(), reg.low_id());
} else if (x <= std.math.maxInt(i32)) {
// Next best case: if we set the lower four bytes, the upper four will be zeroed.
//
// The encoding for `mov IMM32 -> REG` is (0xB8 + R) IMM.
const encoder = try x86_64.Encoder.init(func.data, 6);
// Just as with XORing, we need a REX prefix. This time though, we only
// need the B bit set, as we're extending the opcode's register field,
// and there is no Mod R/M byte.
encoder.rex(.{ .b = reg.isExtended() });
encoder.opcode_withReg(0xB8, reg.low_id());
// no ModR/M byte
// IMM
encoder.imm32(@intCast(x));
} else {
// Worst case: we need to load the 64-bit register with the IMM. GNU's assemblers calls
// this `movabs`, though this is officially just a different variant of the plain `mov`
// instruction.
//
// This encoding is, in fact, the *same* as the one used for 32-bit loads. The only
// difference is that we set REX.W before the instruction, which extends the load to
// 64-bit and uses the full bit-width of the register.
{
const encoder = try x86_64.Encoder.init(func.data, 10);
encoder.rex(.{ .w = true, .b = reg.isExtended() });
encoder.opcode_withReg(0xB8, reg.low_id());
encoder.imm64(@bitCast(x));
}
},
.register => |src_reg| {
// If the registers are the same, nothing to do.
if (src_reg.id() == reg.id())
return;
// This is a variant of 8B /r.
const encoder = try x86_64.Encoder.init(func.data, 3);
encoder.rex(.{
.w = true,
.r = reg.isExtended(),
.b = src_reg.isExtended(),
});
encoder.opcode_1byte(0x8B);
encoder.modRm_direct(reg.low_id(), src_reg.low_id());
},
}
}
fn genNode(func: *Fn, node: NodeIndex) Codegen.Error!Value {
if (func.c.tree.value_map.get(node)) |some| {
if (some.tag == .int)
return Value{ .immediate = @bitCast(some.data.int) };
}
const data = func.c.node_data[@intFromEnum(node)];
switch (func.c.node_tag[@intFromEnum(node)]) {
.static_assert => return Value{ .none = {} },
.compound_stmt_two => {
if (data.bin.lhs != .none) _ = try func.genNode(data.bin.lhs);
if (data.bin.rhs != .none) _ = try func.genNode(data.bin.rhs);
return Value{ .none = {} };
},
.compound_stmt => {
for (func.c.tree.data[data.range.start..data.range.end]) |stmt| {
_ = try func.genNode(stmt);
}
return Value{ .none = {} };
},
.call_expr_one => if (data.bin.rhs != .none)
return func.genCall(data.bin.lhs, &.{data.bin.rhs})
else
return func.genCall(data.bin.lhs, &.{}),
.call_expr => return func.genCall(func.c.tree.data[data.range.start], func.c.tree.data[data.range.start + 1 .. data.range.end]),
.explicit_cast, .implicit_cast => {
switch (data.cast.kind) {
.function_to_pointer,
.array_to_pointer,
=> return func.genNode(data.cast.operand), // no-op
else => return func.c.comp.diag.fatalNoSrc("TODO x86_64 genNode for cast {s}\n", .{@tagName(data.cast.kind)}),
}
},
.decl_ref_expr => {
// TODO locals and arguments
return Value{ .symbol = func.c.tree.tokSlice(data.decl_ref) };
},
.return_stmt => {
const value = try func.genNode(data.un);
try func.setReg(value, x86_64.c_abi_int_return_regs[0]);
try func.data.appendSlice(&.{
0x5d, // pop rbp
0xc3, // ret
});
return Value{ .none = {} };
},
.implicit_return => {
try func.setReg(.{ .immediate = 0 }, x86_64.c_abi_int_return_regs[0]);
try func.data.appendSlice(&.{
0x5d, // pop rbp
0xc3, // ret
});
return Value{ .none = {} };
},
.int_literal => return Value{ .immediate = @bitCast(data.int) },
.string_literal_expr => {
const range = func.c.tree.value_map.get(node).?.data.bytes;
const str_bytes = range.slice(func.c.tree.strings, .@"1");
const section = try func.c.obj.getSection(.strings);
const start = section.items.len;
try section.appendSlice(str_bytes);
const symbol_name = try func.c.obj.declareSymbol(.strings, null, .Internal, .variable, start, str_bytes.len);
return Value{ .symbol = symbol_name };
},
else => return func.c.comp.diag.fatalNoSrc("TODO x86_64 genNode {}\n", .{func.c.node_tag[@intFromEnum(node)]}),
}
}
fn genCall(func: *Fn, lhs: NodeIndex, args: []const NodeIndex) Codegen.Error!Value {
if (args.len > x86_64.c_abi_int_param_regs.len)
return func.c.comp.diag.fatalNoSrc("TODO more than args {d}\n", .{x86_64.c_abi_int_param_regs.len});
const func_value = try func.genNode(lhs);
for (args, 0..) |arg, i| {
const value = try func.genNode(arg);
try func.setReg(value, x86_64.c_abi_int_param_regs[i]);
}
switch (func_value) {
.none => unreachable,
.symbol => |sym| {
const encoder = try x86_64.Encoder.init(func.data, 5);
encoder.opcode_1byte(0xe8);
const offset = func.data.items.len;
encoder.imm32(0);
try func.c.obj.addRelocation(sym, .func, offset, -4);
},
.immediate => return func.c.comp.diag.fatalNoSrc("TODO call immediate\n", .{}),
.register => return func.c.comp.diag.fatalNoSrc("TODO call reg\n", .{}),
}
return Value{ .register = x86_64.c_abi_int_return_regs[0] };
}
pub fn genVar(c: *Codegen, decl: NodeIndex) Codegen.Error!void {
_ = c;
_ = decl;
}

27
deps/aro/lib.zig vendored
View File

@ -1,27 +0,0 @@
/// Deprecated
pub const Codegen = @import("Codegen_legacy.zig");
pub const CodeGen = @import("CodeGen.zig");
pub const Compilation = @import("Compilation.zig");
pub const Diagnostics = @import("Diagnostics.zig");
pub const Driver = @import("Driver.zig");
pub const Interner = @import("Interner.zig");
pub const Ir = @import("Ir.zig");
pub const Object = @import("Object.zig");
pub const Parser = @import("Parser.zig");
pub const Preprocessor = @import("Preprocessor.zig");
pub const Source = @import("Source.zig");
pub const Tokenizer = @import("Tokenizer.zig");
pub const Tree = @import("Tree.zig");
pub const Type = @import("Type.zig");
pub const TypeMapper = @import("StringInterner.zig").TypeMapper;
pub const target_util = @import("target.zig");
pub const version_str = "0.0.0-dev";
pub const version = @import("std").SemanticVersion.parse(version_str) catch unreachable;
pub const CallingConvention = enum {
C,
stdcall,
thiscall,
vectorcall,
};

83
deps/aro/util.zig vendored
View File

@ -1,83 +0,0 @@
const std = @import("std");
const mem = std.mem;
const builtin = @import("builtin");
const is_windows = builtin.os.tag == .windows;
pub const Color = enum {
reset,
red,
green,
blue,
cyan,
purple,
yellow,
white,
};
pub fn fileSupportsColor(file: std.fs.File) bool {
return file.supportsAnsiEscapeCodes() or (is_windows and file.isTty());
}
pub fn setColor(color: Color, w: anytype) void {
if (is_windows) {
const stderr_file = std.io.getStdErr();
if (!stderr_file.isTty()) return;
const windows = std.os.windows;
const S = struct {
var attrs: windows.WORD = undefined;
var init_attrs = false;
};
if (!S.init_attrs) {
S.init_attrs = true;
var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
_ = windows.kernel32.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
S.attrs = info.wAttributes;
_ = windows.kernel32.SetConsoleOutputCP(65001);
}
// need to flush bufferedWriter
const T = if (@typeInfo(@TypeOf(w.context)) == .Pointer) @TypeOf(w.context.*) else @TypeOf(w.context);
if (T != void and @hasDecl(T, "flush")) w.context.flush() catch {};
switch (color) {
.reset => _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs) catch {},
.red => _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY) catch {},
.green => _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY) catch {},
.blue => _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {},
.cyan => _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {},
.purple => _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {},
.yellow => _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY) catch {},
.white => _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {},
}
} else switch (color) {
.reset => w.writeAll("\x1b[0m") catch {},
.red => w.writeAll("\x1b[31;1m") catch {},
.green => w.writeAll("\x1b[32;1m") catch {},
.blue => w.writeAll("\x1b[34;1m") catch {},
.cyan => w.writeAll("\x1b[36;1m") catch {},
.purple => w.writeAll("\x1b[35;1m") catch {},
.yellow => w.writeAll("\x1b[93;1m") catch {},
.white => w.writeAll("\x1b[0m\x1b[1m") catch {},
}
}
pub fn errorDescription(err: anyerror) []const u8 {
return switch (err) {
error.OutOfMemory => "ran out of memory",
error.FileNotFound => "file not found",
error.IsDir => "is a directory",
error.NotDir => "is not a directory",
error.NotOpenForReading => "file is not open for reading",
error.NotOpenForWriting => "file is not open for writing",
error.InvalidUtf8 => "input is not valid UTF-8",
error.FileBusy => "file is busy",
error.NameTooLong => "file name is too long",
error.AccessDenied => "access denied",
error.FileTooBig => "file is too big",
error.ProcessFdQuotaExceeded, error.SystemFdQuotaExceeded => "ran out of file descriptors",
error.SystemResources => "ran out of system resources",
error.FatalError => "a fatal error occurred",
error.Unexpected => "an unexpected error occurred",
else => @errorName(err),
};
}