diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-01-29 23:33:12 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-01-29 23:33:12 -0500 |
| commit | a95dce15ae4bd95cfd2266da51ba860cc6524a1b (patch) | |
| tree | e761ecb74f37ff699d2e1f09d122811b101826e4 /lib/std | |
| parent | 800ead2810fa573a7e94979e707a14d4e066ef77 (diff) | |
| parent | 7ebc624a15c5a01d6bee8eaf9c7487b30ed1904c (diff) | |
| download | zig-a95dce15ae4bd95cfd2266da51ba860cc6524a1b.tar.gz zig-a95dce15ae4bd95cfd2266da51ba860cc6524a1b.zip | |
Merge remote-tracking branch 'origin/master' into llvm10
Diffstat (limited to 'lib/std')
54 files changed, 18594 insertions, 711 deletions
diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig index 6313d693b7..42bf8e8142 100644 --- a/lib/std/buffer.zig +++ b/lib/std/buffer.zig @@ -57,11 +57,11 @@ pub const Buffer = struct { /// The caller owns the returned memory. The Buffer becomes null and /// is safe to `deinit`. - pub fn toOwnedSlice(self: *Buffer) []u8 { + pub fn toOwnedSlice(self: *Buffer) [:0]u8 { const allocator = self.list.allocator; - const result = allocator.shrink(self.list.items, self.len()); + const result = self.list.toOwnedSlice(); self.* = initNull(allocator); - return result; + return result[0 .. result.len - 1 :0]; } pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: var) !Buffer { diff --git a/lib/std/build.zig b/lib/std/build.zig index 53f8f19df5..f535b022af 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -484,6 +484,7 @@ pub const Builder = struct { .arch = builtin.arch, .os = builtin.os, .abi = builtin.abi, + .cpu_features = builtin.cpu_features, }, }).linuxTriple(self.allocator); @@ -1148,6 +1149,7 @@ pub const LibExeObjStep = struct { name_prefix: []const u8, filter: ?[]const u8, single_threaded: bool, + code_model: builtin.CodeModel = .default, root_src: ?FileSource, out_h_filename: []const u8, @@ -1375,6 +1377,7 @@ pub const LibExeObjStep = struct { .arch = target_arch, .os = target_os, .abi = target_abi, + .cpu_features = target_arch.getBaselineCpuFeatures(), }, }); } @@ -1968,11 +1971,56 @@ pub const LibExeObjStep = struct { try zig_args.append("-fno-sanitize-c"); } + if (self.code_model != .default) { + try zig_args.append("-code-model"); + try zig_args.append(@tagName(self.code_model)); + } + switch (self.target) { .Native => {}, - .Cross => { + .Cross => |cross| { try zig_args.append("-target"); try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable); + + const all_features = self.target.getArch().allFeaturesList(); + var populated_cpu_features = cross.cpu_features.cpu.features; + if (self.target.getArch().subArchFeature()) |sub_arch_index| { + populated_cpu_features.addFeature(sub_arch_index); + } + populated_cpu_features.populateDependencies(all_features); + + if (populated_cpu_features.eql(cross.cpu_features.features)) { + // The CPU name alone is sufficient. + // If it is the baseline CPU, no command line args are required. + if (cross.cpu_features.cpu != self.target.getArch().getBaselineCpuFeatures().cpu) { + try zig_args.append("-target-cpu"); + try zig_args.append(cross.cpu_features.cpu.name); + } + } else { + try zig_args.append("-target-cpu"); + try zig_args.append(cross.cpu_features.cpu.name); + + try zig_args.append("-target-feature"); + var feature_str_buffer = try std.Buffer.initSize(builder.allocator, 0); + for (all_features) |feature, i_usize| { + const i = @intCast(Target.Cpu.Feature.Set.Index, i_usize); + const in_cpu_set = populated_cpu_features.isEnabled(i); + const in_actual_set = cross.cpu_features.features.isEnabled(i); + if (in_cpu_set and !in_actual_set) { + try feature_str_buffer.appendByte('-'); + try feature_str_buffer.append(feature.name); + try feature_str_buffer.appendByte(','); + } else if (!in_cpu_set and in_actual_set) { + try feature_str_buffer.appendByte('+'); + try feature_str_buffer.append(feature.name); + try feature_str_buffer.appendByte(','); + } + } + if (mem.endsWith(u8, feature_str_buffer.toSliceConst(), ",")) { + feature_str_buffer.shrink(feature_str_buffer.len() - 1); + } + try zig_args.append(feature_str_buffer.toSliceConst()); + } }, } diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 55f044094e..d8f24753d3 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -1,5 +1,8 @@ pub usingnamespace @import("builtin"); +/// Deprecated: use `std.Target`. +pub const Target = std.Target; + /// Deprecated: use `std.Target.Os`. pub const Os = std.Target.Os; @@ -15,6 +18,12 @@ pub const ObjectFormat = std.Target.ObjectFormat; /// Deprecated: use `std.Target.SubSystem`. pub const SubSystem = std.Target.SubSystem; +/// Deprecated: use `std.Target.CpuFeatures`. +pub const CpuFeatures = std.Target.CpuFeatures; + +/// Deprecated: use `std.Target.Cpu`. +pub const Cpu = std.Target.Cpu; + /// `explicit_subsystem` is missing when the subsystem is automatically detected, /// so Zig standard library has the subsystem detection logic here. This should generally be /// used rather than `explicit_subsystem`. @@ -82,6 +91,21 @@ pub const AtomicRmwOp = enum { Min, }; +/// The code model puts constraints on the location of symbols and the size of code and data. +/// The selection of a code model is a trade off on speed and restrictions that needs to be selected on a per application basis to meet its requirements. +/// A slightly more detailed explanation can be found in (for example) the [System V Application Binary Interface (x86_64)](https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf) 3.5.1. +/// +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const CodeModel = enum { + default, + tiny, + small, + kernel, + medium, + large, +}; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Mode = enum { diff --git a/lib/std/c.zig b/lib/std/c.zig index c912c72418..4d5e72f502 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -2,6 +2,12 @@ const builtin = @import("builtin"); const std = @import("std"); const page_size = std.mem.page_size; +pub const tokenizer = @import("c/tokenizer.zig"); +pub const Token = tokenizer.Token; +pub const Tokenizer = tokenizer.Tokenizer; +pub const parse = @import("c/parse.zig").parse; +pub const ast = @import("c/ast.zig"); + pub usingnamespace @import("os/bits.zig"); pub usingnamespace switch (builtin.os) { diff --git a/lib/std/c/ast.zig b/lib/std/c/ast.zig new file mode 100644 index 0000000000..bb8c01f138 --- /dev/null +++ b/lib/std/c/ast.zig @@ -0,0 +1,681 @@ +const std = @import("std"); +const SegmentedList = std.SegmentedList; +const Token = std.c.Token; +const Source = std.c.tokenizer.Source; + +pub const TokenIndex = usize; + +pub const Tree = struct { + tokens: TokenList, + sources: SourceList, + root_node: *Node.Root, + arena_allocator: std.heap.ArenaAllocator, + msgs: MsgList, + + pub const SourceList = SegmentedList(Source, 4); + pub const TokenList = Source.TokenList; + pub const MsgList = SegmentedList(Msg, 0); + + pub fn deinit(self: *Tree) void { + // Here we copy the arena allocator into stack memory, because + // otherwise it would destroy itself while it was still working. + var arena_allocator = self.arena_allocator; + arena_allocator.deinit(); + // self is destroyed + } + + pub fn tokenSlice(tree: *Tree, token: TokenIndex) []const u8 { + return tree.tokens.at(token).slice(); + } + + pub fn tokenEql(tree: *Tree, a: TokenIndex, b: TokenIndex) bool { + const atok = tree.tokens.at(a); + const btok = tree.tokens.at(b); + return atok.eql(btok.*); + } +}; + +pub const Msg = struct { + kind: enum { + Error, + Warning, + Note, + }, + inner: Error, +}; + +pub const Error = union(enum) { + InvalidToken: SingleTokenError("invalid token '{}'"), + ExpectedToken: ExpectedToken, + ExpectedExpr: SingleTokenError("expected expression, found '{}'"), + ExpectedTypeName: SingleTokenError("expected type name, found '{}'"), + ExpectedFnBody: SingleTokenError("expected function body, found '{}'"), + ExpectedDeclarator: SingleTokenError("expected declarator, found '{}'"), + ExpectedInitializer: SingleTokenError("expected initializer, found '{}'"), + ExpectedEnumField: SingleTokenError("expected enum field, found '{}'"), + ExpectedType: SingleTokenError("expected enum field, found '{}'"), + InvalidTypeSpecifier: InvalidTypeSpecifier, + InvalidStorageClass: SingleTokenError("invalid storage class, found '{}'"), + InvalidDeclarator: SimpleError("invalid declarator"), + DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"), + DuplicateSpecifier: SingleTokenError("duplicate declaration specifier '{}'"), + MustUseKwToRefer: MustUseKwToRefer, + FnSpecOnNonFn: SingleTokenError("function specifier '{}' on non function"), + NothingDeclared: SimpleError("declaration doesn't declare anything"), + QualifierIgnored: SingleTokenError("qualifier '{}' ignored"), + + pub fn render(self: *const Error, tree: *Tree, stream: var) !void { + switch (self.*) { + .InvalidToken => |*x| return x.render(tree, stream), + .ExpectedToken => |*x| return x.render(tree, stream), + .ExpectedExpr => |*x| return x.render(tree, stream), + .ExpectedTypeName => |*x| return x.render(tree, stream), + .ExpectedDeclarator => |*x| return x.render(tree, stream), + .ExpectedFnBody => |*x| return x.render(tree, stream), + .ExpectedInitializer => |*x| return x.render(tree, stream), + .ExpectedEnumField => |*x| return x.render(tree, stream), + .ExpectedType => |*x| return x.render(tree, stream), + .InvalidTypeSpecifier => |*x| return x.render(tree, stream), + .InvalidStorageClass => |*x| return x.render(tree, stream), + .InvalidDeclarator => |*x| return x.render(tree, stream), + .DuplicateQualifier => |*x| return x.render(tree, stream), + .DuplicateSpecifier => |*x| return x.render(tree, stream), + .MustUseKwToRefer => |*x| return x.render(tree, stream), + .FnSpecOnNonFn => |*x| return x.render(tree, stream), + .NothingDeclared => |*x| return x.render(tree, stream), + .QualifierIgnored => |*x| return x.render(tree, stream), + } + } + + pub fn loc(self: *const Error) TokenIndex { + switch (self.*) { + .InvalidToken => |x| return x.token, + .ExpectedToken => |x| return x.token, + .ExpectedExpr => |x| return x.token, + .ExpectedTypeName => |x| return x.token, + .ExpectedDeclarator => |x| return x.token, + .ExpectedFnBody => |x| return x.token, + .ExpectedInitializer => |x| return x.token, + .ExpectedEnumField => |x| return x.token, + .ExpectedType => |*x| return x.token, + .InvalidTypeSpecifier => |x| return x.token, + .InvalidStorageClass => |x| return x.token, + .InvalidDeclarator => |x| return x.token, + .DuplicateQualifier => |x| return x.token, + .DuplicateSpecifier => |x| return x.token, + .MustUseKwToRefer => |*x| return x.name, + .FnSpecOnNonFn => |*x| return x.name, + .NothingDeclared => |*x| return x.name, + .QualifierIgnored => |*x| return x.name, + } + } + + pub const ExpectedToken = struct { + token: TokenIndex, + expected_id: @TagType(Token.Id), + + pub fn render(self: *const ExpectedToken, tree: *Tree, stream: var) !void { + const found_token = tree.tokens.at(self.token); + if (found_token.id == .Invalid) { + return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()}); + } else { + const token_name = found_token.id.symbol(); + return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name }); + } + } + }; + + pub const InvalidTypeSpecifier = struct { + token: TokenIndex, + type_spec: *Node.TypeSpec, + + pub fn render(self: *const ExpectedToken, tree: *Tree, stream: var) !void { + try stream.write("invalid type specifier '"); + try type_spec.spec.print(tree, stream); + const token_name = tree.tokens.at(self.token).id.symbol(); + return stream.print("{}'", .{token_name}); + } + }; + + pub const MustUseKwToRefer = struct { + kw: TokenIndex, + name: TokenIndex, + + pub fn render(self: *const ExpectedToken, tree: *Tree, stream: var) !void { + return stream.print("must use '{}' tag to refer to type '{}'", .{ tree.slice(kw), tree.slice(name) }); + } + }; + + fn SingleTokenError(comptime msg: []const u8) type { + return struct { + token: TokenIndex, + + pub fn render(self: *const @This(), tree: *Tree, stream: var) !void { + const actual_token = tree.tokens.at(self.token); + return stream.print(msg, .{actual_token.id.symbol()}); + } + }; + } + + fn SimpleError(comptime msg: []const u8) type { + return struct { + const ThisError = @This(); + + token: TokenIndex, + + pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void { + return stream.write(msg); + } + }; + } +}; + +pub const Type = struct { + pub const TypeList = std.SegmentedList(*Type, 4); + @"const": bool = false, + atomic: bool = false, + @"volatile": bool = false, + restrict: bool = false, + + id: union(enum) { + Int: struct { + id: Id, + is_signed: bool, + + pub const Id = enum { + Char, + Short, + Int, + Long, + LongLong, + }; + }, + Float: struct { + id: Id, + + pub const Id = enum { + Float, + Double, + LongDouble, + }; + }, + Pointer: *Type, + Function: struct { + return_type: *Type, + param_types: TypeList, + }, + Typedef: *Type, + Record: *Node.RecordType, + Enum: *Node.EnumType, + + /// Special case for macro parameters that can be any type. + /// Only present if `retain_macros == true`. + Macro, + }, +}; + +pub const Node = struct { + id: Id, + + pub const Id = enum { + Root, + EnumField, + RecordField, + RecordDeclarator, + JumpStmt, + ExprStmt, + LabeledStmt, + CompoundStmt, + IfStmt, + SwitchStmt, + WhileStmt, + DoStmt, + ForStmt, + StaticAssert, + Declarator, + Pointer, + FnDecl, + Typedef, + VarDecl, + }; + + pub const Root = struct { + base: Node = Node{ .id = .Root }, + decls: DeclList, + eof: TokenIndex, + + pub const DeclList = SegmentedList(*Node, 4); + }; + + pub const DeclSpec = struct { + storage_class: union(enum) { + Auto: TokenIndex, + Extern: TokenIndex, + Register: TokenIndex, + Static: TokenIndex, + Typedef: TokenIndex, + None, + } = .None, + thread_local: ?TokenIndex = null, + type_spec: TypeSpec = TypeSpec{}, + fn_spec: union(enum) { + Inline: TokenIndex, + Noreturn: TokenIndex, + None, + } = .None, + align_spec: ?struct { + alignas: TokenIndex, + expr: *Node, + rparen: TokenIndex, + } = null, + }; + + pub const TypeSpec = struct { + qual: TypeQual = TypeQual{}, + spec: union(enum) { + /// error or default to int + None, + Void: TokenIndex, + Char: struct { + sign: ?TokenIndex = null, + char: TokenIndex, + }, + Short: struct { + sign: ?TokenIndex = null, + short: TokenIndex = null, + int: ?TokenIndex = null, + }, + Int: struct { + sign: ?TokenIndex = null, + int: ?TokenIndex = null, + }, + Long: struct { + sign: ?TokenIndex = null, + long: TokenIndex, + longlong: ?TokenIndex = null, + int: ?TokenIndex = null, + }, + Float: struct { + float: TokenIndex, + complex: ?TokenIndex = null, + }, + Double: struct { + long: ?TokenIndex = null, + double: ?TokenIndex, + complex: ?TokenIndex = null, + }, + Bool: TokenIndex, + Atomic: struct { + atomic: TokenIndex, + typename: *Node, + rparen: TokenIndex, + }, + Enum: *EnumType, + Record: *RecordType, + Typedef: struct { + sym: TokenIndex, + sym_type: *Type, + }, + + pub fn print(self: *@This(), self: *const @This(), tree: *Tree, stream: var) !void { + switch (self.spec) { + .None => unreachable, + .Void => |index| try stream.write(tree.slice(index)), + .Char => |char| { + if (char.sign) |s| { + try stream.write(tree.slice(s)); + try stream.writeByte(' '); + } + try stream.write(tree.slice(char.char)); + }, + .Short => |short| { + if (short.sign) |s| { + try stream.write(tree.slice(s)); + try stream.writeByte(' '); + } + try stream.write(tree.slice(short.short)); + if (short.int) |i| { + try stream.writeByte(' '); + try stream.write(tree.slice(i)); + } + }, + .Int => |int| { + if (int.sign) |s| { + try stream.write(tree.slice(s)); + try stream.writeByte(' '); + } + if (int.int) |i| { + try stream.writeByte(' '); + try stream.write(tree.slice(i)); + } + }, + .Long => |long| { + if (long.sign) |s| { + try stream.write(tree.slice(s)); + try stream.writeByte(' '); + } + try stream.write(tree.slice(long.long)); + if (long.longlong) |l| { + try stream.writeByte(' '); + try stream.write(tree.slice(l)); + } + if (long.int) |i| { + try stream.writeByte(' '); + try stream.write(tree.slice(i)); + } + }, + .Float => |float| { + try stream.write(tree.slice(float.float)); + if (float.complex) |c| { + try stream.writeByte(' '); + try stream.write(tree.slice(c)); + } + }, + .Double => |double| { + if (double.long) |l| { + try stream.write(tree.slice(l)); + try stream.writeByte(' '); + } + try stream.write(tree.slice(double.double)); + if (double.complex) |c| { + try stream.writeByte(' '); + try stream.write(tree.slice(c)); + } + }, + .Bool => |index| try stream.write(tree.slice(index)), + .Typedef => |typedef| try stream.write(tree.slice(typedef.sym)), + else => try stream.print("TODO print {}", self.spec), + } + } + } = .None, + }; + + pub const EnumType = struct { + tok: TokenIndex, + name: ?TokenIndex, + body: ?struct { + lbrace: TokenIndex, + + /// always EnumField + fields: FieldList, + rbrace: TokenIndex, + }, + + pub const FieldList = Root.DeclList; + }; + + pub const EnumField = struct { + base: Node = Node{ .id = .EnumField }, + name: TokenIndex, + value: ?*Node, + }; + + pub const RecordType = struct { + tok: TokenIndex, + kind: enum { + Struct, + Union, + }, + name: ?TokenIndex, + body: ?struct { + lbrace: TokenIndex, + + /// RecordField or StaticAssert + fields: FieldList, + rbrace: TokenIndex, + }, + + pub const FieldList = Root.DeclList; + }; + + pub const RecordField = struct { + base: Node = Node{ .id = .RecordField }, + type_spec: TypeSpec, + declarators: DeclaratorList, + semicolon: TokenIndex, + + pub const DeclaratorList = Root.DeclList; + }; + + pub const RecordDeclarator = struct { + base: Node = Node{ .id = .RecordDeclarator }, + declarator: ?*Declarator, + bit_field_expr: ?*Expr, + }; + + pub const TypeQual = struct { + @"const": ?TokenIndex = null, + atomic: ?TokenIndex = null, + @"volatile": ?TokenIndex = null, + restrict: ?TokenIndex = null, + }; + + pub const JumpStmt = struct { + base: Node = Node{ .id = .JumpStmt }, + ltoken: TokenIndex, + kind: union(enum) { + Break, + Continue, + Return: ?*Node, + Goto: TokenIndex, + }, + semicolon: TokenIndex, + }; + + pub const ExprStmt = struct { + base: Node = Node{ .id = .ExprStmt }, + expr: ?*Expr, + semicolon: TokenIndex, + }; + + pub const LabeledStmt = struct { + base: Node = Node{ .id = .LabeledStmt }, + kind: union(enum) { + Label: TokenIndex, + Case: TokenIndex, + Default: TokenIndex, + }, + stmt: *Node, + }; + + pub const CompoundStmt = struct { + base: Node = Node{ .id = .CompoundStmt }, + lbrace: TokenIndex, + statements: StmtList, + rbrace: TokenIndex, + + pub const StmtList = Root.DeclList; + }; + + pub const IfStmt = struct { + base: Node = Node{ .id = .IfStmt }, + @"if": TokenIndex, + cond: *Node, + body: *Node, + @"else": ?struct { + tok: TokenIndex, + body: *Node, + }, + }; + + pub const SwitchStmt = struct { + base: Node = Node{ .id = .SwitchStmt }, + @"switch": TokenIndex, + expr: *Expr, + rparen: TokenIndex, + stmt: *Node, + }; + + pub const WhileStmt = struct { + base: Node = Node{ .id = .WhileStmt }, + @"while": TokenIndex, + cond: *Expr, + rparen: TokenIndex, + body: *Node, + }; + + pub const DoStmt = struct { + base: Node = Node{ .id = .DoStmt }, + do: TokenIndex, + body: *Node, + @"while": TokenIndex, + cond: *Expr, + semicolon: TokenIndex, + }; + + pub const ForStmt = struct { + base: Node = Node{ .id = .ForStmt }, + @"for": TokenIndex, + init: ?*Node, + cond: ?*Expr, + semicolon: TokenIndex, + incr: ?*Expr, + rparen: TokenIndex, + body: *Node, + }; + + pub const StaticAssert = struct { + base: Node = Node{ .id = .StaticAssert }, + assert: TokenIndex, + expr: *Node, + semicolon: TokenIndex, + }; + + pub const Declarator = struct { + base: Node = Node{ .id = .Declarator }, + pointer: ?*Pointer, + prefix: union(enum) { + None, + Identifer: TokenIndex, + Complex: struct { + lparen: TokenIndex, + inner: *Node, + rparen: TokenIndex, + }, + }, + suffix: union(enum) { + None, + Fn: struct { + lparen: TokenIndex, + params: Params, + rparen: TokenIndex, + }, + Array: Arrays, + }, + + pub const Arrays = std.SegmentedList(*Array, 2); + pub const Params = std.SegmentedList(*Param, 4); + }; + + pub const Array = struct { + lbracket: TokenIndex, + inner: union(enum) { + Inferred, + Unspecified: TokenIndex, + Variable: struct { + asterisk: ?TokenIndex, + static: ?TokenIndex, + qual: TypeQual, + expr: *Expr, + }, + }, + rbracket: TokenIndex, + }; + + pub const Pointer = struct { + base: Node = Node{ .id = .Pointer }, + asterisk: TokenIndex, + qual: TypeQual, + pointer: ?*Pointer, + }; + + pub const Param = struct { + kind: union(enum) { + Variable, + Old: TokenIndex, + Normal: struct { + decl_spec: *DeclSpec, + declarator: *Node, + }, + }, + }; + + pub const FnDecl = struct { + base: Node = Node{ .id = .FnDecl }, + decl_spec: DeclSpec, + declarator: *Declarator, + old_decls: OldDeclList, + body: ?*CompoundStmt, + + pub const OldDeclList = SegmentedList(*Node, 0); + }; + + pub const Typedef = struct { + base: Node = Node{ .id = .Typedef }, + decl_spec: DeclSpec, + declarators: DeclaratorList, + semicolon: TokenIndex, + + pub const DeclaratorList = Root.DeclList; + }; + + pub const VarDecl = struct { + base: Node = Node{ .id = .VarDecl }, + decl_spec: DeclSpec, + initializers: Initializers, + semicolon: TokenIndex, + + pub const Initializers = Root.DeclList; + }; + + pub const Initialized = struct { + base: Node = Node{ .id = Initialized }, + declarator: *Declarator, + eq: TokenIndex, + init: Initializer, + }; + + pub const Initializer = union(enum) { + list: struct { + initializers: InitializerList, + rbrace: TokenIndex, + }, + expr: *Expr, + pub const InitializerList = std.SegmentedList(*Initializer, 4); + }; + + pub const Macro = struct { + base: Node = Node{ .id = Macro }, + kind: union(enum) { + Undef: []const u8, + Fn: struct { + params: []const []const u8, + expr: *Expr, + }, + Expr: *Expr, + }, + }; +}; + +pub const Expr = struct { + id: Id, + ty: *Type, + value: union(enum) { + None, + }, + + pub const Id = enum { + Infix, + Literal, + }; + + pub const Infix = struct { + base: Expr = Expr{ .id = .Infix }, + lhs: *Expr, + op_token: TokenIndex, + op: Op, + rhs: *Expr, + + pub const Op = enum {}; + }; +}; diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index bc58b1fba1..524c82211e 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -7,7 +7,10 @@ usingnamespace @import("../os/bits.zig"); extern "c" fn __error() *c_int; pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int; +pub extern "c" fn _dyld_image_count() u32; pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header; +pub extern "c" fn _dyld_get_image_vmaddr_slide(image_index: u32) usize; +pub extern "c" fn _dyld_get_image_name(image_index: u32) [*:0]const u8; pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize; diff --git a/lib/std/c/parse.zig b/lib/std/c/parse.zig new file mode 100644 index 0000000000..dd646e06d6 --- /dev/null +++ b/lib/std/c/parse.zig @@ -0,0 +1,1431 @@ +const std = @import("std"); +const mem = std.mem; +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const ast = std.c.ast; +const Node = ast.Node; +const Type = ast.Type; +const Tree = ast.Tree; +const TokenIndex = ast.TokenIndex; +const Token = std.c.Token; +const TokenIterator = ast.Tree.TokenList.Iterator; + +pub const Error = error{ParseError} || Allocator.Error; + +pub const Options = struct { + // /// Keep simple macros unexpanded and add the definitions to the ast + // retain_macros: bool = false, + /// Warning or error + warn_as_err: union(enum) { + /// All warnings are warnings + None, + + /// Some warnings are errors + Some: []@TagType(ast.Error), + + /// All warnings are errors + All, + } = .All, +}; + +/// Result should be freed with tree.deinit() when there are +/// no more references to any of the tokens or nodes. +pub fn parse(allocator: *Allocator, source: []const u8, options: Options) !*Tree { + const tree = blk: { + // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists + // from being initialized with a pointer to this `arena`, which is created on + // the stack. Following code should instead refer to `&tree.arena_allocator`, a + // pointer to data which lives safely on the heap and will outlive `parse`. + var arena = std.heap.ArenaAllocator.init(allocator); + errdefer arena.deinit(); + const tree = try arena.allocator.create(ast.Tree); + tree.* = .{ + .root_node = undefined, + .arena_allocator = arena, + .tokens = undefined, + .sources = undefined, + }; + break :blk tree; + }; + errdefer tree.deinit(); + const arena = &tree.arena_allocator.allocator; + + tree.tokens = ast.Tree.TokenList.init(arena); + tree.sources = ast.Tree.SourceList.init(arena); + + var tokenizer = std.zig.Tokenizer.init(source); + while (true) { + const tree_token = try tree.tokens.addOne(); + tree_token.* = tokenizer.next(); + if (tree_token.id == .Eof) break; + } + // TODO preprocess here + var it = tree.tokens.iterator(0); + + while (true) { + const tok = it.peek().?.id; + switch (id) { + .LineComment, + .MultiLineComment, + => { + _ = it.next(); + }, + else => break, + } + } + + var parse_arena = std.heap.ArenaAllocator.init(allocator); + defer parse_arena.deinit(); + + var parser = Parser{ + .scopes = Parser.SymbolList.init(allocator), + .arena = &parse_arena.allocator, + .it = &it, + .tree = tree, + .options = options, + }; + defer parser.symbols.deinit(); + + tree.root_node = try parser.root(); + return tree; +} + +const Parser = struct { + arena: *Allocator, + it: *TokenIterator, + tree: *Tree, + + arena: *Allocator, + scopes: ScopeList, + options: Options, + + const ScopeList = std.SegmentedLists(Scope); + const SymbolList = std.SegmentedLists(Symbol); + + const Scope = struct { + kind: ScopeKind, + syms: SymbolList, + }; + + const Symbol = struct { + name: []const u8, + ty: *Type, + }; + + const ScopeKind = enum { + Block, + Loop, + Root, + Switch, + }; + + fn pushScope(parser: *Parser, kind: ScopeKind) !void { + const new = try parser.scopes.addOne(); + new.* = .{ + .kind = kind, + .syms = SymbolList.init(parser.arena), + }; + } + + fn popScope(parser: *Parser, len: usize) void { + _ = parser.scopes.pop(); + } + + fn getSymbol(parser: *Parser, tok: TokenIndex) ?*Symbol { + const name = parser.tree.tokenSlice(tok); + var scope_it = parser.scopes.iterator(parser.scopes.len); + while (scope_it.prev()) |scope| { + var sym_it = scope.syms.iterator(scope.syms.len); + while (sym_it.prev()) |sym| { + if (mem.eql(u8, sym.name, name)) { + return sym; + } + } + } + return null; + } + + fn declareSymbol(parser: *Parser, type_spec: Node.TypeSpec, dr: *Node.Declarator) Error!void { + return; // TODO + } + + /// Root <- ExternalDeclaration* eof + fn root(parser: *Parser) Allocator.Error!*Node.Root { + try parser.pushScope(.Root); + defer parser.popScope(); + const node = try parser.arena.create(Node.Root); + node.* = .{ + .decls = Node.Root.DeclList.init(parser.arena), + .eof = undefined, + }; + while (parser.externalDeclarations() catch |e| switch (e) { + error.OutOfMemory => return error.OutOfMemory, + error.ParseError => return node, + }) |decl| { + try node.decls.push(decl); + } + node.eof = parser.eatToken(.Eof) orelse return node; + return node; + } + + /// ExternalDeclaration + /// <- DeclSpec Declarator OldStyleDecl* CompoundStmt + /// / Declaration + /// OldStyleDecl <- DeclSpec Declarator (COMMA Declarator)* SEMICOLON + fn externalDeclarations(parser: *Parser) !?*Node { + return parser.declarationExtra(false); + } + + /// Declaration + /// <- DeclSpec DeclInit SEMICOLON + /// / StaticAssert + /// DeclInit <- Declarator (EQUAL Initializer)? (COMMA Declarator (EQUAL Initializer)?)* + fn declaration(parser: *Parser) !?*Node { + return parser.declarationExtra(true); + } + + fn declarationExtra(parser: *Parser, local: bool) !?*Node { + if (try parser.staticAssert()) |decl| return decl; + const begin = parser.it.index + 1; + var ds = Node.DeclSpec{}; + const got_ds = try parser.declSpec(&ds); + if (local and !got_ds) { + // not a declaration + return null; + } + switch (ds.storage_class) { + .Auto, .Register => |tok| return parser.err(.{ + .InvalidStorageClass = .{ .token = tok }, + }), + .Typedef => { + const node = try parser.arena.create(Node.Typedef); + node.* = .{ + .decl_spec = ds, + .declarators = Node.Typedef.DeclaratorList.init(parser.arena), + .semicolon = undefined, + }; + while (true) { + const dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{ + .ExpectedDeclarator = .{ .token = parser.it.index }, + })); + try parser.declareSymbol(ds.type_spec, dr); + try node.declarators.push(&dr.base); + if (parser.eatToken(.Comma)) |_| {} else break; + } + return &node.base; + }, + else => {}, + } + var first_dr = try parser.declarator(.Must); + if (first_dr != null and declaratorIsFunction(first_dr.?)) { + // TODO typedeffed fn proto-only + const dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?); + try parser.declareSymbol(ds.type_spec, dr); + var old_decls = Node.FnDecl.OldDeclList.init(parser.arena); + const body = if (parser.eatToken(.Semicolon)) |_| + null + else blk: { + if (local) { + // TODO nested function warning + } + // TODO first_dr.is_old + // while (true) { + // var old_ds = Node.DeclSpec{}; + // if (!(try parser.declSpec(&old_ds))) { + // // not old decl + // break; + // } + // var old_dr = (try parser.declarator(.Must)); + // // if (old_dr == null) + // // try parser.err(.{ + // // .NoParamName = .{ .token = parser.it.index }, + // // }); + // // try old_decls.push(decl); + // } + const body_node = (try parser.compoundStmt()) orelse return parser.err(.{ + .ExpectedFnBody = .{ .token = parser.it.index }, + }); + break :blk @fieldParentPtr(Node.CompoundStmt, "base", body_node); + }; + + const node = try parser.arena.create(Node.FnDecl); + node.* = .{ + .decl_spec = ds, + .declarator = dr, + .old_decls = old_decls, + .body = body, + }; + return &node.base; + } else { + switch (ds.fn_spec) { + .Inline, .Noreturn => |tok| return parser.err(.{ + .FnSpecOnNonFn = .{ .token = tok }, + }), + else => {}, + } + // TODO threadlocal without static or extern on local variable + const node = try parser.arena.create(Node.VarDecl); + node.* = .{ + .decl_spec = ds, + .initializers = Node.VarDecl.Initializers.init(parser.arena), + .semicolon = undefined, + }; + if (first_dr == null) { + node.semicolon = try parser.expectToken(.Semicolon); + const ok = switch (ds.type_spec.spec) { + .Enum => |e| e.name != null, + .Record => |r| r.name != null, + else => false, + }; + const q = ds.type_spec.qual; + if (!ok) + try parser.warn(.{ + .NothingDeclared = .{ .token = begin }, + }) + else if (q.@"const" orelse q.atomic orelse q.@"volatile" orelse q.restrict) |tok| + try parser.warn(.{ + .QualifierIgnored = .{ .token = tok }, + }); + return &node.base; + } + var dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?); + while (true) { + try parser.declareSymbol(ds.type_spec, dr); + if (parser.eatToken(.Equal)) |tok| { + try node.initializers.push((try parser.initializer(dr)) orelse return parser.err(.{ + .ExpectedInitializer = .{ .token = parser.it.index }, + })); + } else + try node.initializers.push(&dr.base); + if (parser.eatToken(.Comma) != null) break; + dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{ + .ExpectedDeclarator = .{ .token = parser.it.index }, + })); + } + node.semicolon = try parser.expectToken(.Semicolon); + return &node.base; + } + } + + fn declaratorIsFunction(node: *Node) bool { + if (node.id != .Declarator) return false; + assert(node.id == .Declarator); + const dr = @fieldParentPtr(Node.Declarator, "base", node); + if (dr.suffix != .Fn) return false; + switch (dr.prefix) { + .None, .Identifer => return true, + .Complex => |inner| { + var inner_node = inner.inner; + while (true) { + if (inner_node.id != .Declarator) return false; + assert(inner_node.id == .Declarator); + const inner_dr = @fieldParentPtr(Node.Declarator, "base", inner_node); + if (inner_dr.pointer != null) return false; + switch (inner_dr.prefix) { + .None, .Identifer => return true, + .Complex => |c| inner_node = c.inner, + } + } + }, + } + } + + /// StaticAssert <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON + fn staticAssert(parser: *Parser) !?*Node { + const tok = parser.eatToken(.Keyword_static_assert) orelse return null; + _ = try parser.expectToken(.LParen); + const const_expr = (try parser.constExpr()) orelse parser.err(.{ + .ExpectedExpr = .{ .token = parser.it.index }, + }); + _ = try parser.expectToken(.Comma); + const str = try parser.expectToken(.StringLiteral); + _ = try parser.expectToken(.RParen); + const node = try parser.arena.create(Node.StaticAssert); + node.* = .{ + .assert = tok, + .expr = const_expr, + .semicolon = try parser.expectToken(.Semicolon), + }; + return &node.base; + } + + /// DeclSpec <- (StorageClassSpec / TypeSpec / FnSpec / AlignSpec)* + /// returns true if any tokens were consumed + fn declSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { + var got = false; + while ((try parser.storageClassSpec(ds)) or (try parser.typeSpec(&ds.type_spec)) or (try parser.fnSpec(ds)) or (try parser.alignSpec(ds))) { + got = true; + } + return got; + } + + /// StorageClassSpec + /// <- Keyword_typedef / Keyword_extern / Keyword_static / Keyword_thread_local / Keyword_auto / Keyword_register + fn storageClassSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { + blk: { + if (parser.eatToken(.Keyword_typedef)) |tok| { + if (ds.storage_class != .None or ds.thread_local != null) + break :blk; + ds.storage_class = .{ .Typedef = tok }; + } else if (parser.eatToken(.Keyword_extern)) |tok| { + if (ds.storage_class != .None) + break :blk; + ds.storage_class = .{ .Extern = tok }; + } else if (parser.eatToken(.Keyword_static)) |tok| { + if (ds.storage_class != .None) + break :blk; + ds.storage_class = .{ .Static = tok }; + } else if (parser.eatToken(.Keyword_thread_local)) |tok| { + switch (ds.storage_class) { + .None, .Extern, .Static => {}, + else => break :blk, + } + ds.thread_local = tok; + } else if (parser.eatToken(.Keyword_auto)) |tok| { + if (ds.storage_class != .None or ds.thread_local != null) + break :blk; + ds.storage_class = .{ .Auto = tok }; + } else if (parser.eatToken(.Keyword_register)) |tok| { + if (ds.storage_class != .None or ds.thread_local != null) + break :blk; + ds.storage_class = .{ .Register = tok }; + } else return false; + return true; + } + try parser.warn(.{ + .DuplicateSpecifier = .{ .token = parser.it.index }, + }); + return true; + } + + /// TypeSpec + /// <- Keyword_void / Keyword_char / Keyword_short / Keyword_int / Keyword_long / Keyword_float / Keyword_double + /// / Keyword_signed / Keyword_unsigned / Keyword_bool / Keyword_complex / Keyword_imaginary / + /// / Keyword_atomic LPAREN TypeName RPAREN + /// / EnumSpec + /// / RecordSpec + /// / IDENTIFIER // typedef name + /// / TypeQual + fn typeSpec(parser: *Parser, type_spec: *Node.TypeSpec) !bool { + blk: { + if (parser.eatToken(.Keyword_void)) |tok| { + if (type_spec.spec != .None) + break :blk; + type_spec.spec = .{ .Void = tok }; + } else if (parser.eatToken(.Keyword_char)) |tok| { + switch (type_spec.spec) { + .None => { + type_spec.spec = .{ + .Char = .{ + .char = tok, + }, + }; + }, + .Int => |int| { + if (int.int != null) + break :blk; + type_spec.spec = .{ + .Char = .{ + .char = tok, + .sign = int.sign, + }, + }; + }, + else => break :blk, + } + } else if (parser.eatToken(.Keyword_short)) |tok| { + switch (type_spec.spec) { + .None => { + type_spec.spec = .{ + .Short = .{ + .short = tok, + }, + }; + }, + .Int => |int| { + if (int.int != null) + break :blk; + type_spec.spec = .{ + .Short = .{ + .short = tok, + .sign = int.sign, + }, + }; + }, + else => break :blk, + } + } else if (parser.eatToken(.Keyword_long)) |tok| { + switch (type_spec.spec) { + .None => { + type_spec.spec = .{ + .Long = .{ + .long = tok, + }, + }; + }, + .Int => |int| { + type_spec.spec = .{ + .Long = .{ + .long = tok, + .sign = int.sign, + .int = int.int, + }, + }; + }, + .Long => |*long| { + if (long.longlong != null) + break :blk; + long.longlong = tok; + }, + .Double => |*double| { + if (double.long != null) + break :blk; + double.long = tok; + }, + else => break :blk, + } + } else if (parser.eatToken(.Keyword_int)) |tok| { + switch (type_spec.spec) { + .None => { + type_spec.spec = .{ + .Int = .{ + .int = tok, + }, + }; + }, + .Short => |*short| { + if (short.int != null) + break :blk; + short.int = tok; + }, + .Int => |*int| { + if (int.int != null) + break :blk; + int.int = tok; + }, + .Long => |*long| { + if (long.int != null) + break :blk; + long.int = tok; + }, + else => break :blk, + } + } else if (parser.eatToken(.Keyword_signed) orelse parser.eatToken(.Keyword_unsigned)) |tok| { + switch (type_spec.spec) { + .None => { + type_spec.spec = .{ + .Int = .{ + .sign = tok, + }, + }; + }, + .Char => |*char| { + if (char.sign != null) + break :blk; + char.sign = tok; + }, + .Short => |*short| { + if (short.sign != null) + break :blk; + short.sign = tok; + }, + .Int => |*int| { + if (int.sign != null) + break :blk; + int.sign = tok; + }, + .Long => |*long| { + if (long.sign != null) + break :blk; + long.sign = tok; + }, + else => break :blk, + } + } else if (parser.eatToken(.Keyword_float)) |tok| { + if (type_spec.spec != .None) + break :blk; + type_spec.spec = .{ + .Float = .{ + .float = tok, + }, + }; + } else if (parser.eatToken(.Keyword_double)) |tok| { + if (type_spec.spec != .None) + break :blk; + type_spec.spec = .{ + .Double = .{ + .double = tok, + }, + }; + } else if (parser.eatToken(.Keyword_complex)) |tok| { + switch (type_spec.spec) { + .None => { + type_spec.spec = .{ + .Double = .{ + .complex = tok, + .double = null, + }, + }; + }, + .Float => |*float| { + if (float.complex != null) + break :blk; + float.complex = tok; + }, + .Double => |*double| { + if (double.complex != null) + break :blk; + double.complex = tok; + }, + else => break :blk, + } + } else if (parser.eatToken(.Keyword_bool)) |tok| { + if (type_spec.spec != .None) + break :blk; + type_spec.spec = .{ .Bool = tok }; + } else if (parser.eatToken(.Keyword_atomic)) |tok| { + // might be _Atomic qualifier + if (parser.eatToken(.LParen)) |_| { + if (type_spec.spec != .None) + break :blk; + const name = (try parser.typeName()) orelse return parser.err(.{ + .ExpectedTypeName = .{ .token = parser.it.index }, + }); + type_spec.spec.Atomic = .{ + .atomic = tok, + .typename = name, + .rparen = try parser.expectToken(.RParen), + }; + } else { + parser.putBackToken(tok); + } + } else if (parser.eatToken(.Keyword_enum)) |tok| { + if (type_spec.spec != .None) + break :blk; + type_spec.spec.Enum = try parser.enumSpec(tok); + } else if (parser.eatToken(.Keyword_union) orelse parser.eatToken(.Keyword_struct)) |tok| { + if (type_spec.spec != .None) + break :blk; + type_spec.spec.Record = try parser.recordSpec(tok); + } else if (parser.eatToken(.Identifier)) |tok| { + const ty = parser.getSymbol(tok) orelse { + parser.putBackToken(tok); + return false; + }; + switch (ty.id) { + .Enum => |e| blk: { + if (e.name) |some| + if (!parser.tree.tokenEql(some, tok)) + break :blk; + return parser.err(.{ + .MustUseKwToRefer = .{ .kw = e.tok, .name = tok }, + }); + }, + .Record => |r| blk: { + if (r.name) |some| + if (!parser.tree.tokenEql(some, tok)) + break :blk; + return parser.err(.{ + .MustUseKwToRefer = .{ + .kw = r.tok, + .name = tok, + }, + }); + }, + .Typedef => { + type_spec.spec = .{ + .Typedef = .{ + .sym = tok, + .sym_type = ty, + }, + }; + return true; + }, + else => {}, + } + parser.putBackToken(tok); + return false; + } + return parser.typeQual(&type_spec.qual); + } + return parser.err(.{ + .InvalidTypeSpecifier = .{ + .token = parser.it.index, + .type_spec = type_spec, + }, + }); + } + + /// TypeQual <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic + fn typeQual(parser: *Parser, qual: *Node.TypeQual) !bool { + blk: { + if (parser.eatToken(.Keyword_const)) |tok| { + if (qual.@"const" != null) + break :blk; + qual.@"const" = tok; + } else if (parser.eatToken(.Keyword_restrict)) |tok| { + if (qual.atomic != null) + break :blk; + qual.atomic = tok; + } else if (parser.eatToken(.Keyword_volatile)) |tok| { + if (qual.@"volatile" != null) + break :blk; + qual.@"volatile" = tok; + } else if (parser.eatToken(.Keyword_atomic)) |tok| { + if (qual.atomic != null) + break :blk; + qual.atomic = tok; + } else return false; + return true; + } + try parser.warn(.{ + .DuplicateQualifier = .{ .token = parser.it.index }, + }); + return true; + } + + /// FnSpec <- Keyword_inline / Keyword_noreturn + fn fnSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { + blk: { + if (parser.eatToken(.Keyword_inline)) |tok| { + if (ds.fn_spec != .None) + break :blk; + ds.fn_spec = .{ .Inline = tok }; + } else if (parser.eatToken(.Keyword_noreturn)) |tok| { + if (ds.fn_spec != .None) + break :blk; + ds.fn_spec = .{ .Noreturn = tok }; + } else return false; + return true; + } + try parser.warn(.{ + .DuplicateSpecifier = .{ .token = parser.it.index }, + }); + return true; + } + + /// AlignSpec <- Keyword_alignas LPAREN (TypeName / ConstExpr) RPAREN + fn alignSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { + if (parser.eatToken(.Keyword_alignas)) |tok| { + _ = try parser.expectToken(.LParen); + const node = (try parser.typeName()) orelse (try parser.constExpr()) orelse parser.err(.{ + .ExpectedExpr = .{ .token = parser.it.index }, + }); + if (ds.align_spec != null) { + try parser.warn(.{ + .DuplicateSpecifier = .{ .token = parser.it.index }, + }); + } + ds.align_spec = .{ + .alignas = tok, + .expr = node, + .rparen = try parser.expectToken(.RParen), + }; + return true; + } + return false; + } + + /// EnumSpec <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)? + fn enumSpec(parser: *Parser, tok: TokenIndex) !*Node.EnumType { + const node = try parser.arena.create(Node.EnumType); + const name = parser.eatToken(.Identifier); + node.* = .{ + .tok = tok, + .name = name, + .body = null, + }; + const ty = try parser.arena.create(Type); + ty.* = .{ + .id = .{ + .Enum = node, + }, + }; + if (name) |some| + try parser.symbols.append(.{ + .name = parser.tree.tokenSlice(some), + .ty = ty, + }); + if (parser.eatToken(.LBrace)) |lbrace| { + var fields = Node.EnumType.FieldList.init(parser.arena); + try fields.push((try parser.enumField()) orelse return parser.err(.{ + .ExpectedEnumField = .{ .token = parser.it.index }, + })); + while (parser.eatToken(.Comma)) |_| { + try fields.push((try parser.enumField()) orelse break); + } + node.body = .{ + .lbrace = lbrace, + .fields = fields, + .rbrace = try parser.expectToken(.RBrace), + }; + } + return node; + } + + /// EnumField <- IDENTIFIER (EQUAL ConstExpr)? (COMMA EnumField) COMMA? + fn enumField(parser: *Parser) !?*Node { + const name = parser.eatToken(.Identifier) orelse return null; + const node = try parser.arena.create(Node.EnumField); + node.* = .{ + .name = name, + .value = null, + }; + if (parser.eatToken(.Equal)) |eq| { + node.value = (try parser.constExpr()) orelse parser.err(.{ + .ExpectedExpr = .{ .token = parser.it.index }, + }); + } + return &node.base; + } + + /// RecordSpec <- (Keyword_struct / Keyword_union) IDENTIFIER? (LBRACE RecordField+ RBRACE)? + fn recordSpec(parser: *Parser, tok: TokenIndex) !*Node.RecordType { + const node = try parser.arena.create(Node.RecordType); + const name = parser.eatToken(.Identifier); + const is_struct = parser.tree.tokenSlice(tok)[0] == 's'; + node.* = .{ + .tok = tok, + .kind = if (is_struct) .Struct else .Union, + .name = name, + .body = null, + }; + const ty = try parser.arena.create(Type); + ty.* = .{ + .id = .{ + .Record = node, + }, + }; + if (name) |some| + try parser.symbols.append(.{ + .name = parser.tree.tokenSlice(some), + .ty = ty, + }); + if (parser.eatToken(.LBrace)) |lbrace| { + try parser.pushScope(.Block); + defer parser.popScope(); + var fields = Node.RecordType.FieldList.init(parser.arena); + while (true) { + if (parser.eatToken(.RBrace)) |rbrace| { + node.body = .{ + .lbrace = lbrace, + .fields = fields, + .rbrace = rbrace, + }; + break; + } + try fields.push(try parser.recordField()); + } + } + return node; + } + + /// RecordField + /// <- TypeSpec* (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON + /// \ StaticAssert + fn recordField(parser: *Parser) Error!*Node { + if (try parser.staticAssert()) |decl| return decl; + var got = false; + var type_spec = Node.TypeSpec{}; + while (try parser.typeSpec(&type_spec)) got = true; + if (!got) + return parser.err(.{ + .ExpectedType = .{ .token = parser.it.index }, + }); + const node = try parser.arena.create(Node.RecordField); + node.* = .{ + .type_spec = type_spec, + .declarators = Node.RecordField.DeclaratorList.init(parser.arena), + .semicolon = undefined, + }; + while (true) { + const rdr = try parser.recordDeclarator(); + try parser.declareSymbol(type_spec, rdr.declarator); + try node.declarators.push(&rdr.base); + if (parser.eatToken(.Comma)) |_| {} else break; + } + + node.semicolon = try parser.expectToken(.Semicolon); + return &node.base; + } + + /// TypeName <- TypeSpec* AbstractDeclarator? + fn typeName(parser: *Parser) Error!?*Node { + @panic("TODO"); + } + + /// RecordDeclarator <- Declarator? (COLON ConstExpr)? + fn recordDeclarator(parser: *Parser) Error!*Node.RecordDeclarator { + @panic("TODO"); + } + + /// Pointer <- ASTERISK TypeQual* Pointer? + fn pointer(parser: *Parser) Error!?*Node.Pointer { + const asterisk = parser.eatToken(.Asterisk) orelse return null; + const node = try parser.arena.create(Node.Pointer); + node.* = .{ + .asterisk = asterisk, + .qual = .{}, + .pointer = null, + }; + while (try parser.typeQual(&node.qual)) {} + node.pointer = try parser.pointer(); + return node; + } + + const Named = enum { + Must, + Allowed, + Forbidden, + }; + + /// Declarator <- Pointer? DeclaratorSuffix + /// DeclaratorPrefix + /// <- IDENTIFIER // if named != .Forbidden + /// / LPAREN Declarator RPAREN + /// / (none) // if named != .Must + /// DeclaratorSuffix + /// <- DeclaratorPrefix (LBRACKET ArrayDeclarator? RBRACKET)* + /// / DeclaratorPrefix LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN + fn declarator(parser: *Parser, named: Named) Error!?*Node { + const ptr = try parser.pointer(); + var node: *Node.Declarator = undefined; + var inner_fn = false; + + // TODO sizof(int (int)) + // prefix + if (parser.eatToken(.LParen)) |lparen| { + const inner = (try parser.declarator(named)) orelse return parser.err(.{ + .ExpectedDeclarator = .{ .token = lparen + 1 }, + }); + inner_fn = declaratorIsFunction(inner); + node = try parser.arena.create(Node.Declarator); + node.* = .{ + .pointer = ptr, + .prefix = .{ + .Complex = .{ + .lparen = lparen, + .inner = inner, + .rparen = try parser.expectToken(.RParen), + }, + }, + .suffix = .None, + }; + } else if (named != .Forbidden) { + if (parser.eatToken(.Identifier)) |tok| { + node = try parser.arena.create(Node.Declarator); + node.* = .{ + .pointer = ptr, + .prefix = .{ .Identifer = tok }, + .suffix = .None, + }; + } else if (named == .Must) { + return parser.err(.{ + .ExpectedToken = .{ .token = parser.it.index, .expected_id = .Identifier }, + }); + } else { + if (ptr) |some| + return &some.base; + return null; + } + } else { + node = try parser.arena.create(Node.Declarator); + node.* = .{ + .pointer = ptr, + .prefix = .None, + .suffix = .None, + }; + } + // suffix + if (parser.eatToken(.LParen)) |lparen| { + if (inner_fn) + return parser.err(.{ + .InvalidDeclarator = .{ .token = lparen }, + }); + node.suffix = .{ + .Fn = .{ + .lparen = lparen, + .params = Node.Declarator.Params.init(parser.arena), + .rparen = undefined, + }, + }; + try parser.paramDecl(node); + node.suffix.Fn.rparen = try parser.expectToken(.RParen); + } else if (parser.eatToken(.LBracket)) |tok| { + if (inner_fn) + return parser.err(.{ + .InvalidDeclarator = .{ .token = tok }, + }); + node.suffix = .{ .Array = Node.Declarator.Arrays.init(parser.arena) }; + var lbrace = tok; + while (true) { + try node.suffix.Array.push(try parser.arrayDeclarator(lbrace)); + if (parser.eatToken(.LBracket)) |t| lbrace = t else break; + } + } + if (parser.eatToken(.LParen) orelse parser.eatToken(.LBracket)) |tok| + return parser.err(.{ + .InvalidDeclarator = .{ .token = tok }, + }); + return &node.base; + } + + /// ArrayDeclarator + /// <- ASTERISK + /// / Keyword_static TypeQual* AssignmentExpr + /// / TypeQual+ (ASTERISK / Keyword_static AssignmentExpr) + /// / TypeQual+ AssignmentExpr? + /// / AssignmentExpr + fn arrayDeclarator(parser: *Parser, lbracket: TokenIndex) !*Node.Array { + const arr = try parser.arena.create(Node.Array); + arr.* = .{ + .lbracket = lbracket, + .inner = .Inferred, + .rbracket = undefined, + }; + if (parser.eatToken(.Asterisk)) |tok| { + arr.inner = .{ .Unspecified = tok }; + } else { + // TODO + } + arr.rbracket = try parser.expectToken(.RBracket); + return arr; + } + + /// Params <- ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)? + /// ParamDecl <- DeclSpec (Declarator / AbstractDeclarator) + fn paramDecl(parser: *Parser, dr: *Node.Declarator) !void { + var old_style = false; + while (true) { + var ds = Node.DeclSpec{}; + if (try parser.declSpec(&ds)) { + //TODO + // TODO try parser.declareSymbol(ds.type_spec, dr); + } else if (parser.eatToken(.Identifier)) |tok| { + old_style = true; + } else if (parser.eatToken(.Ellipsis)) |tok| { + // TODO + } + } + } + + /// Expr <- AssignmentExpr (COMMA Expr)* + fn expr(parser: *Parser) Error!?*Expr { + @panic("TODO"); + } + + /// AssignmentExpr + /// <- ConditionalExpr // TODO recursive? + /// / UnaryExpr (EQUAL / ASTERISKEQUAL / SLASHEQUAL / PERCENTEQUAL / PLUSEQUAL / MINUSEQUA / + /// / ANGLEBRACKETANGLEBRACKETLEFTEQUAL / ANGLEBRACKETANGLEBRACKETRIGHTEQUAL / + /// / AMPERSANDEQUAL / CARETEQUAL / PIPEEQUAL) AssignmentExpr + fn assignmentExpr(parser: *Parser) !?*Expr { + @panic("TODO"); + } + + /// ConstExpr <- ConditionalExpr + fn constExpr(parser: *Parser) Error!?*Expr { + const start = parser.it.index; + const expression = try parser.conditionalExpr(); + if (expression != null and expression.?.value == .None) + return parser.err(.{ + .ConsExpr = start, + }); + return expression; + } + + /// ConditionalExpr <- LogicalOrExpr (QUESTIONMARK Expr COLON ConditionalExpr)? + fn conditionalExpr(parser: *Parser) Error!?*Expr { + @panic("TODO"); + } + + /// LogicalOrExpr <- LogicalAndExpr (PIPEPIPE LogicalOrExpr)* + fn logicalOrExpr(parser: *Parser) !*Node { + const lhs = (try parser.logicalAndExpr()) orelse return null; + } + + /// LogicalAndExpr <- BinOrExpr (AMPERSANDAMPERSAND LogicalAndExpr)* + fn logicalAndExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// BinOrExpr <- BinXorExpr (PIPE BinOrExpr)* + fn binOrExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// BinXorExpr <- BinAndExpr (CARET BinXorExpr)* + fn binXorExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// BinAndExpr <- EqualityExpr (AMPERSAND BinAndExpr)* + fn binAndExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// EqualityExpr <- ComparisionExpr ((EQUALEQUAL / BANGEQUAL) EqualityExpr)* + fn equalityExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// ComparisionExpr <- ShiftExpr (ANGLEBRACKETLEFT / ANGLEBRACKETLEFTEQUAL /ANGLEBRACKETRIGHT / ANGLEBRACKETRIGHTEQUAL) ComparisionExpr)* + fn comparisionExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// ShiftExpr <- AdditiveExpr (ANGLEBRACKETANGLEBRACKETLEFT / ANGLEBRACKETANGLEBRACKETRIGHT) ShiftExpr)* + fn shiftExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// AdditiveExpr <- MultiplicativeExpr (PLUS / MINUS) AdditiveExpr)* + fn additiveExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// MultiplicativeExpr <- UnaryExpr (ASTERISK / SLASH / PERCENT) MultiplicativeExpr)* + fn multiplicativeExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// UnaryExpr + /// <- LPAREN TypeName RPAREN UnaryExpr + /// / Keyword_sizeof LAPERN TypeName RPAREN + /// / Keyword_sizeof UnaryExpr + /// / Keyword_alignof LAPERN TypeName RPAREN + /// / (AMPERSAND / ASTERISK / PLUS / PLUSPLUS / MINUS / MINUSMINUS / TILDE / BANG) UnaryExpr + /// / PrimaryExpr PostFixExpr* + fn unaryExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// PrimaryExpr + /// <- IDENTIFIER + /// / INTEGERLITERAL / FLOATLITERAL / STRINGLITERAL / CHARLITERAL + /// / LPAREN Expr RPAREN + /// / Keyword_generic LPAREN AssignmentExpr (COMMA Generic)+ RPAREN + fn primaryExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// Generic + /// <- TypeName COLON AssignmentExpr + /// / Keyword_default COLON AssignmentExpr + fn generic(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// PostFixExpr + /// <- LPAREN TypeName RPAREN LBRACE Initializers RBRACE + /// / LBRACKET Expr RBRACKET + /// / LPAREN (AssignmentExpr (COMMA AssignmentExpr)*)? RPAREN + /// / (PERIOD / ARROW) IDENTIFIER + /// / (PLUSPLUS / MINUSMINUS) + fn postFixExpr(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// Initializers <- ((Designator+ EQUAL)? Initializer COMMA)* (Designator+ EQUAL)? Initializer COMMA? + fn initializers(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// Initializer + /// <- LBRACE Initializers RBRACE + /// / AssignmentExpr + fn initializer(parser: *Parser, dr: *Node.Declarator) Error!?*Node { + @panic("TODO"); + } + + /// Designator + /// <- LBRACKET ConstExpr RBRACKET + /// / PERIOD IDENTIFIER + fn designator(parser: *Parser) !*Node { + @panic("TODO"); + } + + /// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE + fn compoundStmt(parser: *Parser) Error!?*Node { + const lbrace = parser.eatToken(.LBrace) orelse return null; + try parser.pushScope(.Block); + defer parser.popScope(); + const body_node = try parser.arena.create(Node.CompoundStmt); + body_node.* = .{ + .lbrace = lbrace, + .statements = Node.CompoundStmt.StmtList.init(parser.arena), + .rbrace = undefined, + }; + while (true) { + if (parser.eatToken(.RBRACE)) |rbrace| { + body_node.rbrace = rbrace; + break; + } + try body_node.statements.push((try parser.declaration()) orelse (try parser.stmt())); + } + return &body_node.base; + } + + /// Stmt + /// <- CompoundStmt + /// / Keyword_if LPAREN Expr RPAREN Stmt (Keyword_ELSE Stmt)? + /// / Keyword_switch LPAREN Expr RPAREN Stmt + /// / Keyword_while LPAREN Expr RPAREN Stmt + /// / Keyword_do statement Keyword_while LPAREN Expr RPAREN SEMICOLON + /// / Keyword_for LPAREN (Declaration / ExprStmt) ExprStmt Expr? RPAREN Stmt + /// / Keyword_default COLON Stmt + /// / Keyword_case ConstExpr COLON Stmt + /// / Keyword_goto IDENTIFIER SEMICOLON + /// / Keyword_continue SEMICOLON + /// / Keyword_break SEMICOLON + /// / Keyword_return Expr? SEMICOLON + /// / IDENTIFIER COLON Stmt + /// / ExprStmt + fn stmt(parser: *Parser) Error!*Node { + if (try parser.compoundStmt()) |node| return node; + if (parser.eatToken(.Keyword_if)) |tok| { + const node = try parser.arena.create(Node.IfStmt); + _ = try parser.expectToken(.LParen); + node.* = .{ + .@"if" = tok, + .cond = (try parser.expr()) orelse return parser.err(.{ + .ExpectedExpr = .{ .token = parser.it.index }, + }), + .body = undefined, + .@"else" = null, + }; + _ = try parser.expectToken(.RParen); + node.body = try parser.stmt(); + if (parser.eatToken(.Keyword_else)) |else_tok| { + node.@"else" = .{ + .tok = else_tok, + .body = try parser.stmt(), + }; + } + return &node.base; + } + if (parser.eatToken(.Keyword_while)) |tok| { + try parser.pushScope(.Loop); + defer parser.popScope(); + _ = try parser.expectToken(.LParen); + const cond = (try parser.expr()) orelse return parser.err(.{ + .ExpectedExpr = .{ .token = parser.it.index }, + }); + const rparen = try parser.expectToken(.RParen); + const node = try parser.arena.create(Node.WhileStmt); + node.* = .{ + .@"while" = tok, + .cond = cond, + .rparen = rparen, + .body = try parser.stmt(), + .semicolon = try parser.expectToken(.Semicolon), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_do)) |tok| { + try parser.pushScope(.Loop); + defer parser.popScope(); + const body = try parser.stmt(); + _ = try parser.expectToken(.LParen); + const cond = (try parser.expr()) orelse return parser.err(.{ + .ExpectedExpr = .{ .token = parser.it.index }, + }); + _ = try parser.expectToken(.RParen); + const node = try parser.arena.create(Node.DoStmt); + node.* = .{ + .do = tok, + .body = body, + .cond = cond, + .@"while" = @"while", + .semicolon = try parser.expectToken(.Semicolon), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_for)) |tok| { + try parser.pushScope(.Loop); + defer parser.popScope(); + _ = try parser.expectToken(.LParen); + const init = if (try parser.declaration()) |decl| blk: { + // TODO disallow storage class other than auto and register + break :blk decl; + } else try parser.exprStmt(); + const cond = try parser.expr(); + const semicolon = try parser.expectToken(.Semicolon); + const incr = try parser.expr(); + const rparen = try parser.expectToken(.RParen); + const node = try parser.arena.create(Node.ForStmt); + node.* = .{ + .@"for" = tok, + .init = init, + .cond = cond, + .semicolon = semicolon, + .incr = incr, + .rparen = rparen, + .body = try parser.stmt(), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_switch)) |tok| { + try parser.pushScope(.Switch); + defer parser.popScope(); + _ = try parser.expectToken(.LParen); + const switch_expr = try parser.exprStmt(); + const rparen = try parser.expectToken(.RParen); + const node = try parser.arena.create(Node.SwitchStmt); + node.* = .{ + .@"switch" = tok, + .expr = switch_expr, + .rparen = rparen, + .body = try parser.stmt(), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_default)) |tok| { + _ = try parser.expectToken(.Colon); + const node = try parser.arena.create(Node.LabeledStmt); + node.* = .{ + .kind = .{ .Default = tok }, + .stmt = try parser.stmt(), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_case)) |tok| { + _ = try parser.expectToken(.Colon); + const node = try parser.arena.create(Node.LabeledStmt); + node.* = .{ + .kind = .{ .Case = tok }, + .stmt = try parser.stmt(), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_goto)) |tok| { + const node = try parser.arena.create(Node.JumpStmt); + node.* = .{ + .ltoken = tok, + .kind = .{ .Goto = tok }, + .semicolon = try parser.expectToken(.Semicolon), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_continue)) |tok| { + const node = try parser.arena.create(Node.JumpStmt); + node.* = .{ + .ltoken = tok, + .kind = .Continue, + .semicolon = try parser.expectToken(.Semicolon), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_break)) |tok| { + const node = try parser.arena.create(Node.JumpStmt); + node.* = .{ + .ltoken = tok, + .kind = .Break, + .semicolon = try parser.expectToken(.Semicolon), + }; + return &node.base; + } + if (parser.eatToken(.Keyword_return)) |tok| { + const node = try parser.arena.create(Node.JumpStmt); + node.* = .{ + .ltoken = tok, + .kind = .{ .Return = try parser.expr() }, + .semicolon = try parser.expectToken(.Semicolon), + }; + return &node.base; + } + if (parser.eatToken(.Identifier)) |tok| { + if (parser.eatToken(.Colon)) |_| { + const node = try parser.arena.create(Node.LabeledStmt); + node.* = .{ + .kind = .{ .Label = tok }, + .stmt = try parser.stmt(), + }; + return &node.base; + } + parser.putBackToken(tok); + } + return parser.exprStmt(); + } + + /// ExprStmt <- Expr? SEMICOLON + fn exprStmt(parser: *Parser) !*Node { + const node = try parser.arena.create(Node.ExprStmt); + node.* = .{ + .expr = try parser.expr(), + .semicolon = try parser.expectToken(.Semicolon), + }; + return &node.base; + } + + fn eatToken(parser: *Parser, id: @TagType(Token.Id)) ?TokenIndex { + while (true) { + switch ((parser.it.next() orelse return null).id) { + .LineComment, .MultiLineComment, .Nl => continue, + else => |next_id| if (next_id == id) { + return parser.it.index; + } else { + _ = parser.it.prev(); + return null; + }, + } + } + } + + fn expectToken(parser: *Parser, id: @TagType(Token.Id)) Error!TokenIndex { + while (true) { + switch ((parser.it.next() orelse return error.ParseError).id) { + .LineComment, .MultiLineComment, .Nl => continue, + else => |next_id| if (next_id != id) { + return parser.err(.{ + .ExpectedToken = .{ .token = parser.it.index, .expected_id = id }, + }); + } else { + return parser.it.index; + }, + } + } + } + + fn putBackToken(parser: *Parser, putting_back: TokenIndex) void { + while (true) { + const prev_tok = parser.it.next() orelse return; + switch (prev_tok.id) { + .LineComment, .MultiLineComment, .Nl => continue, + else => { + assert(parser.it.list.at(putting_back) == prev_tok); + return; + }, + } + } + } + + fn err(parser: *Parser, msg: ast.Error) Error { + try parser.tree.msgs.push(.{ + .kind = .Error, + .inner = msg, + }); + return error.ParseError; + } + + fn warn(parser: *Parser, msg: ast.Error) Error!void { + const is_warning = switch (parser.options.warn_as_err) { + .None => true, + .Some => |list| for (list) |item| (if (item == msg) break false) else true, + .All => false, + }; + try parser.tree.msgs.push(.{ + .kind = if (is_warning) .Warning else .Error, + .inner = msg, + }); + if (!is_warning) return error.ParseError; + } + + fn note(parser: *Parser, msg: ast.Error) Error!void { + try parser.tree.msgs.push(.{ + .kind = .Note, + .inner = msg, + }); + } +}; + diff --git a/lib/std/c/tokenizer.zig b/lib/std/c/tokenizer.zig new file mode 100644 index 0000000000..a641529502 --- /dev/null +++ b/lib/std/c/tokenizer.zig @@ -0,0 +1,1583 @@ +const std = @import("std"); +const mem = std.mem; + +pub const Source = struct { + buffer: []const u8, + file_name: []const u8, + tokens: TokenList, + + pub const TokenList = std.SegmentedList(Token, 64); +}; + +pub const Token = struct { + id: Id, + start: usize, + end: usize, + source: *Source, + + pub const Id = union(enum) { + Invalid, + Eof, + Nl, + Identifier, + + /// special case for #include <...> + MacroString, + StringLiteral: StrKind, + CharLiteral: StrKind, + IntegerLiteral: NumSuffix, + FloatLiteral: NumSuffix, + Bang, + BangEqual, + Pipe, + PipePipe, + PipeEqual, + Equal, + EqualEqual, + LParen, + RParen, + LBrace, + RBrace, + LBracket, + RBracket, + Period, + Ellipsis, + Caret, + CaretEqual, + Plus, + PlusPlus, + PlusEqual, + Minus, + MinusMinus, + MinusEqual, + Asterisk, + AsteriskEqual, + Percent, + PercentEqual, + Arrow, + Colon, + Semicolon, + Slash, + SlashEqual, + Comma, + Ampersand, + AmpersandAmpersand, + AmpersandEqual, + QuestionMark, + AngleBracketLeft, + AngleBracketLeftEqual, + AngleBracketAngleBracketLeft, + AngleBracketAngleBracketLeftEqual, + AngleBracketRight, + AngleBracketRightEqual, + AngleBracketAngleBracketRight, + AngleBracketAngleBracketRightEqual, + Tilde, + LineComment, + MultiLineComment, + Hash, + HashHash, + + Keyword_auto, + Keyword_break, + Keyword_case, + Keyword_char, + Keyword_const, + Keyword_continue, + Keyword_default, + Keyword_do, + Keyword_double, + Keyword_else, + Keyword_enum, + Keyword_extern, + Keyword_float, + Keyword_for, + Keyword_goto, + Keyword_if, + Keyword_int, + Keyword_long, + Keyword_register, + Keyword_return, + Keyword_short, + Keyword_signed, + Keyword_sizeof, + Keyword_static, + Keyword_struct, + Keyword_switch, + Keyword_typedef, + Keyword_union, + Keyword_unsigned, + Keyword_void, + Keyword_volatile, + Keyword_while, + + // ISO C99 + Keyword_bool, + Keyword_complex, + Keyword_imaginary, + Keyword_inline, + Keyword_restrict, + + // ISO C11 + Keyword_alignas, + Keyword_alignof, + Keyword_atomic, + Keyword_generic, + Keyword_noreturn, + Keyword_static_assert, + Keyword_thread_local, + + // Preprocessor directives + Keyword_include, + Keyword_define, + Keyword_ifdef, + Keyword_ifndef, + Keyword_error, + Keyword_pragma, + + pub fn symbol(id: @TagType(Id)) []const u8 { + return switch (id) { + .Invalid => "Invalid", + .Eof => "Eof", + .Nl => "NewLine", + .Identifier => "Identifier", + .MacroString => "MacroString", + .StringLiteral => "StringLiteral", + .CharLiteral => "CharLiteral", + .IntegerLiteral => "IntegerLiteral", + .FloatLiteral => "FloatLiteral", + .LineComment => "LineComment", + .MultiLineComment => "MultiLineComment", + + .Bang => "!", + .BangEqual => "!=", + .Pipe => "|", + .PipePipe => "||", + .PipeEqual => "|=", + .Equal => "=", + .EqualEqual => "==", + .LParen => "(", + .RParen => ")", + .LBrace => "{", + .RBrace => "}", + .LBracket => "[", + .RBracket => "]", + .Period => ".", + .Ellipsis => "...", + .Caret => "^", + .CaretEqual => "^=", + .Plus => "+", + .PlusPlus => "++", + .PlusEqual => "+=", + .Minus => "-", + .MinusMinus => "--", + .MinusEqual => "-=", + .Asterisk => "*", + .AsteriskEqual => "*=", + .Percent => "%", + .PercentEqual => "%=", + .Arrow => "->", + .Colon => ":", + .Semicolon => ";", + .Slash => "/", + .SlashEqual => "/=", + .Comma => ",", + .Ampersand => "&", + .AmpersandAmpersand => "&&", + .AmpersandEqual => "&=", + .QuestionMark => "?", + .AngleBracketLeft => "<", + .AngleBracketLeftEqual => "<=", + .AngleBracketAngleBracketLeft => "<<", + .AngleBracketAngleBracketLeftEqual => "<<=", + .AngleBracketRight => ">", + .AngleBracketRightEqual => ">=", + .AngleBracketAngleBracketRight => ">>", + .AngleBracketAngleBracketRightEqual => ">>=", + .Tilde => "~", + .Hash => "#", + .HashHash => "##", + .Keyword_auto => "auto", + .Keyword_break => "break", + .Keyword_case => "case", + .Keyword_char => "char", + .Keyword_const => "const", + .Keyword_continue => "continue", + .Keyword_default => "default", + .Keyword_do => "do", + .Keyword_double => "double", + .Keyword_else => "else", + .Keyword_enum => "enum", + .Keyword_extern => "extern", + .Keyword_float => "float", + .Keyword_for => "for", + .Keyword_goto => "goto", + .Keyword_if => "if", + .Keyword_int => "int", + .Keyword_long => "long", + .Keyword_register => "register", + .Keyword_return => "return", + .Keyword_short => "short", + .Keyword_signed => "signed", + .Keyword_sizeof => "sizeof", + .Keyword_static => "static", + .Keyword_struct => "struct", + .Keyword_switch => "switch", + .Keyword_typedef => "typedef", + .Keyword_union => "union", + .Keyword_unsigned => "unsigned", + .Keyword_void => "void", + .Keyword_volatile => "volatile", + .Keyword_while => "while", + .Keyword_bool => "_Bool", + .Keyword_complex => "_Complex", + .Keyword_imaginary => "_Imaginary", + .Keyword_inline => "inline", + .Keyword_restrict => "restrict", + .Keyword_alignas => "_Alignas", + .Keyword_alignof => "_Alignof", + .Keyword_atomic => "_Atomic", + .Keyword_generic => "_Generic", + .Keyword_noreturn => "_Noreturn", + .Keyword_static_assert => "_Static_assert", + .Keyword_thread_local => "_Thread_local", + .Keyword_include => "include", + .Keyword_define => "define", + .Keyword_ifdef => "ifdef", + .Keyword_ifndef => "ifndef", + .Keyword_error => "error", + .Keyword_pragma => "pragma", + }; + } + }; + + pub fn eql(a: Token, b: Token) bool { + // do we really need this cast here + if (@as(@TagType(Id), a.id) != b.id) return false; + return mem.eql(u8, a.slice(), b.slice()); + } + + pub fn slice(tok: Token) []const u8 { + return tok.source.buffer[tok.start..tok.end]; + } + + pub const Keyword = struct { + bytes: []const u8, + id: Id, + hash: u32, + + fn init(bytes: []const u8, id: Id) Keyword { + @setEvalBranchQuota(2000); + return .{ + .bytes = bytes, + .id = id, + .hash = std.hash_map.hashString(bytes), + }; + } + }; + + // TODO extensions + pub const keywords = [_]Keyword{ + Keyword.init("auto", .Keyword_auto), + Keyword.init("break", .Keyword_break), + Keyword.init("case", .Keyword_case), + Keyword.init("char", .Keyword_char), + Keyword.init("const", .Keyword_const), + Keyword.init("continue", .Keyword_continue), + Keyword.init("default", .Keyword_default), + Keyword.init("do", .Keyword_do), + Keyword.init("double", .Keyword_double), + Keyword.init("else", .Keyword_else), + Keyword.init("enum", .Keyword_enum), + Keyword.init("extern", .Keyword_extern), + Keyword.init("float", .Keyword_float), + Keyword.init("for", .Keyword_for), + Keyword.init("goto", .Keyword_goto), + Keyword.init("if", .Keyword_if), + Keyword.init("int", .Keyword_int), + Keyword.init("long", .Keyword_long), + Keyword.init("register", .Keyword_register), + Keyword.init("return", .Keyword_return), + Keyword.init("short", .Keyword_short), + Keyword.init("signed", .Keyword_signed), + Keyword.init("sizeof", .Keyword_sizeof), + Keyword.init("static", .Keyword_static), + Keyword.init("struct", .Keyword_struct), + Keyword.init("switch", .Keyword_switch), + Keyword.init("typedef", .Keyword_typedef), + Keyword.init("union", .Keyword_union), + Keyword.init("unsigned", .Keyword_unsigned), + Keyword.init("void", .Keyword_void), + Keyword.init("volatile", .Keyword_volatile), + Keyword.init("while", .Keyword_while), + + // ISO C99 + Keyword.init("_Bool", .Keyword_bool), + Keyword.init("_Complex", .Keyword_complex), + Keyword.init("_Imaginary", .Keyword_imaginary), + Keyword.init("inline", .Keyword_inline), + Keyword.init("restrict", .Keyword_restrict), + + // ISO C11 + Keyword.init("_Alignas", .Keyword_alignas), + Keyword.init("_Alignof", .Keyword_alignof), + Keyword.init("_Atomic", .Keyword_atomic), + Keyword.init("_Generic", .Keyword_generic), + Keyword.init("_Noreturn", .Keyword_noreturn), + Keyword.init("_Static_assert", .Keyword_static_assert), + Keyword.init("_Thread_local", .Keyword_thread_local), + + // Preprocessor directives + Keyword.init("include", .Keyword_include), + Keyword.init("define", .Keyword_define), + Keyword.init("ifdef", .Keyword_ifdef), + Keyword.init("ifndef", .Keyword_ifndef), + Keyword.init("error", .Keyword_error), + Keyword.init("pragma", .Keyword_pragma), + }; + + // TODO perfect hash at comptime + // TODO do this in the preprocessor + pub fn getKeyword(bytes: []const u8, pp_directive: bool) ?Id { + var hash = std.hash_map.hashString(bytes); + for (keywords) |kw| { + if (kw.hash == hash and mem.eql(u8, kw.bytes, bytes)) { + switch (kw.id) { + .Keyword_include, + .Keyword_define, + .Keyword_ifdef, + .Keyword_ifndef, + .Keyword_error, + .Keyword_pragma, + => if (!pp_directive) return null, + else => {}, + } + return kw.id; + } + } + return null; + } + + pub const NumSuffix = enum { + None, + F, + L, + U, + LU, + LL, + LLU, + }; + + pub const StrKind = enum { + None, + Wide, + Utf8, + Utf16, + Utf32, + }; +}; + +pub const Tokenizer = struct { + source: *Source, + index: usize = 0, + prev_tok_id: @TagType(Token.Id) = .Invalid, + pp_directive: bool = false, + + pub fn next(self: *Tokenizer) Token { + const start_index = self.index; + var result = Token{ + .id = .Eof, + .start = self.index, + .end = undefined, + .source = self.source, + }; + var state: enum { + Start, + Cr, + BackSlash, + BackSlashCr, + u, + u8, + U, + L, + StringLiteral, + CharLiteralStart, + CharLiteral, + EscapeSequence, + CrEscape, + OctalEscape, + HexEscape, + UnicodeEscape, + Identifier, + Equal, + Bang, + Pipe, + Percent, + Asterisk, + Plus, + + /// special case for #include <...> + MacroString, + AngleBracketLeft, + AngleBracketAngleBracketLeft, + AngleBracketRight, + AngleBracketAngleBracketRight, + Caret, + Period, + Period2, + Minus, + Slash, + Ampersand, + Hash, + LineComment, + MultiLineComment, + MultiLineCommentAsterisk, + Zero, + IntegerLiteralOct, + IntegerLiteralBinary, + IntegerLiteralHex, + IntegerLiteral, + IntegerSuffix, + IntegerSuffixU, + IntegerSuffixL, + IntegerSuffixLL, + IntegerSuffixUL, + FloatFraction, + FloatFractionHex, + FloatExponent, + FloatExponentDigits, + FloatSuffix, + } = .Start; + var string = false; + var counter: u32 = 0; + while (self.index < self.source.buffer.len) : (self.index += 1) { + const c = self.source.buffer[self.index]; + switch (state) { + .Start => switch (c) { + '\n' => { + self.pp_directive = false; + result.id = .Nl; + self.index += 1; + break; + }, + '\r' => { + state = .Cr; + }, + '"' => { + result.id = .{ .StringLiteral = .None }; + state = .StringLiteral; + }, + '\'' => { + result.id = .{ .CharLiteral = .None }; + state = .CharLiteralStart; + }, + 'u' => { + state = .u; + }, + 'U' => { + state = .U; + }, + 'L' => { + state = .L; + }, + 'a'...'t', 'v'...'z', 'A'...'K', 'M'...'T', 'V'...'Z', '_' => { + state = .Identifier; + }, + '=' => { + state = .Equal; + }, + '!' => { + state = .Bang; + }, + '|' => { + state = .Pipe; + }, + '(' => { + result.id = .LParen; + self.index += 1; + break; + }, + ')' => { + result.id = .RParen; + self.index += 1; + break; + }, + '[' => { + result.id = .LBracket; + self.index += 1; + break; + }, + ']' => { + result.id = .RBracket; + self.index += 1; + break; + }, + ';' => { + result.id = .Semicolon; + self.index += 1; + break; + }, + ',' => { + result.id = .Comma; + self.index += 1; + break; + }, + '?' => { + result.id = .QuestionMark; + self.index += 1; + break; + }, + ':' => { + result.id = .Colon; + self.index += 1; + break; + }, + '%' => { + state = .Percent; + }, + '*' => { + state = .Asterisk; + }, + '+' => { + state = .Plus; + }, + '<' => { + if (self.prev_tok_id == .Keyword_include) + state = .MacroString + else + state = .AngleBracketLeft; + }, + '>' => { + state = .AngleBracketRight; + }, + '^' => { + state = .Caret; + }, + '{' => { + result.id = .LBrace; + self.index += 1; + break; + }, + '}' => { + result.id = .RBrace; + self.index += 1; + break; + }, + '~' => { + result.id = .Tilde; + self.index += 1; + break; + }, + '.' => { + state = .Period; + }, + '-' => { + state = .Minus; + }, + '/' => { + state = .Slash; + }, + '&' => { + state = .Ampersand; + }, + '#' => { + state = .Hash; + }, + '0' => { + state = .Zero; + }, + '1'...'9' => { + state = .IntegerLiteral; + }, + '\\' => { + state = .BackSlash; + }, + '\t', '\x0B', '\x0C', ' ' => { + result.start = self.index + 1; + }, + else => { + // TODO handle invalid bytes better + result.id = .Invalid; + self.index += 1; + break; + }, + }, + .Cr => switch (c) { + '\n' => { + self.pp_directive = false; + result.id = .Nl; + self.index += 1; + break; + }, + else => { + result.id = .Invalid; + break; + }, + }, + .BackSlash => switch (c) { + '\n' => { + state = .Start; + }, + '\r' => { + state = .BackSlashCr; + }, + '\t', '\x0B', '\x0C', ' ' => { + // TODO warn + }, + else => { + result.id = .Invalid; + break; + }, + }, + .BackSlashCr => switch (c) { + '\n' => { + state = .Start; + }, + else => { + result.id = .Invalid; + break; + }, + }, + .u => switch (c) { + '8' => { + state = .u8; + }, + '\'' => { + result.id = .{ .CharLiteral = .Utf16 }; + state = .CharLiteralStart; + }, + '\"' => { + result.id = .{ .StringLiteral = .Utf16 }; + state = .StringLiteral; + }, + else => { + state = .Identifier; + }, + }, + .u8 => switch (c) { + '\"' => { + result.id = .{ .StringLiteral = .Utf8 }; + state = .StringLiteral; + }, + else => { + state = .Identifier; + }, + }, + .U => switch (c) { + '\'' => { + result.id = .{ .CharLiteral = .Utf32 }; + state = .CharLiteralStart; + }, + '\"' => { + result.id = .{ .StringLiteral = .Utf32 }; + state = .StringLiteral; + }, + else => { + state = .Identifier; + }, + }, + .L => switch (c) { + '\'' => { + result.id = .{ .CharLiteral = .Wide }; + state = .CharLiteralStart; + }, + '\"' => { + result.id = .{ .StringLiteral = .Wide }; + state = .StringLiteral; + }, + else => { + state = .Identifier; + }, + }, + .StringLiteral => switch (c) { + '\\' => { + string = true; + state = .EscapeSequence; + }, + '"' => { + self.index += 1; + break; + }, + '\n', '\r' => { + result.id = .Invalid; + break; + }, + else => {}, + }, + .CharLiteralStart => switch (c) { + '\\' => { + string = false; + state = .EscapeSequence; + }, + '\'', '\n' => { + result.id = .Invalid; + break; + }, + else => { + state = .CharLiteral; + }, + }, + .CharLiteral => switch (c) { + '\\' => { + string = false; + state = .EscapeSequence; + }, + '\'' => { + self.index += 1; + break; + }, + '\n' => { + result.id = .Invalid; + break; + }, + else => {}, + }, + .EscapeSequence => switch (c) { + '\'', '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v', '\n' => { + state = if (string) .StringLiteral else .CharLiteral; + }, + '\r' => { + state = .CrEscape; + }, + '0'...'7' => { + counter = 1; + state = .OctalEscape; + }, + 'x' => { + state = .HexEscape; + }, + 'u' => { + counter = 4; + state = .OctalEscape; + }, + 'U' => { + counter = 8; + state = .OctalEscape; + }, + else => { + result.id = .Invalid; + break; + }, + }, + .CrEscape => switch (c) { + '\n' => { + state = if (string) .StringLiteral else .CharLiteral; + }, + else => { + result.id = .Invalid; + break; + }, + }, + .OctalEscape => switch (c) { + '0'...'7' => { + counter += 1; + if (counter == 3) { + state = if (string) .StringLiteral else .CharLiteral; + } + }, + else => { + state = if (string) .StringLiteral else .CharLiteral; + }, + }, + .HexEscape => switch (c) { + '0'...'9', 'a'...'f', 'A'...'F' => {}, + else => { + state = if (string) .StringLiteral else .CharLiteral; + }, + }, + .UnicodeEscape => switch (c) { + '0'...'9', 'a'...'f', 'A'...'F' => { + counter -= 1; + if (counter == 0) { + state = if (string) .StringLiteral else .CharLiteral; + } + }, + else => { + if (counter != 0) { + result.id = .Invalid; + break; + } + state = if (string) .StringLiteral else .CharLiteral; + }, + }, + .Identifier => switch (c) { + 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, + else => { + result.id = Token.getKeyword(self.source.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier; + if (self.prev_tok_id == .Hash) + self.pp_directive = true; + break; + }, + }, + .Equal => switch (c) { + '=' => { + result.id = .EqualEqual; + self.index += 1; + break; + }, + else => { + result.id = .Equal; + break; + }, + }, + .Bang => switch (c) { + '=' => { + result.id = .BangEqual; + self.index += 1; + break; + }, + else => { + result.id = .Bang; + break; + }, + }, + .Pipe => switch (c) { + '=' => { + result.id = .PipeEqual; + self.index += 1; + break; + }, + '|' => { + result.id = .PipePipe; + self.index += 1; + break; + }, + else => { + result.id = .Pipe; + break; + }, + }, + .Percent => switch (c) { + '=' => { + result.id = .PercentEqual; + self.index += 1; + break; + }, + else => { + result.id = .Percent; + break; + }, + }, + .Asterisk => switch (c) { + '=' => { + result.id = .AsteriskEqual; + self.index += 1; + break; + }, + else => { + result.id = .Asterisk; + break; + }, + }, + .Plus => switch (c) { + '=' => { + result.id = .PlusEqual; + self.index += 1; + break; + }, + '+' => { + result.id = .PlusPlus; + self.index += 1; + break; + }, + else => { + result.id = .Plus; + break; + }, + }, + .MacroString => switch (c) { + '>' => { + result.id = .MacroString; + self.index += 1; + break; + }, + else => {}, + }, + .AngleBracketLeft => switch (c) { + '<' => { + state = .AngleBracketAngleBracketLeft; + }, + '=' => { + result.id = .AngleBracketLeftEqual; + self.index += 1; + break; + }, + else => { + result.id = .AngleBracketLeft; + break; + }, + }, + .AngleBracketAngleBracketLeft => switch (c) { + '=' => { + result.id = .AngleBracketAngleBracketLeftEqual; + self.index += 1; + break; + }, + else => { + result.id = .AngleBracketAngleBracketLeft; + break; + }, + }, + .AngleBracketRight => switch (c) { + '>' => { + state = .AngleBracketAngleBracketRight; + }, + '=' => { + result.id = .AngleBracketRightEqual; + self.index += 1; + break; + }, + else => { + result.id = .AngleBracketRight; + break; + }, + }, + .AngleBracketAngleBracketRight => switch (c) { + '=' => { + result.id = .AngleBracketAngleBracketRightEqual; + self.index += 1; + break; + }, + else => { + result.id = .AngleBracketAngleBracketRight; + break; + }, + }, + .Caret => switch (c) { + '=' => { + result.id = .CaretEqual; + self.index += 1; + break; + }, + else => { + result.id = .Caret; + break; + }, + }, + .Period => switch (c) { + '.' => { + state = .Period2; + }, + '0'...'9' => { + state = .FloatFraction; + }, + else => { + result.id = .Period; + break; + }, + }, + .Period2 => switch (c) { + '.' => { + result.id = .Ellipsis; + self.index += 1; + break; + }, + else => { + result.id = .Period; + self.index -= 1; + break; + }, + }, + .Minus => switch (c) { + '>' => { + result.id = .Arrow; + self.index += 1; + break; + }, + '=' => { + result.id = .MinusEqual; + self.index += 1; + break; + }, + '-' => { + result.id = .MinusMinus; + self.index += 1; + break; + }, + else => { + result.id = .Minus; + break; + }, + }, + .Slash => switch (c) { + '/' => { + state = .LineComment; + }, + '*' => { + state = .MultiLineComment; + }, + '=' => { + result.id = .SlashEqual; + self.index += 1; + break; + }, + else => { + result.id = .Slash; + break; + }, + }, + .Ampersand => switch (c) { + '&' => { + result.id = .AmpersandAmpersand; + self.index += 1; + break; + }, + '=' => { + result.id = .AmpersandEqual; + self.index += 1; + break; + }, + else => { + result.id = .Ampersand; + break; + }, + }, + .Hash => switch (c) { + '#' => { + result.id = .HashHash; + self.index += 1; + break; + }, + else => { + result.id = .Hash; + break; + }, + }, + .LineComment => switch (c) { + '\n' => { + result.id = .LineComment; + self.index += 1; + break; + }, + else => {}, + }, + .MultiLineComment => switch (c) { + '*' => { + state = .MultiLineCommentAsterisk; + }, + else => {}, + }, + .MultiLineCommentAsterisk => switch (c) { + '/' => { + result.id = .MultiLineComment; + self.index += 1; + break; + }, + else => { + state = .MultiLineComment; + }, + }, + .Zero => switch (c) { + '0'...'9' => { + state = .IntegerLiteralOct; + }, + 'b', 'B' => { + state = .IntegerLiteralBinary; + }, + 'x', 'X' => { + state = .IntegerLiteralHex; + }, + else => { + state = .IntegerSuffix; + self.index -= 1; + }, + }, + .IntegerLiteralOct => switch (c) { + '0'...'7' => {}, + else => { + state = .IntegerSuffix; + self.index -= 1; + }, + }, + .IntegerLiteralBinary => switch (c) { + '0', '1' => {}, + else => { + state = .IntegerSuffix; + self.index -= 1; + }, + }, + .IntegerLiteralHex => switch (c) { + '0'...'9', 'a'...'f', 'A'...'F' => {}, + '.' => { + state = .FloatFractionHex; + }, + 'p', 'P' => { + state = .FloatExponent; + }, + else => { + state = .IntegerSuffix; + self.index -= 1; + }, + }, + .IntegerLiteral => switch (c) { + '0'...'9' => {}, + '.' => { + state = .FloatFraction; + }, + 'e', 'E' => { + state = .FloatExponent; + }, + else => { + state = .IntegerSuffix; + self.index -= 1; + }, + }, + .IntegerSuffix => switch (c) { + 'u', 'U' => { + state = .IntegerSuffixU; + }, + 'l', 'L' => { + state = .IntegerSuffixL; + }, + else => { + result.id = .{ .IntegerLiteral = .None }; + break; + }, + }, + .IntegerSuffixU => switch (c) { + 'l', 'L' => { + state = .IntegerSuffixUL; + }, + else => { + result.id = .{ .IntegerLiteral = .U }; + break; + }, + }, + .IntegerSuffixL => switch (c) { + 'l', 'L' => { + state = .IntegerSuffixLL; + }, + 'u', 'U' => { + result.id = .{ .IntegerLiteral = .LU }; + self.index += 1; + break; + }, + else => { + result.id = .{ .IntegerLiteral = .L }; + break; + }, + }, + .IntegerSuffixLL => switch (c) { + 'u', 'U' => { + result.id = .{ .IntegerLiteral = .LLU }; + self.index += 1; + break; + }, + else => { + result.id = .{ .IntegerLiteral = .LL }; + break; + }, + }, + .IntegerSuffixUL => switch (c) { + 'l', 'L' => { + result.id = .{ .IntegerLiteral = .LLU }; + self.index += 1; + break; + }, + else => { + result.id = .{ .IntegerLiteral = .LU }; + break; + }, + }, + .FloatFraction => switch (c) { + '0'...'9' => {}, + 'e', 'E' => { + state = .FloatExponent; + }, + else => { + self.index -= 1; + state = .FloatSuffix; + }, + }, + .FloatFractionHex => switch (c) { + '0'...'9', 'a'...'f', 'A'...'F' => {}, + 'p', 'P' => { + state = .FloatExponent; + }, + else => { + result.id = .Invalid; + break; + }, + }, + .FloatExponent => switch (c) { + '+', '-' => { + state = .FloatExponentDigits; + }, + else => { + self.index -= 1; + state = .FloatExponentDigits; + }, + }, + .FloatExponentDigits => switch (c) { + '0'...'9' => { + counter += 1; + }, + else => { + if (counter == 0) { + result.id = .Invalid; + break; + } + state = .FloatSuffix; + }, + }, + .FloatSuffix => switch (c) { + 'l', 'L' => { + result.id = .{ .FloatLiteral = .L }; + self.index += 1; + break; + }, + 'f', 'F' => { + result.id = .{ .FloatLiteral = .F }; + self.index += 1; + break; + }, + else => { + result.id = .{ .FloatLiteral = .None }; + break; + }, + }, + } + } else if (self.index == self.source.buffer.len) { + switch (state) { + .Start => {}, + .u, .u8, .U, .L, .Identifier => { + result.id = Token.getKeyword(self.source.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier; + }, + + .Cr, + .BackSlash, + .BackSlashCr, + .Period2, + .StringLiteral, + .CharLiteralStart, + .CharLiteral, + .EscapeSequence, + .CrEscape, + .OctalEscape, + .HexEscape, + .UnicodeEscape, + .MultiLineComment, + .MultiLineCommentAsterisk, + .FloatFraction, + .FloatFractionHex, + .FloatExponent, + .FloatExponentDigits, + .MacroString, + => result.id = .Invalid, + + .IntegerLiteralOct, + .IntegerLiteralBinary, + .IntegerLiteralHex, + .IntegerLiteral, + .IntegerSuffix, + .Zero, + => result.id = .{ .IntegerLiteral = .None }, + .IntegerSuffixU => result.id = .{ .IntegerLiteral = .U }, + .IntegerSuffixL => result.id = .{ .IntegerLiteral = .L }, + .IntegerSuffixLL => result.id = .{ .IntegerLiteral = .LL }, + .IntegerSuffixUL => result.id = .{ .IntegerLiteral = .LU }, + + .FloatSuffix => result.id = .{ .FloatLiteral = .None }, + .Equal => result.id = .Equal, + .Bang => result.id = .Bang, + .Minus => result.id = .Minus, + .Slash => result.id = .Slash, + .Ampersand => result.id = .Ampersand, + .Hash => result.id = .Hash, + .Period => result.id = .Period, + .Pipe => result.id = .Pipe, + .AngleBracketAngleBracketRight => result.id = .AngleBracketAngleBracketRight, + .AngleBracketRight => result.id = .AngleBracketRight, + .AngleBracketAngleBracketLeft => result.id = .AngleBracketAngleBracketLeft, + .AngleBracketLeft => result.id = .AngleBracketLeft, + .Plus => result.id = .Plus, + .Percent => result.id = .Percent, + .Caret => result.id = .Caret, + .Asterisk => result.id = .Asterisk, + .LineComment => result.id = .LineComment, + } + } + + self.prev_tok_id = result.id; + result.end = self.index; + return result; + } +}; + +test "operators" { + expectTokens( + \\ ! != | || |= = == + \\ ( ) { } [ ] . .. ... + \\ ^ ^= + ++ += - -- -= + \\ * *= % %= -> : ; / /= + \\ , & && &= ? < <= << + \\ <<= > >= >> >>= ~ # ## + \\ + , &[_]Token.Id{ + .Bang, + .BangEqual, + .Pipe, + .PipePipe, + .PipeEqual, + .Equal, + .EqualEqual, + .Nl, + .LParen, + .RParen, + .LBrace, + .RBrace, + .LBracket, + .RBracket, + .Period, + .Period, + .Period, + .Ellipsis, + .Nl, + .Caret, + .CaretEqual, + .Plus, + .PlusPlus, + .PlusEqual, + .Minus, + .MinusMinus, + .MinusEqual, + .Nl, + .Asterisk, + .AsteriskEqual, + .Percent, + .PercentEqual, + .Arrow, + .Colon, + .Semicolon, + .Slash, + .SlashEqual, + .Nl, + .Comma, + .Ampersand, + .AmpersandAmpersand, + .AmpersandEqual, + .QuestionMark, + .AngleBracketLeft, + .AngleBracketLeftEqual, + .AngleBracketAngleBracketLeft, + .Nl, + .AngleBracketAngleBracketLeftEqual, + .AngleBracketRight, + .AngleBracketRightEqual, + .AngleBracketAngleBracketRight, + .AngleBracketAngleBracketRightEqual, + .Tilde, + .Hash, + .HashHash, + .Nl, + }); +} + +test "keywords" { + expectTokens( + \\auto break case char const continue default do + \\double else enum extern float for goto if int + \\long register return short signed sizeof static + \\struct switch typedef union unsigned void volatile + \\while _Bool _Complex _Imaginary inline restrict _Alignas + \\_Alignof _Atomic _Generic _Noreturn _Static_assert _Thread_local + \\ + , &[_]Token.Id{ + .Keyword_auto, + .Keyword_break, + .Keyword_case, + .Keyword_char, + .Keyword_const, + .Keyword_continue, + .Keyword_default, + .Keyword_do, + .Nl, + .Keyword_double, + .Keyword_else, + .Keyword_enum, + .Keyword_extern, + .Keyword_float, + .Keyword_for, + .Keyword_goto, + .Keyword_if, + .Keyword_int, + .Nl, + .Keyword_long, + .Keyword_register, + .Keyword_return, + .Keyword_short, + .Keyword_signed, + .Keyword_sizeof, + .Keyword_static, + .Nl, + .Keyword_struct, + .Keyword_switch, + .Keyword_typedef, + .Keyword_union, + .Keyword_unsigned, + .Keyword_void, + .Keyword_volatile, + .Nl, + .Keyword_while, + .Keyword_bool, + .Keyword_complex, + .Keyword_imaginary, + .Keyword_inline, + .Keyword_restrict, + .Keyword_alignas, + .Nl, + .Keyword_alignof, + .Keyword_atomic, + .Keyword_generic, + .Keyword_noreturn, + .Keyword_static_assert, + .Keyword_thread_local, + .Nl, + }); +} + +test "preprocessor keywords" { + expectTokens( + \\#include <test> + \\#define #include <1 + \\#ifdef + \\#ifndef + \\#error + \\#pragma + \\ + , &[_]Token.Id{ + .Hash, + .Keyword_include, + .MacroString, + .Nl, + .Hash, + .Keyword_define, + .Hash, + .Identifier, + .AngleBracketLeft, + .{ .IntegerLiteral = .None }, + .Nl, + .Hash, + .Keyword_ifdef, + .Nl, + .Hash, + .Keyword_ifndef, + .Nl, + .Hash, + .Keyword_error, + .Nl, + .Hash, + .Keyword_pragma, + .Nl, + }); +} + +test "line continuation" { + expectTokens( + \\#define foo \ + \\ bar + \\"foo\ + \\ bar" + \\#define "foo" + \\ "bar" + \\#define "foo" \ + \\ "bar" + , &[_]Token.Id{ + .Hash, + .Keyword_define, + .Identifier, + .Identifier, + .Nl, + .{ .StringLiteral = .None }, + .Nl, + .Hash, + .Keyword_define, + .{ .StringLiteral = .None }, + .Nl, + .{ .StringLiteral = .None }, + .Nl, + .Hash, + .Keyword_define, + .{ .StringLiteral = .None }, + .{ .StringLiteral = .None }, + }); +} + +test "string prefix" { + expectTokens( + \\"foo" + \\u"foo" + \\u8"foo" + \\U"foo" + \\L"foo" + \\'foo' + \\u'foo' + \\U'foo' + \\L'foo' + \\ + , &[_]Token.Id{ + .{ .StringLiteral = .None }, + .Nl, + .{ .StringLiteral = .Utf16 }, + .Nl, + .{ .StringLiteral = .Utf8 }, + .Nl, + .{ .StringLiteral = .Utf32 }, + .Nl, + .{ .StringLiteral = .Wide }, + .Nl, + .{ .CharLiteral = .None }, + .Nl, + .{ .CharLiteral = .Utf16 }, + .Nl, + .{ .CharLiteral = .Utf32 }, + .Nl, + .{ .CharLiteral = .Wide }, + .Nl, + }); +} + +test "num suffixes" { + expectTokens( + \\ 1.0f 1.0L 1.0 .0 1. + \\ 0l 0lu 0ll 0llu 0 + \\ 1u 1ul 1ull 1 + \\ + , &[_]Token.Id{ + .{ .FloatLiteral = .F }, + .{ .FloatLiteral = .L }, + .{ .FloatLiteral = .None }, + .{ .FloatLiteral = .None }, + .{ .FloatLiteral = .None }, + .Nl, + .{ .IntegerLiteral = .L }, + .{ .IntegerLiteral = .LU }, + .{ .IntegerLiteral = .LL }, + .{ .IntegerLiteral = .LLU }, + .{ .IntegerLiteral = .None }, + .Nl, + .{ .IntegerLiteral = .U }, + .{ .IntegerLiteral = .LU }, + .{ .IntegerLiteral = .LLU }, + .{ .IntegerLiteral = .None }, + .Nl, + }); +} + +fn expectTokens(source: []const u8, expected_tokens: []const Token.Id) void { + var tokenizer = Tokenizer{ + .source = &Source{ + .buffer = source, + .file_name = undefined, + .tokens = undefined, + }, + }; + for (expected_tokens) |expected_token_id| { + const token = tokenizer.next(); + if (!std.meta.eql(token.id, expected_token_id)) { + std.debug.panic("expected {}, found {}\n", .{ @tagName(expected_token_id), @tagName(token.id) }); + } + } + const last_token = tokenizer.next(); + std.testing.expect(last_token.id == .Eof); +} diff --git a/lib/std/debug.zig b/lib/std/debug.zig index dfdaca6d3f..d035707a54 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -81,10 +81,20 @@ pub fn getSelfDebugInfo() !*DebugInfo { } } -fn wantTtyColor() bool { +pub fn detectTTYConfig() TTY.Config { var bytes: [128]u8 = undefined; const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator; - return if (process.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty(); + if (process.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| { + return .escape_codes; + } else |_| { + if (stderr_file.supportsAnsiEscapeCodes()) { + return .escape_codes; + } else if (builtin.os == .windows and stderr_file.isTty()) { + return .windows_api; + } else { + return .no_color; + } + } } /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. @@ -99,7 +109,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return; return; }; - writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| { + writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(), start_addr) catch |err| { stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return; return; }; @@ -118,16 +128,16 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return; return; }; - const tty_color = wantTtyColor(); - printSourceAtAddress(debug_info, stderr, ip, tty_color) catch return; + const tty_config = detectTTYConfig(); + printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*; - printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_color) catch return; + printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_config) catch return; var it = StackIterator{ .first_addr = null, .fp = bp, }; while (it.next()) |return_address| { - printSourceAtAddress(debug_info, stderr, return_address - 1, tty_color) catch return; + printSourceAtAddress(debug_info, stderr, return_address - 1, tty_config) catch return; } } @@ -191,7 +201,7 @@ pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void { stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return; return; }; - writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, wantTtyColor()) catch |err| { + writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, detectTTYConfig()) catch |err| { stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return; return; }; @@ -264,7 +274,7 @@ pub fn writeStackTrace( out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, - tty_color: bool, + tty_config: TTY.Config, ) !void { if (builtin.strip_debug_info) return error.MissingDebugInfo; var frame_index: usize = 0; @@ -275,7 +285,7 @@ pub fn writeStackTrace( frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len; }) { const return_address = stack_trace.instruction_addresses[frame_index]; - try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_color); + try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config); } } @@ -319,20 +329,25 @@ pub const StackIterator = struct { } }; -pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { +pub fn writeCurrentStackTrace( + out_stream: var, + debug_info: *DebugInfo, + tty_config: TTY.Config, + start_addr: ?usize, +) !void { if (builtin.os == .windows) { - return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr); + return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr); } var it = StackIterator.init(start_addr); while (it.next()) |return_address| { - try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_color); + try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config); } } pub fn writeCurrentStackTraceWindows( out_stream: var, debug_info: *DebugInfo, - tty_color: bool, + tty_config: TTY.Config, start_addr: ?usize, ) !void { var addr_buf: [1024]usize = undefined; @@ -345,23 +360,28 @@ pub fn writeCurrentStackTraceWindows( return; } else 0; for (addrs[start_i..]) |addr| { - try printSourceAtAddress(debug_info, out_stream, addr, tty_color); + try printSourceAtAddress(debug_info, out_stream, addr - 1, tty_config); } } /// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented, /// make this `noasync fn` and remove the individual noasync calls. -pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { +pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void { if (builtin.os == .windows) { - return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_color); + return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_config); } if (comptime std.Target.current.isDarwin()) { - return noasync printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color); + return noasync printSourceAtAddressMacOs(debug_info, out_stream, address, tty_config); } - return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_color); + return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_config); } -fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void { +fn printSourceAtAddressWindows( + di: *DebugInfo, + out_stream: var, + relocated_address: usize, + tty_config: TTY.Config, +) !void { const allocator = getDebugInfoAllocator(); const base_address = process.getBaseAddress(); const relative_address = relocated_address - base_address; @@ -379,16 +399,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres } } else { // we have no information to add to the address - if (tty_color) { - try out_stream.print("???:?:?: ", .{}); - setTtyColor(TtyColor.Dim); - try out_stream.print("0x{x} in ??? (???)", .{relocated_address}); - setTtyColor(TtyColor.Reset); - try out_stream.print("\n\n\n", .{}); - } else { - try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", .{relocated_address}); - } - return; + return printLineInfo(out_stream, null, relocated_address, "???", "???", tty_config, printLineFromFileAnyOs); }; const mod = &di.modules[mod_index]; @@ -401,7 +412,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres if (prefix.RecordLen < 2) return error.InvalidDebugInfo; switch (prefix.RecordKind) { - pdb.SymbolKind.S_LPROC32 => { + .S_LPROC32, .S_GPROC32 => { const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]); const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset; const vaddr_end = vaddr_start + proc_sym.CodeSize; @@ -510,137 +521,86 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres } }; - if (tty_color) { - setTtyColor(TtyColor.White); - if (opt_line_info) |li| { - try out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column }); - } else { - try out_stream.print("???:?:?", .{}); - } - setTtyColor(TtyColor.Reset); - try out_stream.print(": ", .{}); - setTtyColor(TtyColor.Dim); - try out_stream.print("0x{x} in {} ({})", .{ relocated_address, symbol_name, obj_basename }); - setTtyColor(TtyColor.Reset); - - if (opt_line_info) |line_info| { - try out_stream.print("\n", .{}); - if (printLineFromFileAnyOs(out_stream, line_info)) { - if (line_info.column == 0) { - try out_stream.write("\n"); - } else { - { - var col_i: usize = 1; - while (col_i < line_info.column) : (col_i += 1) { - try out_stream.writeByte(' '); - } - } - setTtyColor(TtyColor.Green); - try out_stream.write("^"); - setTtyColor(TtyColor.Reset); - try out_stream.write("\n"); - } - } else |err| switch (err) { - error.EndOfFile => {}, - error.FileNotFound => { - setTtyColor(TtyColor.Dim); - try out_stream.write("file not found\n\n"); - setTtyColor(TtyColor.White); - }, - else => return err, - } - } else { - try out_stream.print("\n\n\n", .{}); - } - } else { - if (opt_line_info) |li| { - try out_stream.print("{}:{}:{}: 0x{x} in {} ({})\n\n\n", .{ - li.file_name, - li.line, - li.column, - relocated_address, - symbol_name, - obj_basename, - }); - } else { - try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", .{ - relocated_address, - symbol_name, - obj_basename, - }); - } - } + try printLineInfo( + out_stream, + opt_line_info, + relocated_address, + symbol_name, + obj_basename, + tty_config, + printLineFromFileAnyOs, + ); } -const TtyColor = enum { - Red, - Green, - Cyan, - White, - Dim, - Bold, - Reset, -}; +pub const TTY = struct { + pub const Color = enum { + Red, + Green, + Cyan, + White, + Dim, + Bold, + Reset, + }; -/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt -fn setTtyColor(tty_color: TtyColor) void { - if (stderr_file.supportsAnsiEscapeCodes()) { - switch (tty_color) { - TtyColor.Red => { - stderr_file.write(RED) catch return; - }, - TtyColor.Green => { - stderr_file.write(GREEN) catch return; - }, - TtyColor.Cyan => { - stderr_file.write(CYAN) catch return; - }, - TtyColor.White, TtyColor.Bold => { - stderr_file.write(WHITE) catch return; - }, - TtyColor.Dim => { - stderr_file.write(DIM) catch return; - }, - TtyColor.Reset => { - stderr_file.write(RESET) catch return; - }, - } - } else { - 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; - // TODO handle error - _ = windows.kernel32.GetConsoleScreenBufferInfo(stderr_file.handle, &info); - S.attrs = info.wAttributes; - } + pub const Config = enum { + no_color, + escape_codes, + // TODO give this a payload of file handle + windows_api, + + fn setColor(conf: Config, out_stream: var, color: Color) void { + switch (conf) { + .no_color => return, + .escape_codes => switch (color) { + .Red => out_stream.write(RED) catch return, + .Green => out_stream.write(GREEN) catch return, + .Cyan => out_stream.write(CYAN) catch return, + .White, .Bold => out_stream.write(WHITE) catch return, + .Dim => out_stream.write(DIM) catch return, + .Reset => out_stream.write(RESET) catch return, + }, + .windows_api => if (builtin.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; + // TODO handle error + _ = windows.kernel32.GetConsoleScreenBufferInfo(stderr_file.handle, &info); + S.attrs = info.wAttributes; + } - // TODO handle errors - switch (tty_color) { - TtyColor.Red => { - _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY) catch {}; - }, - TtyColor.Green => { - _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY) catch {}; - }, - TtyColor.Cyan => { - _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {}; - }, - TtyColor.White, TtyColor.Bold => { - _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {}; - }, - TtyColor.Dim => { - _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY) catch {}; - }, - TtyColor.Reset => { - _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs) catch {}; - }, + // TODO handle errors + switch (color) { + .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 {}; + }, + .Cyan => { + _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {}; + }, + .White, .Bold => { + _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {}; + }, + .Dim => { + _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY) catch {}; + }, + .Reset => { + _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs) catch {}; + }, + } + } else { + unreachable; + }, + } } - } -} + }; +}; fn populateModule(di: *DebugInfo, mod: *Module) !void { if (mod.populated) @@ -706,17 +666,12 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach return null; } -fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { +fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void { const base_addr = process.getBaseAddress(); const adjusted_addr = 0x100000000 + (address - base_addr); const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse { - if (tty_color) { - try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", .{address}); - } else { - try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", .{address}); - } - return; + return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs); }; const symbol_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + symbol.nlist.n_strx)); @@ -724,78 +679,70 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); break :blk fs.path.basename(ofile_path); } else "???"; - if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| { - defer line_info.deinit(); - try printLineInfo( - out_stream, - line_info, - address, - symbol_name, - compile_unit_name, - tty_color, - printLineFromFileAnyOs, - ); - } else |err| switch (err) { - error.MissingDebugInfo, error.InvalidDebugInfo => { - if (tty_color) { - try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n\n\n", .{ - address, symbol_name, compile_unit_name, - }); - } else { - try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", .{ address, symbol_name, compile_unit_name }); - } - }, + + const line_info = getLineNumberInfoMacOs(di, symbol.*, adjusted_addr) catch |err| switch (err) { + error.MissingDebugInfo, error.InvalidDebugInfo => null, else => return err, - } + }; + defer if (line_info) |li| li.deinit(); + + try printLineInfo( + out_stream, + line_info, + address, + symbol_name, + compile_unit_name, + tty_config, + printLineFromFileAnyOs, + ); } -pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { - return debug_info.printSourceAtAddress(out_stream, address, tty_color, printLineFromFileAnyOs); +pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void { + return debug_info.printSourceAtAddress(out_stream, address, tty_config, printLineFromFileAnyOs); } fn printLineInfo( out_stream: var, - line_info: LineInfo, + line_info: ?LineInfo, address: usize, symbol_name: []const u8, compile_unit_name: []const u8, - tty_color: bool, + tty_config: TTY.Config, comptime printLineFromFile: var, ) !void { - if (tty_color) { - try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n", .{ - line_info.file_name, - line_info.line, - line_info.column, - address, - symbol_name, - compile_unit_name, - }); - if (printLineFromFile(out_stream, line_info)) { - if (line_info.column == 0) { - try out_stream.write("\n"); - } else { - { - var col_i: usize = 1; - while (col_i < line_info.column) : (col_i += 1) { - try out_stream.writeByte(' '); - } - } - try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n"); + tty_config.setColor(out_stream, .White); + + if (line_info) |*li| { + try out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column }); + } else { + try out_stream.print("???:?:?", .{}); + } + + tty_config.setColor(out_stream, .Reset); + try out_stream.write(": "); + tty_config.setColor(out_stream, .Dim); + try out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name }); + tty_config.setColor(out_stream, .Reset); + try out_stream.write("\n"); + + // Show the matching source code line if possible + if (line_info) |li| { + if (noasync printLineFromFile(out_stream, li)) { + if (li.column > 0) { + // The caret already takes one char + const space_needed = @intCast(usize, li.column - 1); + + try out_stream.writeByteNTimes(' ', space_needed); + tty_config.setColor(out_stream, .Green); + try out_stream.write("^"); + tty_config.setColor(out_stream, .Reset); } + try out_stream.write("\n"); } else |err| switch (err) { error.EndOfFile, error.FileNotFound => {}, + error.BadPathName => {}, else => return err, } - } else { - try out_stream.print("{}:{}:{}: 0x{x} in {} ({})\n", .{ - line_info.file_name, - line_info.line, - line_info.column, - address, - symbol_name, - compile_unit_name, - }); } } @@ -1016,59 +963,61 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void { pub fn openElfDebugInfo( allocator: *mem.Allocator, - elf_seekable_stream: *DwarfSeekableStream, - elf_in_stream: *DwarfInStream, + data: []u8, ) !DwarfInfo { - var efile = try elf.Elf.openStream(allocator, elf_seekable_stream, elf_in_stream); - errdefer efile.close(); + var seekable_stream = io.SliceSeekableInStream.init(data); + var efile = try elf.Elf.openStream( + allocator, + @ptrCast(*DwarfSeekableStream, &seekable_stream.seekable_stream), + @ptrCast(*DwarfInStream, &seekable_stream.stream), + ); + defer efile.close(); + + const debug_info = (try efile.findSection(".debug_info")) orelse + return error.MissingDebugInfo; + const debug_abbrev = (try efile.findSection(".debug_abbrev")) orelse + return error.MissingDebugInfo; + const debug_str = (try efile.findSection(".debug_str")) orelse + return error.MissingDebugInfo; + const debug_line = (try efile.findSection(".debug_line")) orelse + return error.MissingDebugInfo; + const opt_debug_ranges = try efile.findSection(".debug_ranges"); var di = DwarfInfo{ - .dwarf_seekable_stream = elf_seekable_stream, - .dwarf_in_stream = elf_in_stream, .endian = efile.endian, - .debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo, - .debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo, - .debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo, - .debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo, - .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")), - .abbrev_table_list = undefined, - .compile_unit_list = undefined, - .func_list = undefined, + .debug_info = (data[@intCast(usize, debug_info.offset)..@intCast(usize, debug_info.offset + debug_info.size)]), + .debug_abbrev = (data[@intCast(usize, debug_abbrev.offset)..@intCast(usize, debug_abbrev.offset + debug_abbrev.size)]), + .debug_str = (data[@intCast(usize, debug_str.offset)..@intCast(usize, debug_str.offset + debug_str.size)]), + .debug_line = (data[@intCast(usize, debug_line.offset)..@intCast(usize, debug_line.offset + debug_line.size)]), + .debug_ranges = if (opt_debug_ranges) |debug_ranges| + data[@intCast(usize, debug_ranges.offset)..@intCast(usize, debug_ranges.offset + debug_ranges.size)] + else + null, }; + + efile.close(); + try openDwarfDebugInfo(&di, allocator); return di; } fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo { - const S = struct { - var self_exe_file: File = undefined; - var self_exe_mmap_seekable: io.SliceSeekableInStream = undefined; - }; - - S.self_exe_file = try fs.openSelfExe(); - errdefer S.self_exe_file.close(); + var exe_file = try fs.openSelfExe(); + errdefer exe_file.close(); - const self_exe_len = math.cast(usize, try S.self_exe_file.getEndPos()) catch return error.DebugInfoTooLarge; - const self_exe_mmap_len = mem.alignForward(self_exe_len, mem.page_size); - const self_exe_mmap = try os.mmap( + const exe_len = math.cast(usize, try exe_file.getEndPos()) catch + return error.DebugInfoTooLarge; + const exe_mmap = try os.mmap( null, - self_exe_mmap_len, + exe_len, os.PROT_READ, os.MAP_SHARED, - S.self_exe_file.handle, + exe_file.handle, 0, ); - errdefer os.munmap(self_exe_mmap); + errdefer os.munmap(exe_mmap); - S.self_exe_mmap_seekable = io.SliceSeekableInStream.init(self_exe_mmap); - - return openElfDebugInfo( - allocator, - // TODO https://github.com/ziglang/zig/issues/764 - @ptrCast(*DwarfSeekableStream, &S.self_exe_mmap_seekable.seekable_stream), - // TODO https://github.com/ziglang/zig/issues/764 - @ptrCast(*DwarfInStream, &S.self_exe_mmap_seekable.stream), - ); + return openElfDebugInfo(allocator, exe_mmap); } fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { @@ -1195,83 +1144,56 @@ const MachoSymbol = struct { } }; -const MachOFile = struct { - bytes: []align(@alignOf(macho.mach_header_64)) const u8, - sect_debug_info: ?*const macho.section_64, - sect_debug_line: ?*const macho.section_64, -}; - pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror); pub const DwarfInStream = io.InStream(anyerror); pub const DwarfInfo = struct { - dwarf_seekable_stream: *DwarfSeekableStream, - dwarf_in_stream: *DwarfInStream, endian: builtin.Endian, - debug_info: Section, - debug_abbrev: Section, - debug_str: Section, - debug_line: Section, - debug_ranges: ?Section, - abbrev_table_list: ArrayList(AbbrevTableHeader), - compile_unit_list: ArrayList(CompileUnit), - func_list: ArrayList(Func), - - pub const Section = struct { - offset: u64, - size: u64, - }; + // No memory is owned by the DwarfInfo + debug_info: []u8, + debug_abbrev: []u8, + debug_str: []u8, + debug_line: []u8, + debug_ranges: ?[]u8, + // Filled later by the initializer + abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined, + compile_unit_list: ArrayList(CompileUnit) = undefined, + func_list: ArrayList(Func) = undefined, pub fn allocator(self: DwarfInfo) *mem.Allocator { return self.abbrev_table_list.allocator; } - pub fn readString(self: *DwarfInfo) ![]u8 { - return readStringRaw(self.allocator(), self.dwarf_in_stream); - } - /// This function works in freestanding mode. /// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void pub fn printSourceAtAddress( self: *DwarfInfo, out_stream: var, address: usize, - tty_color: bool, + tty_config: TTY.Config, comptime printLineFromFile: var, ) !void { const compile_unit = self.findCompileUnit(address) catch { - if (tty_color) { - try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", .{address}); - } else { - try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", .{address}); - } - return; + return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFile); }; + const compile_unit_name = try compile_unit.die.getAttrString(self, DW.AT_name); - if (self.getLineNumberInfo(compile_unit.*, address)) |line_info| { - defer line_info.deinit(); - const symbol_name = self.getSymbolName(address) orelse "???"; - try printLineInfo( - out_stream, - line_info, - address, - symbol_name, - compile_unit_name, - tty_color, - printLineFromFile, - ); - } else |err| switch (err) { - error.MissingDebugInfo, error.InvalidDebugInfo => { - if (tty_color) { - try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n\n\n", .{ - address, compile_unit_name, - }); - } else { - try out_stream.print("???:?:?: 0x{x} in ??? ({})\n\n\n", .{ address, compile_unit_name }); - } - }, + const symbol_name = self.getSymbolName(address) orelse "???"; + const line_info = self.getLineNumberInfo(compile_unit.*, address) catch |err| switch (err) { + error.MissingDebugInfo, error.InvalidDebugInfo => null, else => return err, - } + }; + defer if (line_info) |li| li.deinit(); + + try printLineInfo( + out_stream, + line_info, + address, + symbol_name, + compile_unit_name, + tty_config, + printLineFromFile, + ); } fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 { @@ -1287,35 +1209,38 @@ pub const DwarfInfo = struct { } fn scanAllFunctions(di: *DwarfInfo) !void { - const debug_info_end = di.debug_info.offset + di.debug_info.size; - var this_unit_offset = di.debug_info.offset; + var s = io.SliceSeekableInStream.init(di.debug_info); + var this_unit_offset: u64 = 0; - while (this_unit_offset < debug_info_end) { - try di.dwarf_seekable_stream.seekTo(this_unit_offset); + while (true) { + s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) { + error.EndOfStream => return, + else => return err, + }; var is_64: bool = undefined; - const unit_length = try readInitialLength(@TypeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); + const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64); if (unit_length == 0) return; const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); - const version = try di.dwarf_in_stream.readInt(u16, di.endian); + const version = try s.stream.readInt(u16, di.endian); if (version < 2 or version > 5) return error.InvalidDebugInfo; - const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); + const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian); - const address_size = try di.dwarf_in_stream.readByte(); + const address_size = try s.stream.readByte(); if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; - const compile_unit_pos = try di.dwarf_seekable_stream.getPos(); + const compile_unit_pos = try s.seekable_stream.getPos(); const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset); - try di.dwarf_seekable_stream.seekTo(compile_unit_pos); + try s.seekable_stream.seekTo(compile_unit_pos); const next_unit_pos = this_unit_offset + next_offset; - while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) { - const die_obj = (try di.parseDie(abbrev_table, is_64)) orelse continue; - const after_die_offset = try di.dwarf_seekable_stream.getPos(); + while ((try s.seekable_stream.getPos()) < next_unit_pos) { + const die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse continue; + const after_die_offset = try s.seekable_stream.getPos(); switch (die_obj.tag_id) { DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => { @@ -1331,14 +1256,14 @@ pub const DwarfInfo = struct { // Follow the DIE it points to and repeat const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin); if (ref_offset > next_offset) return error.InvalidDebugInfo; - try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset); - this_die_obj = (try di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo; + try s.seekable_stream.seekTo(this_unit_offset + ref_offset); + this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| { // Follow the DIE it points to and repeat const ref_offset = try this_die_obj.getAttrRef(DW.AT_specification); if (ref_offset > next_offset) return error.InvalidDebugInfo; - try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset); - this_die_obj = (try di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo; + try s.seekable_stream.seekTo(this_unit_offset + ref_offset); + this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; } else { break :x null; } @@ -1376,12 +1301,10 @@ pub const DwarfInfo = struct { .pc_range = pc_range, }); }, - else => { - continue; - }, + else => {}, } - try di.dwarf_seekable_stream.seekTo(after_die_offset); + try s.seekable_stream.seekTo(after_die_offset); } this_unit_offset += next_offset; @@ -1389,32 +1312,35 @@ pub const DwarfInfo = struct { } fn scanAllCompileUnits(di: *DwarfInfo) !void { - const debug_info_end = di.debug_info.offset + di.debug_info.size; - var this_unit_offset = di.debug_info.offset; + var s = io.SliceSeekableInStream.init(di.debug_info); + var this_unit_offset: u64 = 0; - while (this_unit_offset < debug_info_end) { - try di.dwarf_seekable_stream.seekTo(this_unit_offset); + while (true) { + s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) { + error.EndOfStream => return, + else => return err, + }; var is_64: bool = undefined; - const unit_length = try readInitialLength(@TypeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); + const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64); if (unit_length == 0) return; const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); - const version = try di.dwarf_in_stream.readInt(u16, di.endian); + const version = try s.stream.readInt(u16, di.endian); if (version < 2 or version > 5) return error.InvalidDebugInfo; - const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); + const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian); - const address_size = try di.dwarf_in_stream.readByte(); + const address_size = try s.stream.readByte(); if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; - const compile_unit_pos = try di.dwarf_seekable_stream.getPos(); + const compile_unit_pos = try s.seekable_stream.getPos(); const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset); - try di.dwarf_seekable_stream.seekTo(compile_unit_pos); + try s.seekable_stream.seekTo(compile_unit_pos); const compile_unit_die = try di.allocator().create(Die); - compile_unit_die.* = (try di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo; + compile_unit_die.* = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo; @@ -1458,28 +1384,38 @@ pub const DwarfInfo = struct { if (compile_unit.pc_range) |range| { if (target_address >= range.start and target_address < range.end) return compile_unit; } - if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| { - var base_address: usize = 0; - if (di.debug_ranges) |debug_ranges| { - try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset); + if (di.debug_ranges) |debug_ranges| { + if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| { + var s = io.SliceSeekableInStream.init(debug_ranges); + + // All the addresses in the list are relative to the value + // specified by DW_AT_low_pc or to some other value encoded + // in the list itself + var base_address = try compile_unit.die.getAttrAddr(DW.AT_low_pc); + + try s.seekable_stream.seekTo(ranges_offset); + while (true) { - const begin_addr = try di.dwarf_in_stream.readIntLittle(usize); - const end_addr = try di.dwarf_in_stream.readIntLittle(usize); + const begin_addr = try s.stream.readIntLittle(usize); + const end_addr = try s.stream.readIntLittle(usize); if (begin_addr == 0 and end_addr == 0) { break; } + // This entry selects a new value for the base address if (begin_addr == maxInt(usize)) { - base_address = begin_addr; + base_address = end_addr; continue; } - if (target_address >= begin_addr and target_address < end_addr) { + if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) { return compile_unit; } } + + return error.InvalidDebugInfo; + } else |err| { + if (err != error.MissingDebugInfo) return err; + continue; } - } else |err| { - if (err != error.MissingDebugInfo) return err; - continue; } } return error.MissingDebugInfo; @@ -1493,30 +1429,33 @@ pub const DwarfInfo = struct { return &header.table; } } - try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset); try di.abbrev_table_list.append(AbbrevTableHeader{ .offset = abbrev_offset, - .table = try di.parseAbbrevTable(), + .table = try di.parseAbbrevTable(abbrev_offset), }); return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table; } - fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable { + fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable { + var s = io.SliceSeekableInStream.init(di.debug_abbrev); + + try s.seekable_stream.seekTo(offset); var result = AbbrevTable.init(di.allocator()); + errdefer result.deinit(); while (true) { - const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream); + const abbrev_code = try leb.readULEB128(u64, &s.stream); if (abbrev_code == 0) return result; try result.append(AbbrevTableEntry{ .abbrev_code = abbrev_code, - .tag_id = try leb.readULEB128(u64, di.dwarf_in_stream), - .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes, + .tag_id = try leb.readULEB128(u64, &s.stream), + .has_children = (try s.stream.readByte()) == DW.CHILDREN_yes, .attrs = ArrayList(AbbrevAttr).init(di.allocator()), }); const attrs = &result.items[result.len - 1].attrs; while (true) { - const attr_id = try leb.readULEB128(u64, di.dwarf_in_stream); - const form_id = try leb.readULEB128(u64, di.dwarf_in_stream); + const attr_id = try leb.readULEB128(u64, &s.stream); + const form_id = try leb.readULEB128(u64, &s.stream); if (attr_id == 0 and form_id == 0) break; try attrs.append(AbbrevAttr{ .attr_id = attr_id, @@ -1526,8 +1465,8 @@ pub const DwarfInfo = struct { } } - fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die { - const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream); + fn parseDie(di: *DwarfInfo, in_stream: var, abbrev_table: *const AbbrevTable, is_64: bool) !?Die { + const abbrev_code = try leb.readULEB128(u64, in_stream); if (abbrev_code == 0) return null; const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; @@ -1540,63 +1479,63 @@ pub const DwarfInfo = struct { for (table_entry.attrs.toSliceConst()) |attr, i| { result.attrs.items[i] = Die.Attr{ .id = attr.attr_id, - .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64), + .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, is_64), }; } return result; } fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo { + var s = io.SliceSeekableInStream.init(di.debug_line); + const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir); const line_info_offset = try compile_unit.die.getAttrSecOffset(DW.AT_stmt_list); - assert(line_info_offset < di.debug_line.size); - - try di.dwarf_seekable_stream.seekTo(di.debug_line.offset + line_info_offset); + try s.seekable_stream.seekTo(line_info_offset); var is_64: bool = undefined; - const unit_length = try readInitialLength(@TypeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); + const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64); if (unit_length == 0) { return error.MissingDebugInfo; } const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); - const version = try di.dwarf_in_stream.readInt(u16, di.endian); + const version = try s.stream.readInt(u16, di.endian); // TODO support 3 and 5 if (version != 2 and version != 4) return error.InvalidDebugInfo; - const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); - const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length; + const prologue_length = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian); + const prog_start_offset = (try s.seekable_stream.getPos()) + prologue_length; - const minimum_instruction_length = try di.dwarf_in_stream.readByte(); + const minimum_instruction_length = try s.stream.readByte(); if (minimum_instruction_length == 0) return error.InvalidDebugInfo; if (version >= 4) { // maximum_operations_per_instruction - _ = try di.dwarf_in_stream.readByte(); + _ = try s.stream.readByte(); } - const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0; - const line_base = try di.dwarf_in_stream.readByteSigned(); + const default_is_stmt = (try s.stream.readByte()) != 0; + const line_base = try s.stream.readByteSigned(); - const line_range = try di.dwarf_in_stream.readByte(); + const line_range = try s.stream.readByte(); if (line_range == 0) return error.InvalidDebugInfo; - const opcode_base = try di.dwarf_in_stream.readByte(); + const opcode_base = try s.stream.readByte(); const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1); { var i: usize = 0; while (i < opcode_base - 1) : (i += 1) { - standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte(); + standard_opcode_lengths[i] = try s.stream.readByte(); } } var include_directories = ArrayList([]u8).init(di.allocator()); try include_directories.append(compile_unit_cwd); while (true) { - const dir = try di.readString(); + const dir = try readStringRaw(di.allocator(), &s.stream); if (dir.len == 0) break; try include_directories.append(dir); } @@ -1605,11 +1544,11 @@ pub const DwarfInfo = struct { var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address); while (true) { - const file_name = try di.readString(); + const file_name = try readStringRaw(di.allocator(), &s.stream); if (file_name.len == 0) break; - const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream); - const mtime = try leb.readULEB128(usize, di.dwarf_in_stream); - const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream); + const dir_index = try leb.readULEB128(usize, &s.stream); + const mtime = try leb.readULEB128(usize, &s.stream); + const len_bytes = try leb.readULEB128(usize, &s.stream); try file_entries.append(FileEntry{ .file_name = file_name, .dir_index = dir_index, @@ -1618,30 +1557,32 @@ pub const DwarfInfo = struct { }); } - try di.dwarf_seekable_stream.seekTo(prog_start_offset); + try s.seekable_stream.seekTo(prog_start_offset); - while (true) { - const opcode = try di.dwarf_in_stream.readByte(); + const next_unit_pos = line_info_offset + next_offset; + + while ((try s.seekable_stream.getPos()) < next_unit_pos) { + const opcode = try s.stream.readByte(); if (opcode == DW.LNS_extended_op) { - const op_size = try leb.readULEB128(u64, di.dwarf_in_stream); + const op_size = try leb.readULEB128(u64, &s.stream); if (op_size < 1) return error.InvalidDebugInfo; - var sub_op = try di.dwarf_in_stream.readByte(); + var sub_op = try s.stream.readByte(); switch (sub_op) { DW.LNE_end_sequence => { prog.end_sequence = true; if (try prog.checkLineMatch()) |info| return info; - return error.MissingDebugInfo; + prog.reset(); }, DW.LNE_set_address => { - const addr = try di.dwarf_in_stream.readInt(usize, di.endian); + const addr = try s.stream.readInt(usize, di.endian); prog.address = addr; }, DW.LNE_define_file => { - const file_name = try di.readString(); - const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream); - const mtime = try leb.readULEB128(usize, di.dwarf_in_stream); - const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream); + const file_name = try readStringRaw(di.allocator(), &s.stream); + const dir_index = try leb.readULEB128(usize, &s.stream); + const mtime = try leb.readULEB128(usize, &s.stream); + const len_bytes = try leb.readULEB128(usize, &s.stream); try file_entries.append(FileEntry{ .file_name = file_name, .dir_index = dir_index, @@ -1651,7 +1592,7 @@ pub const DwarfInfo = struct { }, else => { const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo; - try di.dwarf_seekable_stream.seekBy(fwd_amt); + try s.seekable_stream.seekBy(fwd_amt); }, } } else if (opcode >= opcode_base) { @@ -1670,19 +1611,19 @@ pub const DwarfInfo = struct { prog.basic_block = false; }, DW.LNS_advance_pc => { - const arg = try leb.readULEB128(usize, di.dwarf_in_stream); + const arg = try leb.readULEB128(usize, &s.stream); prog.address += arg * minimum_instruction_length; }, DW.LNS_advance_line => { - const arg = try leb.readILEB128(i64, di.dwarf_in_stream); + const arg = try leb.readILEB128(i64, &s.stream); prog.line += arg; }, DW.LNS_set_file => { - const arg = try leb.readULEB128(usize, di.dwarf_in_stream); + const arg = try leb.readULEB128(usize, &s.stream); prog.file = arg; }, DW.LNS_set_column => { - const arg = try leb.readULEB128(u64, di.dwarf_in_stream); + const arg = try leb.readULEB128(u64, &s.stream); prog.column = arg; }, DW.LNS_negate_stmt => { @@ -1696,14 +1637,14 @@ pub const DwarfInfo = struct { prog.address += inc_addr; }, DW.LNS_fixed_advance_pc => { - const arg = try di.dwarf_in_stream.readInt(u16, di.endian); + const arg = try s.stream.readInt(u16, di.endian); prog.address += arg; }, DW.LNS_set_prologue_end => {}, else => { if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo; const len_bytes = standard_opcode_lengths[opcode - 1]; - try di.dwarf_seekable_stream.seekBy(len_bytes); + try s.seekable_stream.seekBy(len_bytes); }, } } @@ -1713,9 +1654,17 @@ pub const DwarfInfo = struct { } fn getString(di: *DwarfInfo, offset: u64) ![]u8 { - const pos = di.debug_str.offset + offset; - try di.dwarf_seekable_stream.seekTo(pos); - return di.readString(); + if (offset > di.debug_str.len) + return error.InvalidDebugInfo; + const casted_offset = math.cast(usize, offset) catch + return error.InvalidDebugInfo; + + // Valid strings always have a terminating zero byte + if (mem.indexOfScalarPos(u8, di.debug_str, casted_offset, 0)) |last| { + return di.debug_str[casted_offset..last]; + } + + return error.InvalidDebugInfo; } }; @@ -1727,7 +1676,7 @@ pub const DebugInfo = switch (builtin.os) { const OFileTable = std.HashMap( *macho.nlist_64, - MachOFile, + DwarfInfo, std.hash_map.getHashPtrAddrFn(*macho.nlist_64), std.hash_map.getTrivialEqlFn(*macho.nlist_64), ); @@ -1888,6 +1837,7 @@ const LineNumberProgram = struct { basic_block: bool, end_sequence: bool, + default_is_stmt: bool, target_address: usize, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), @@ -1900,6 +1850,25 @@ const LineNumberProgram = struct { prev_basic_block: bool, prev_end_sequence: bool, + // Reset the state machine following the DWARF specification + pub fn reset(self: *LineNumberProgram) void { + self.address = 0; + self.file = 1; + self.line = 1; + self.column = 0; + self.is_stmt = self.default_is_stmt; + self.basic_block = false; + self.end_sequence = false; + // Invalidate all the remaining fields + self.prev_address = 0; + self.prev_file = undefined; + self.prev_line = undefined; + self.prev_column = undefined; + self.prev_is_stmt = undefined; + self.prev_basic_block = undefined; + self.prev_end_sequence = undefined; + } + pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram { return LineNumberProgram{ .address = 0, @@ -1911,6 +1880,7 @@ const LineNumberProgram = struct { .end_sequence = false, .include_dirs = include_dirs, .file_entries = file_entries, + .default_is_stmt = is_stmt, .target_address = target_address, .prev_address = 0, .prev_file = undefined, @@ -2100,24 +2070,32 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con return null; } -fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo { +fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !LineInfo { const ofile = symbol.ofile orelse return error.MissingDebugInfo; const gop = try di.ofiles.getOrPut(ofile); - const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: { + const dwarf_info = if (gop.found_existing) &gop.kv.value else blk: { errdefer _ = di.ofiles.remove(ofile); const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); - gop.kv.value = MachOFile{ - .bytes = try std.fs.cwd().readFileAllocAligned( - di.ofiles.allocator, - ofile_path, - maxInt(usize), - @alignOf(macho.mach_header_64), - ), - .sect_debug_info = null, - .sect_debug_line = null, - }; - const hdr = @ptrCast(*const macho.mach_header_64, gop.kv.value.bytes.ptr); + var exe_file = try std.fs.openFileAbsoluteC(ofile_path, .{}); + errdefer exe_file.close(); + + const exe_len = math.cast(usize, try exe_file.getEndPos()) catch + return error.DebugInfoTooLarge; + const exe_mmap = try os.mmap( + null, + exe_len, + os.PROT_READ, + os.MAP_SHARED, + exe_file.handle, + 0, + ); + errdefer os.munmap(exe_mmap); + + const hdr = @ptrCast( + *const macho.mach_header_64, + @alignCast(@alignOf(macho.mach_header_64), exe_mmap.ptr), + ); if (hdr.magic != std.macho.MH_MAGIC_64) return error.InvalidDebugInfo; const hdr_base = @ptrCast([*]const u8, hdr); @@ -2126,181 +2104,75 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u const segcmd = while (ncmd != 0) : (ncmd -= 1) { const lc = @ptrCast(*const std.macho.load_command, ptr); switch (lc.cmd) { - std.macho.LC_SEGMENT_64 => break @ptrCast(*const std.macho.segment_command_64, @alignCast(@alignOf(std.macho.segment_command_64), ptr)), + std.macho.LC_SEGMENT_64 => { + break @ptrCast( + *const std.macho.segment_command_64, + @alignCast(@alignOf(std.macho.segment_command_64), ptr), + ); + }, else => {}, } ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize); } else { return error.MissingDebugInfo; }; + + var opt_debug_line: ?*const macho.section_64 = null; + var opt_debug_info: ?*const macho.section_64 = null; + var opt_debug_abbrev: ?*const macho.section_64 = null; + var opt_debug_str: ?*const macho.section_64 = null; + var opt_debug_ranges: ?*const macho.section_64 = null; + const sections = @ptrCast([*]const macho.section_64, @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)))[0..segcmd.nsects]; for (sections) |*sect| { - if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and - (sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG) - { - const sect_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, §.sectname)); - if (mem.eql(u8, sect_name, "__debug_line")) { - gop.kv.value.sect_debug_line = sect; - } else if (mem.eql(u8, sect_name, "__debug_info")) { - gop.kv.value.sect_debug_info = sect; - } + // The section name may not exceed 16 chars and a trailing null may + // not be present + const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last| + sect.sectname[0..last] + else + sect.sectname[0..]; + + if (mem.eql(u8, name, "__debug_line")) { + opt_debug_line = sect; + } else if (mem.eql(u8, name, "__debug_info")) { + opt_debug_info = sect; + } else if (mem.eql(u8, name, "__debug_abbrev")) { + opt_debug_abbrev = sect; + } else if (mem.eql(u8, name, "__debug_str")) { + opt_debug_str = sect; + } else if (mem.eql(u8, name, "__debug_ranges")) { + opt_debug_ranges = sect; } } - break :blk &gop.kv.value; - }; - - const sect_debug_line = mach_o_file.sect_debug_line orelse return error.MissingDebugInfo; - var ptr = mach_o_file.bytes.ptr + sect_debug_line.offset; - - var is_64: bool = undefined; - const unit_length = try readInitialLengthMem(&ptr, &is_64); - if (unit_length == 0) return error.MissingDebugInfo; - - const version = readIntMem(&ptr, u16, builtin.Endian.Little); - // TODO support 3 and 5 - if (version != 2 and version != 4) return error.InvalidDebugInfo; - - const prologue_length = if (is_64) - readIntMem(&ptr, u64, builtin.Endian.Little) - else - readIntMem(&ptr, u32, builtin.Endian.Little); - const prog_start = ptr + prologue_length; - - const minimum_instruction_length = readByteMem(&ptr); - if (minimum_instruction_length == 0) return error.InvalidDebugInfo; - - if (version >= 4) { - // maximum_operations_per_instruction - ptr += 1; - } - - const default_is_stmt = readByteMem(&ptr) != 0; - const line_base = readByteSignedMem(&ptr); - - const line_range = readByteMem(&ptr); - if (line_range == 0) return error.InvalidDebugInfo; - - const opcode_base = readByteMem(&ptr); - - const standard_opcode_lengths = ptr[0 .. opcode_base - 1]; - ptr += opcode_base - 1; - - var include_directories = ArrayList([]const u8).init(di.allocator()); - try include_directories.append(""); - while (true) { - const dir = readStringMem(&ptr); - if (dir.len == 0) break; - try include_directories.append(dir); - } - - var file_entries = ArrayList(FileEntry).init(di.allocator()); - var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address); + var debug_line = opt_debug_line orelse + return error.MissingDebugInfo; + var debug_info = opt_debug_info orelse + return error.MissingDebugInfo; + var debug_str = opt_debug_str orelse + return error.MissingDebugInfo; + var debug_abbrev = opt_debug_abbrev orelse + return error.MissingDebugInfo; - while (true) { - const file_name = readStringMem(&ptr); - if (file_name.len == 0) break; - const dir_index = try leb.readULEB128Mem(usize, &ptr); - const mtime = try leb.readULEB128Mem(usize, &ptr); - const len_bytes = try leb.readULEB128Mem(usize, &ptr); - try file_entries.append(FileEntry{ - .file_name = file_name, - .dir_index = dir_index, - .mtime = mtime, - .len_bytes = len_bytes, - }); - } + gop.kv.value = DwarfInfo{ + .endian = .Little, + .debug_info = exe_mmap[@intCast(usize, debug_info.offset)..@intCast(usize, debug_info.offset + debug_info.size)], + .debug_abbrev = exe_mmap[@intCast(usize, debug_abbrev.offset)..@intCast(usize, debug_abbrev.offset + debug_abbrev.size)], + .debug_str = exe_mmap[@intCast(usize, debug_str.offset)..@intCast(usize, debug_str.offset + debug_str.size)], + .debug_line = exe_mmap[@intCast(usize, debug_line.offset)..@intCast(usize, debug_line.offset + debug_line.size)], + .debug_ranges = if (opt_debug_ranges) |debug_ranges| + exe_mmap[@intCast(usize, debug_ranges.offset)..@intCast(usize, debug_ranges.offset + debug_ranges.size)] + else + null, + }; + try openDwarfDebugInfo(&gop.kv.value, di.allocator()); - ptr = prog_start; - while (true) { - const opcode = readByteMem(&ptr); - - if (opcode == DW.LNS_extended_op) { - const op_size = try leb.readULEB128Mem(u64, &ptr); - if (op_size < 1) return error.InvalidDebugInfo; - var sub_op = readByteMem(&ptr); - switch (sub_op) { - DW.LNE_end_sequence => { - prog.end_sequence = true; - if (try prog.checkLineMatch()) |info| return info; - return error.MissingDebugInfo; - }, - DW.LNE_set_address => { - const addr = readIntMem(&ptr, usize, builtin.Endian.Little); - prog.address = symbol.reloc + addr; - }, - DW.LNE_define_file => { - const file_name = readStringMem(&ptr); - const dir_index = try leb.readULEB128Mem(usize, &ptr); - const mtime = try leb.readULEB128Mem(usize, &ptr); - const len_bytes = try leb.readULEB128Mem(usize, &ptr); - try file_entries.append(FileEntry{ - .file_name = file_name, - .dir_index = dir_index, - .mtime = mtime, - .len_bytes = len_bytes, - }); - }, - else => { - ptr += op_size - 1; - }, - } - } else if (opcode >= opcode_base) { - // special opcodes - const adjusted_opcode = opcode - opcode_base; - const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range); - const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range); - prog.line += inc_line; - prog.address += inc_addr; - if (try prog.checkLineMatch()) |info| return info; - prog.basic_block = false; - } else { - switch (opcode) { - DW.LNS_copy => { - if (try prog.checkLineMatch()) |info| return info; - prog.basic_block = false; - }, - DW.LNS_advance_pc => { - const arg = try leb.readULEB128Mem(usize, &ptr); - prog.address += arg * minimum_instruction_length; - }, - DW.LNS_advance_line => { - const arg = try leb.readILEB128Mem(i64, &ptr); - prog.line += arg; - }, - DW.LNS_set_file => { - const arg = try leb.readULEB128Mem(usize, &ptr); - prog.file = arg; - }, - DW.LNS_set_column => { - const arg = try leb.readULEB128Mem(u64, &ptr); - prog.column = arg; - }, - DW.LNS_negate_stmt => { - prog.is_stmt = !prog.is_stmt; - }, - DW.LNS_set_basic_block => { - prog.basic_block = true; - }, - DW.LNS_const_add_pc => { - const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range); - prog.address += inc_addr; - }, - DW.LNS_fixed_advance_pc => { - const arg = readIntMem(&ptr, u16, builtin.Endian.Little); - prog.address += arg; - }, - DW.LNS_set_prologue_end => {}, - else => { - if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo; - const len_bytes = standard_opcode_lengths[opcode - 1]; - ptr += len_bytes; - }, - } - } - } + break :blk &gop.kv.value; + }; - return error.MissingDebugInfo; + const o_file_address = address - symbol.reloc; + const compile_unit = try dwarf_info.findCompileUnit(o_file_address); + return dwarf_info.getLineNumberInfo(compile_unit.*, o_file_address); } const Func = struct { @@ -2308,47 +2180,6 @@ const Func = struct { name: ?[]u8, }; -fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T { - // TODO https://github.com/ziglang/zig/issues/863 - const size = (T.bit_count + 7) / 8; - const result = mem.readIntSlice(T, ptr.*[0..size], endian); - ptr.* += size; - return result; -} - -fn readByteMem(ptr: *[*]const u8) u8 { - const result = ptr.*[0]; - ptr.* += 1; - return result; -} - -fn readByteSignedMem(ptr: *[*]const u8) i8 { - return @bitCast(i8, readByteMem(ptr)); -} - -fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 { - // TODO this code can be improved with https://github.com/ziglang/zig/issues/863 - const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]); - is_64.* = (first_32_bits == 0xffffffff); - if (is_64.*) { - ptr.* += 4; - const result = mem.readIntSliceLittle(u64, ptr.*[0..8]); - ptr.* += 8; - return result; - } else { - if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; - ptr.* += 4; - // TODO this cast should not be needed - return @as(u64, first_32_bits); - } -} - -fn readStringMem(ptr: *[*]const u8) [:0]const u8 { - const result = mem.toSliceConst(u8, @ptrCast([*:0]const u8, ptr.*)); - ptr.* += result.len + 1; - return result; -} - fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 { const first_32_bits = try in_stream.readIntLittle(u32); is_64.* = (first_32_bits == 0xffffffff); diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 5a650c3b10..cf3322a995 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1135,6 +1135,11 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) { size.* += bytes.len; } +pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 { + const result = try allocPrint(allocator, fmt ++ "\x00", args); + return result[0 .. result.len - 1 :0]; +} + test "bufPrintInt" { var buffer: [100]u8 = undefined; const buf = buffer[0..]; diff --git a/lib/std/fmt/parse_float.zig b/lib/std/fmt/parse_float.zig index 2c480852ac..1456dd8e57 100644 --- a/lib/std/fmt/parse_float.zig +++ b/lib/std/fmt/parse_float.zig @@ -382,6 +382,10 @@ pub fn parseFloat(comptime T: type, s: []const u8) !T { } test "fmt.parseFloat" { + if (std.Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } const testing = std.testing; const expect = testing.expect; const expectEqual = testing.expectEqual; diff --git a/lib/std/hash/murmur.zig b/lib/std/hash/murmur.zig index f6c0ccafb3..23b11ef284 100644 --- a/lib/std/hash/murmur.zig +++ b/lib/std/hash/murmur.zig @@ -15,7 +15,7 @@ pub const Murmur2_32 = struct { const m: u32 = 0x5bd1e995; const len = @truncate(u32, str.len); var h1: u32 = seed ^ len; - for (@ptrCast([*]allowzero align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { + for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { var k1: u32 = v; if (builtin.endian == builtin.Endian.Big) k1 = @byteSwap(u32, k1); @@ -100,7 +100,7 @@ pub const Murmur2_64 = struct { const m: u64 = 0xc6a4a7935bd1e995; const len = @as(u64, str.len); var h1: u64 = seed ^ (len *% m); - for (@ptrCast([*]allowzero align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| { + for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| { var k1: u64 = v; if (builtin.endian == builtin.Endian.Big) k1 = @byteSwap(u64, k1); @@ -180,7 +180,7 @@ pub const Murmur3_32 = struct { const c2: u32 = 0x1b873593; const len = @truncate(u32, str.len); var h1: u32 = seed; - for (@ptrCast([*]allowzero align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { + for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { var k1: u32 = v; if (builtin.endian == builtin.Endian.Big) k1 = @byteSwap(u32, k1); diff --git a/lib/std/http/headers.zig b/lib/std/http/headers.zig index b1d047aeec..dfe53fe750 100644 --- a/lib/std/http/headers.zig +++ b/lib/std/http/headers.zig @@ -172,7 +172,7 @@ pub const Headers = struct { var dex = HeaderIndexList.init(self.allocator); try dex.append(n - 1); errdefer dex.deinit(); - _ = try self.index.put(name, dex); + _ = try self.index.put(name_dup, dex); } self.data.appendAssumeCapacity(entry); } diff --git a/lib/std/io/out_stream.zig b/lib/std/io/out_stream.zig index b8f5db6fff..265be066a1 100644 --- a/lib/std/io/out_stream.zig +++ b/lib/std/io/out_stream.zig @@ -45,10 +45,14 @@ pub fn OutStream(comptime WriteError: type) type { } pub fn writeByteNTimes(self: *Self, byte: u8, n: usize) Error!void { - const slice = @as(*const [1]u8, &byte)[0..]; - var i: usize = 0; - while (i < n) : (i += 1) { - try self.writeFn(self, slice); + var bytes: [256]u8 = undefined; + mem.set(u8, bytes[0..], byte); + + var remaining: usize = n; + while (remaining > 0) { + const to_write = std.math.min(remaining, bytes.len); + try self.writeFn(self, bytes[0..to_write]); + remaining -= to_write; } } diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig index 92259fd6e9..21ebd723c4 100644 --- a/lib/std/io/test.zig +++ b/lib/std/io/test.zig @@ -547,6 +547,10 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: } test "Serializer/Deserializer generic" { + if (std.Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } try testSerializerDeserializer(builtin.Endian.Big, .Byte); try testSerializerDeserializer(builtin.Endian.Little, .Byte); try testSerializerDeserializer(builtin.Endian.Big, .Bit); diff --git a/lib/std/math/fabs.zig b/lib/std/math/fabs.zig index a659e35ca2..61692283e6 100644 --- a/lib/std/math/fabs.zig +++ b/lib/std/math/fabs.zig @@ -95,6 +95,10 @@ test "math.fabs64.special" { } test "math.fabs128.special" { + if (std.Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } expect(math.isPositiveInf(fabs(math.inf(f128)))); expect(math.isPositiveInf(fabs(-math.inf(f128)))); expect(math.isNan(fabs(math.nan(f128)))); diff --git a/lib/std/math/isinf.zig b/lib/std/math/isinf.zig index 6eacab52ad..eeac61915c 100644 --- a/lib/std/math/isinf.zig +++ b/lib/std/math/isinf.zig @@ -74,6 +74,10 @@ pub fn isNegativeInf(x: var) bool { } test "math.isInf" { + if (std.Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } expect(!isInf(@as(f16, 0.0))); expect(!isInf(@as(f16, -0.0))); expect(!isInf(@as(f32, 0.0))); @@ -93,6 +97,10 @@ test "math.isInf" { } test "math.isPositiveInf" { + if (std.Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } expect(!isPositiveInf(@as(f16, 0.0))); expect(!isPositiveInf(@as(f16, -0.0))); expect(!isPositiveInf(@as(f32, 0.0))); @@ -112,6 +120,10 @@ test "math.isPositiveInf" { } test "math.isNegativeInf" { + if (std.Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } expect(!isNegativeInf(@as(f16, 0.0))); expect(!isNegativeInf(@as(f16, -0.0))); expect(!isNegativeInf(@as(f32, 0.0))); diff --git a/lib/std/math/isnan.zig b/lib/std/math/isnan.zig index ac865f0d0c..4b7e69490a 100644 --- a/lib/std/math/isnan.zig +++ b/lib/std/math/isnan.zig @@ -16,6 +16,10 @@ pub fn isSignalNan(x: var) bool { } test "math.isNan" { + if (std.Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } expect(isNan(math.nan(f16))); expect(isNan(math.nan(f32))); expect(isNan(math.nan(f64))); diff --git a/lib/std/mem.zig b/lib/std/mem.zig index f7b2bf261d..46f23c84fe 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -175,6 +175,7 @@ pub const Allocator = struct { const old_byte_slice = @sliceToBytes(old_mem); const byte_count = math.mul(usize, @sizeOf(T), new_n) catch return Error.OutOfMemory; + // Note: can't set shrunk memory to undefined as memory shouldn't be modified on realloc failure const byte_slice = try self.reallocFn(self, old_byte_slice, Slice.alignment, byte_count, new_alignment); assert(byte_slice.len == byte_count); if (new_n > old_mem.len) { @@ -221,6 +222,7 @@ pub const Allocator = struct { const byte_count = @sizeOf(T) * new_n; const old_byte_slice = @sliceToBytes(old_mem); + @memset(old_byte_slice.ptr + byte_count, undefined, old_byte_slice.len - byte_count); const byte_slice = self.shrinkFn(self, old_byte_slice, Slice.alignment, byte_count, new_alignment); assert(byte_slice.len == byte_count); return @bytesToSlice(T, @alignCast(new_alignment, byte_slice)); @@ -234,6 +236,7 @@ pub const Allocator = struct { const bytes_len = bytes.len + @boolToInt(Slice.sentinel != null); if (bytes_len == 0) return; const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr)); + @memset(non_const_ptr, undefined, bytes_len); const shrink_result = self.shrinkFn(self, non_const_ptr[0..bytes_len], Slice.alignment, 0, 1); assert(shrink_result.len == 0); } diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 5e5850e393..5cb9c6589c 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -556,3 +556,21 @@ pub fn refAllDecls(comptime T: type) void { if (!builtin.is_test) return; _ = declarations(T); } + +/// Returns a slice of pointers to public declarations of a namespace. +pub fn declList(comptime Namespace: type, comptime Decl: type) []const *const Decl { + const S = struct { + fn declNameLessThan(lhs: *const Decl, rhs: *const Decl) bool { + return mem.lessThan(u8, lhs.name, rhs.name); + } + }; + comptime { + const decls = declarations(Namespace); + var array: [decls.len]*const Decl = undefined; + for (decls) |decl, i| { + array[i] = &@field(Namespace, decl.name); + } + std.sort.sort(*const Decl, &array, S.declNameLessThan); + return &array; + } +} diff --git a/lib/std/os.zig b/lib/std/os.zig index c39891c6b0..f881d74835 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2697,7 +2697,7 @@ pub fn dl_iterate_phdr( // the whole ELF image if (it.end()) { var info = dl_phdr_info{ - .dlpi_addr = elf_base, + .dlpi_addr = 0, .dlpi_name = "/proc/self/exe", .dlpi_phdr = phdrs.ptr, .dlpi_phnum = ehdr.e_phnum, diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index fcc1e62489..5c25b4369c 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1041,63 +1041,6 @@ pub fn uname(uts: *utsname) usize { return syscall1(SYS_uname, @ptrToInt(uts)); } -// XXX: This should be weak -extern const __ehdr_start: elf.Ehdr; - -pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, data: ?*T) isize { - if (builtin.link_libc) { - return std.c.dl_iterate_phdr(@ptrCast(std.c.dl_iterate_phdr_callback, callback), @ptrCast(?*c_void, data)); - } - - const elf_base = @ptrToInt(&__ehdr_start); - const n_phdr = __ehdr_start.e_phnum; - const phdrs = (@intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff))[0..n_phdr]; - - var it = dl.linkmap_iterator(phdrs) catch return 0; - - // The executable has no dynamic link segment, create a single entry for - // the whole ELF image - if (it.end()) { - var info = dl_phdr_info{ - .dlpi_addr = elf_base, - .dlpi_name = "/proc/self/exe", - .dlpi_phdr = @intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff), - .dlpi_phnum = __ehdr_start.e_phnum, - }; - - return callback(&info, @sizeOf(dl_phdr_info), data); - } - - // Last return value from the callback function - var last_r: isize = 0; - while (it.next()) |entry| { - var dlpi_phdr: usize = undefined; - var dlpi_phnum: u16 = undefined; - - if (entry.l_addr != 0) { - const elf_header = @intToPtr(*elf.Ehdr, entry.l_addr); - dlpi_phdr = entry.l_addr + elf_header.e_phoff; - dlpi_phnum = elf_header.e_phnum; - } else { - // This is the running ELF image - dlpi_phdr = elf_base + __ehdr_start.e_phoff; - dlpi_phnum = __ehdr_start.e_phnum; - } - - var info = dl_phdr_info{ - .dlpi_addr = entry.l_addr, - .dlpi_name = entry.l_name, - .dlpi_phdr = @intToPtr([*]elf.Phdr, dlpi_phdr), - .dlpi_phnum = dlpi_phnum, - }; - - last_r = callback(&info, @sizeOf(dl_phdr_info), data); - if (last_r != 0) break; - } - - return last_r; -} - pub fn io_uring_setup(entries: u32, p: *io_uring_params) usize { return syscall2(SYS_io_uring_setup, entries, @ptrToInt(p)); } diff --git a/lib/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig index efb1e5fe04..5dbdafb60a 100644 --- a/lib/std/os/linux/tls.zig +++ b/lib/std/os/linux/tls.zig @@ -211,7 +211,7 @@ pub fn initTLS() ?*elf.Phdr { if (tls_phdr) |phdr| { // If the cpu is arm-based, check if it supports the TLS register - if (builtin.arch == builtin.Arch.arm and at_hwcap & std.os.linux.HWCAP_TLS == 0) { + if (builtin.arch == .arm and at_hwcap & std.os.linux.HWCAP_TLS == 0) { // If the CPU does not support TLS via a coprocessor register, // a kernel helper function can be used instead on certain linux kernels. // See linux/arch/arm/include/asm/tls.h and musl/src/thread/arm/__set_thread_area.c. diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index 1e51dd6f82..f71e80c7d7 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -186,8 +186,9 @@ fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) callconv(.C) i32 { if (phdr.p_type != elf.PT_LOAD) continue; + const reloc_addr = info.dlpi_addr + phdr.p_vaddr; // Find the ELF header - const elf_header = @intToPtr(*elf.Ehdr, phdr.p_vaddr - phdr.p_offset); + const elf_header = @intToPtr(*elf.Ehdr, reloc_addr - phdr.p_offset); // Validate the magic if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return -1; // Consistency check diff --git a/lib/std/sort.zig b/lib/std/sort.zig index 9fa7803cba..98bac0678d 100644 --- a/lib/std/sort.zig +++ b/lib/std/sort.zig @@ -7,16 +7,14 @@ const builtin = @import("builtin"); /// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required). pub fn insertionSort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) void { - { - var i: usize = 1; - while (i < items.len) : (i += 1) { - const x = items[i]; - var j: usize = i; - while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) { - items[j] = items[j - 1]; - } - items[j] = x; + var i: usize = 1; + while (i < items.len) : (i += 1) { + const x = items[i]; + var j: usize = i; + while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) { + items[j] = items[j - 1]; } + items[j] = x; } } diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig index 90dbf0cdf4..f5e83b5278 100644 --- a/lib/std/special/compiler_rt.zig +++ b/lib/std/special/compiler_rt.zig @@ -130,6 +130,7 @@ comptime { @export(@import("compiler_rt/int.zig").__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = linkage }); @export(@import("compiler_rt/popcountdi2.zig").__popcountdi2, .{ .name = "__popcountdi2", .linkage = linkage }); + @export(@import("compiler_rt/int.zig").__mulsi3, .{ .name = "__mulsi3", .linkage = linkage }); @export(@import("compiler_rt/muldi3.zig").__muldi3, .{ .name = "__muldi3", .linkage = linkage }); @export(@import("compiler_rt/int.zig").__divmoddi4, .{ .name = "__divmoddi4", .linkage = linkage }); @export(@import("compiler_rt/int.zig").__divsi3, .{ .name = "__divsi3", .linkage = linkage }); diff --git a/lib/std/special/compiler_rt/addXf3_test.zig b/lib/std/special/compiler_rt/addXf3_test.zig index af991b37e9..402bb5a43c 100644 --- a/lib/std/special/compiler_rt/addXf3_test.zig +++ b/lib/std/special/compiler_rt/addXf3_test.zig @@ -31,6 +31,10 @@ fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void { } test "addtf3" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); // NaN + any = NaN @@ -71,6 +75,10 @@ fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void { } test "subtf3" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } // qNaN - any = qNaN test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); diff --git a/lib/std/special/compiler_rt/fixtfdi_test.zig b/lib/std/special/compiler_rt/fixtfdi_test.zig index 6baa9011c3..4c43c90550 100644 --- a/lib/std/special/compiler_rt/fixtfdi_test.zig +++ b/lib/std/special/compiler_rt/fixtfdi_test.zig @@ -11,6 +11,10 @@ fn test__fixtfdi(a: f128, expected: i64) void { } test "fixtfdi" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } //warn("\n", .{}); test__fixtfdi(-math.f128_max, math.minInt(i64)); diff --git a/lib/std/special/compiler_rt/fixtfsi_test.zig b/lib/std/special/compiler_rt/fixtfsi_test.zig index c7294fe250..4eabd0c594 100644 --- a/lib/std/special/compiler_rt/fixtfsi_test.zig +++ b/lib/std/special/compiler_rt/fixtfsi_test.zig @@ -11,6 +11,10 @@ fn test__fixtfsi(a: f128, expected: i32) void { } test "fixtfsi" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } //warn("\n", .{}); test__fixtfsi(-math.f128_max, math.minInt(i32)); diff --git a/lib/std/special/compiler_rt/fixtfti_test.zig b/lib/std/special/compiler_rt/fixtfti_test.zig index 6b8218e2f6..acda2f162b 100644 --- a/lib/std/special/compiler_rt/fixtfti_test.zig +++ b/lib/std/special/compiler_rt/fixtfti_test.zig @@ -11,6 +11,10 @@ fn test__fixtfti(a: f128, expected: i128) void { } test "fixtfti" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } //warn("\n", .{}); test__fixtfti(-math.f128_max, math.minInt(i128)); diff --git a/lib/std/special/compiler_rt/fixunstfdi_test.zig b/lib/std/special/compiler_rt/fixunstfdi_test.zig index 0d47641c09..154fffe18a 100644 --- a/lib/std/special/compiler_rt/fixunstfdi_test.zig +++ b/lib/std/special/compiler_rt/fixunstfdi_test.zig @@ -7,6 +7,10 @@ fn test__fixunstfdi(a: f128, expected: u64) void { } test "fixunstfdi" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } test__fixunstfdi(0.0, 0); test__fixunstfdi(0.5, 0); diff --git a/lib/std/special/compiler_rt/fixunstfsi_test.zig b/lib/std/special/compiler_rt/fixunstfsi_test.zig index 286567629a..af312ddc46 100644 --- a/lib/std/special/compiler_rt/fixunstfsi_test.zig +++ b/lib/std/special/compiler_rt/fixunstfsi_test.zig @@ -9,6 +9,10 @@ fn test__fixunstfsi(a: f128, expected: u32) void { const inf128 = @bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)); test "fixunstfsi" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } test__fixunstfsi(inf128, 0xffffffff); test__fixunstfsi(0, 0x0); test__fixunstfsi(0x1.23456789abcdefp+5, 0x24); diff --git a/lib/std/special/compiler_rt/fixunstfti_test.zig b/lib/std/special/compiler_rt/fixunstfti_test.zig index 62a9bbfecf..84dbf991e2 100644 --- a/lib/std/special/compiler_rt/fixunstfti_test.zig +++ b/lib/std/special/compiler_rt/fixunstfti_test.zig @@ -9,6 +9,10 @@ fn test__fixunstfti(a: f128, expected: u128) void { const inf128 = @bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)); test "fixunstfti" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } test__fixunstfti(inf128, 0xffffffffffffffffffffffffffffffff); test__fixunstfti(0.0, 0); diff --git a/lib/std/special/compiler_rt/floattitf_test.zig b/lib/std/special/compiler_rt/floattitf_test.zig index 53e3e48bdb..0b2b5b958a 100644 --- a/lib/std/special/compiler_rt/floattitf_test.zig +++ b/lib/std/special/compiler_rt/floattitf_test.zig @@ -7,6 +7,10 @@ fn test__floattitf(a: i128, expected: f128) void { } test "floattitf" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } test__floattitf(0, 0.0); test__floattitf(1, 1.0); diff --git a/lib/std/special/compiler_rt/floatuntitf_test.zig b/lib/std/special/compiler_rt/floatuntitf_test.zig index 09f3eabb3e..8b99bbef5d 100644 --- a/lib/std/special/compiler_rt/floatuntitf_test.zig +++ b/lib/std/special/compiler_rt/floatuntitf_test.zig @@ -7,6 +7,10 @@ fn test__floatuntitf(a: u128, expected: f128) void { } test "floatuntitf" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } test__floatuntitf(0, 0.0); test__floatuntitf(1, 1.0); diff --git a/lib/std/special/compiler_rt/int.zig b/lib/std/special/compiler_rt/int.zig index 88f4d66966..eb731ee898 100644 --- a/lib/std/special/compiler_rt/int.zig +++ b/lib/std/special/compiler_rt/int.zig @@ -1,6 +1,8 @@ // Builtin functions that operate on integer types const builtin = @import("builtin"); const testing = @import("std").testing; +const maxInt = @import("std").math.maxInt; +const minInt = @import("std").math.minInt; const udivmod = @import("udivmod.zig").udivmod; @@ -578,3 +580,61 @@ fn test_one_umodsi3(a: u32, b: u32, expected_r: u32) void { const r: u32 = __umodsi3(a, b); testing.expect(r == expected_r); } + +pub fn __mulsi3(a: i32, b: i32) callconv(.C) i32 { + @setRuntimeSafety(builtin.is_test); + + var ua = @bitCast(u32, a); + var ub = @bitCast(u32, b); + var r: u32 = 0; + + while (ua > 0) { + if ((ua & 1) != 0) r +%= ub; + ua >>= 1; + ub <<= 1; + } + + return @bitCast(i32, r); +} + +fn test_one_mulsi3(a: i32, b: i32, result: i32) void { + testing.expectEqual(result, __mulsi3(a, b)); +} + +test "mulsi3" { + test_one_mulsi3(0, 0, 0); + test_one_mulsi3(0, 1, 0); + test_one_mulsi3(1, 0, 0); + test_one_mulsi3(0, 10, 0); + test_one_mulsi3(10, 0, 0); + test_one_mulsi3(0, maxInt(i32), 0); + test_one_mulsi3(maxInt(i32), 0, 0); + test_one_mulsi3(0, -1, 0); + test_one_mulsi3(-1, 0, 0); + test_one_mulsi3(0, -10, 0); + test_one_mulsi3(-10, 0, 0); + test_one_mulsi3(0, minInt(i32), 0); + test_one_mulsi3(minInt(i32), 0, 0); + test_one_mulsi3(1, 1, 1); + test_one_mulsi3(1, 10, 10); + test_one_mulsi3(10, 1, 10); + test_one_mulsi3(1, maxInt(i32), maxInt(i32)); + test_one_mulsi3(maxInt(i32), 1, maxInt(i32)); + test_one_mulsi3(1, -1, -1); + test_one_mulsi3(1, -10, -10); + test_one_mulsi3(-10, 1, -10); + test_one_mulsi3(1, minInt(i32), minInt(i32)); + test_one_mulsi3(minInt(i32), 1, minInt(i32)); + test_one_mulsi3(46340, 46340, 2147395600); + test_one_mulsi3(-46340, 46340, -2147395600); + test_one_mulsi3(46340, -46340, -2147395600); + test_one_mulsi3(-46340, -46340, 2147395600); + test_one_mulsi3(4194303, 8192, @truncate(i32, 34359730176)); + test_one_mulsi3(-4194303, 8192, @truncate(i32, -34359730176)); + test_one_mulsi3(4194303, -8192, @truncate(i32, -34359730176)); + test_one_mulsi3(-4194303, -8192, @truncate(i32, 34359730176)); + test_one_mulsi3(8192, 4194303, @truncate(i32, 34359730176)); + test_one_mulsi3(-8192, 4194303, @truncate(i32, -34359730176)); + test_one_mulsi3(8192, -4194303, @truncate(i32, -34359730176)); + test_one_mulsi3(-8192, -4194303, @truncate(i32, 34359730176)); +} diff --git a/lib/std/special/compiler_rt/mulXf3_test.zig b/lib/std/special/compiler_rt/mulXf3_test.zig index 57dc385321..00db984a89 100644 --- a/lib/std/special/compiler_rt/mulXf3_test.zig +++ b/lib/std/special/compiler_rt/mulXf3_test.zig @@ -44,6 +44,10 @@ fn makeNaN128(rand: u64) f128 { return float_result; } test "multf3" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } // qNaN * any = qNaN test__multf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); diff --git a/lib/std/special/compiler_rt/truncXfYf2_test.zig b/lib/std/special/compiler_rt/truncXfYf2_test.zig index baec2a4450..f14dbe6b43 100644 --- a/lib/std/special/compiler_rt/truncXfYf2_test.zig +++ b/lib/std/special/compiler_rt/truncXfYf2_test.zig @@ -151,6 +151,10 @@ fn test__trunctfsf2(a: f128, expected: u32) void { } test "trunctfsf2" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } // qnan test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); // nan @@ -186,6 +190,10 @@ fn test__trunctfdf2(a: f128, expected: u64) void { } test "trunctfdf2" { + if (@import("std").Target.current.isWindows()) { + // TODO https://github.com/ziglang/zig/issues/508 + return error.SkipZigTest; + } // qnan test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); // nan diff --git a/lib/std/target.zig b/lib/std/target.zig index 42cbe6c7fc..09f56dcb87 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -49,6 +49,22 @@ pub const Target = union(enum) { other, }; + pub const aarch64 = @import("target/aarch64.zig"); + pub const amdgpu = @import("target/amdgpu.zig"); + pub const arm = @import("target/arm.zig"); + pub const avr = @import("target/avr.zig"); + pub const bpf = @import("target/bpf.zig"); + pub const hexagon = @import("target/hexagon.zig"); + pub const mips = @import("target/mips.zig"); + pub const msp430 = @import("target/msp430.zig"); + pub const nvptx = @import("target/nvptx.zig"); + pub const powerpc = @import("target/powerpc.zig"); + pub const riscv = @import("target/riscv.zig"); + pub const sparc = @import("target/sparc.zig"); + pub const systemz = @import("target/systemz.zig"); + pub const wasm = @import("target/wasm.zig"); + pub const x86 = @import("target/x86.zig"); + pub const Arch = union(enum) { arm: Arm32, armeb: Arm32, @@ -108,12 +124,12 @@ pub const Target = union(enum) { v8_3a, v8_2a, v8_1a, - v8, + v8a, v8r, v8m_baseline, v8m_mainline, v8_1m_mainline, - v7, + v7a, v7em, v7m, v7s, @@ -129,8 +145,8 @@ pub const Target = union(enum) { pub fn version(version: Arm32) comptime_int { return switch (version) { - .v8_5a, .v8_4a, .v8_3a, .v8_2a, .v8_1a, .v8, .v8r, .v8m_baseline, .v8m_mainline, .v8_1m_mainline => 8, - .v7, .v7em, .v7m, .v7s, .v7k, .v7ve => 7, + .v8_5a, .v8_4a, .v8_3a, .v8_2a, .v8_1a, .v8a, .v8r, .v8m_baseline, .v8m_mainline, .v8_1m_mainline => 8, + .v7a, .v7em, .v7m, .v7s, .v7k, .v7ve => 7, .v6, .v6m, .v6k, .v6t2 => 6, .v5, .v5te => 5, .v4t => 4, @@ -143,10 +159,7 @@ pub const Target = union(enum) { v8_3a, v8_2a, v8_1a, - v8, - v8r, - v8m_baseline, - v8m_mainline, + v8a, }; pub const Kalimba = enum { v5, @@ -160,6 +173,54 @@ pub const Target = union(enum) { spe, }; + pub fn subArchName(arch: Arch) ?[]const u8 { + return switch (arch) { + .arm, .armeb, .thumb, .thumbeb => |arm32| @tagName(arm32), + .aarch64, .aarch64_be, .aarch64_32 => |arm64| @tagName(arm64), + .kalimba => |kalimba| @tagName(kalimba), + else => return null, + }; + } + + pub fn subArchFeature(arch: Arch) ?Cpu.Feature.Set.Index { + return switch (arch) { + .arm, .armeb, .thumb, .thumbeb => |arm32| switch (arm32) { + .v8_5a => @enumToInt(arm.Feature.armv8_5_a), + .v8_4a => @enumToInt(arm.Feature.armv8_4_a), + .v8_3a => @enumToInt(arm.Feature.armv8_3_a), + .v8_2a => @enumToInt(arm.Feature.armv8_2_a), + .v8_1a => @enumToInt(arm.Feature.armv8_1_a), + .v8a => @enumToInt(arm.Feature.armv8_a), + .v8r => @enumToInt(arm.Feature.armv8_r), + .v8m_baseline => @enumToInt(arm.Feature.armv8_m_base), + .v8m_mainline => @enumToInt(arm.Feature.armv8_m_main), + .v8_1m_mainline => @enumToInt(arm.Feature.armv8_1_m_main), + .v7a => @enumToInt(arm.Feature.armv7_a), + .v7em => @enumToInt(arm.Feature.armv7e_m), + .v7m => @enumToInt(arm.Feature.armv7_m), + .v7s => @enumToInt(arm.Feature.armv7s), + .v7k => @enumToInt(arm.Feature.armv7k), + .v7ve => @enumToInt(arm.Feature.armv7ve), + .v6 => @enumToInt(arm.Feature.armv6), + .v6m => @enumToInt(arm.Feature.armv6_m), + .v6k => @enumToInt(arm.Feature.armv6k), + .v6t2 => @enumToInt(arm.Feature.armv6t2), + .v5 => @enumToInt(arm.Feature.armv5t), + .v5te => @enumToInt(arm.Feature.armv5te), + .v4t => @enumToInt(arm.Feature.armv4t), + }, + .aarch64, .aarch64_be, .aarch64_32 => |arm64| switch (arm64) { + .v8_5a => @enumToInt(aarch64.Feature.v8_5a), + .v8_4a => @enumToInt(aarch64.Feature.v8_4a), + .v8_3a => @enumToInt(aarch64.Feature.v8_3a), + .v8_2a => @enumToInt(aarch64.Feature.v8_2a), + .v8_1a => @enumToInt(aarch64.Feature.v8_1a), + .v8a => @enumToInt(aarch64.Feature.v8a), + }, + else => return null, + }; + } + pub fn isARM(arch: Arch) bool { return switch (arch) { .arm, .armeb => true, @@ -188,6 +249,53 @@ pub const Target = union(enum) { }; } + pub fn parseCpu(arch: Arch, cpu_name: []const u8) !*const Cpu { + for (arch.allCpus()) |cpu| { + if (mem.eql(u8, cpu_name, cpu.name)) { + return cpu; + } + } + return error.UnknownCpu; + } + + /// Comma-separated list of features, with + or - in front of each feature. This + /// form represents a deviation from baseline CPU, which is provided as a parameter. + /// Extra commas are ignored. + pub fn parseCpuFeatureSet(arch: Arch, cpu: *const Cpu, features_text: []const u8) !Cpu.Feature.Set { + const all_features = arch.allFeaturesList(); + var set = cpu.features; + var it = mem.tokenize(features_text, ","); + while (it.next()) |item_text| { + var feature_name: []const u8 = undefined; + var op: enum { + add, + sub, + } = undefined; + if (mem.startsWith(u8, item_text, "+")) { + op = .add; + feature_name = item_text[1..]; + } else if (mem.startsWith(u8, item_text, "-")) { + op = .sub; + feature_name = item_text[1..]; + } else { + return error.InvalidCpuFeatures; + } + for (all_features) |feature, index_usize| { + const index = @intCast(Cpu.Feature.Set.Index, index_usize); + if (mem.eql(u8, feature_name, feature.name)) { + switch (op) { + .add => set.addFeature(index), + .sub => set.removeFeature(index), + } + break; + } + } else { + return error.UnknownCpuFeature; + } + } + return set; + } + pub fn toElfMachine(arch: Arch) std.elf.EM { return switch (arch) { .avr => ._AVR, @@ -300,6 +408,109 @@ pub const Target = union(enum) { => .Big, }; } + + /// Returns a name that matches the lib/std/target/* directory name. + pub fn genericName(arch: Arch) []const u8 { + return switch (arch) { + .arm, .armeb, .thumb, .thumbeb => "arm", + .aarch64, .aarch64_be, .aarch64_32 => "aarch64", + .avr => "avr", + .bpfel, .bpfeb => "bpf", + .hexagon => "hexagon", + .mips, .mipsel, .mips64, .mips64el => "mips", + .msp430 => "msp430", + .powerpc, .powerpc64, .powerpc64le => "powerpc", + .amdgcn => "amdgpu", + .riscv32, .riscv64 => "riscv", + .sparc, .sparcv9, .sparcel => "sparc", + .s390x => "systemz", + .i386, .x86_64 => "x86", + .nvptx, .nvptx64 => "nvptx", + .wasm32, .wasm64 => "wasm", + else => @tagName(arch), + }; + } + + /// All CPU features Zig is aware of, sorted lexicographically by name. + pub fn allFeaturesList(arch: Arch) []const Cpu.Feature { + return switch (arch) { + .arm, .armeb, .thumb, .thumbeb => &arm.all_features, + .aarch64, .aarch64_be, .aarch64_32 => &aarch64.all_features, + .avr => &avr.all_features, + .bpfel, .bpfeb => &bpf.all_features, + .hexagon => &hexagon.all_features, + .mips, .mipsel, .mips64, .mips64el => &mips.all_features, + .msp430 => &msp430.all_features, + .powerpc, .powerpc64, .powerpc64le => &powerpc.all_features, + .amdgcn => &amdgpu.all_features, + .riscv32, .riscv64 => &riscv.all_features, + .sparc, .sparcv9, .sparcel => &sparc.all_features, + .s390x => &systemz.all_features, + .i386, .x86_64 => &x86.all_features, + .nvptx, .nvptx64 => &nvptx.all_features, + .wasm32, .wasm64 => &wasm.all_features, + + else => &[0]Cpu.Feature{}, + }; + } + + /// The "default" set of CPU features for cross-compiling. A conservative set + /// of features that is expected to be supported on most available hardware. + pub fn getBaselineCpuFeatures(arch: Arch) CpuFeatures { + const S = struct { + const generic_cpu = Cpu{ + .name = "generic", + .llvm_name = null, + .features = Cpu.Feature.Set.empty, + }; + }; + const cpu = switch (arch) { + .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic, + .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic, + .avr => &avr.cpu.avr1, + .bpfel, .bpfeb => &bpf.cpu.generic, + .hexagon => &hexagon.cpu.generic, + .mips, .mipsel => &mips.cpu.mips32, + .mips64, .mips64el => &mips.cpu.mips64, + .msp430 => &msp430.cpu.generic, + .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic, + .amdgcn => &amdgpu.cpu.generic, + .riscv32 => &riscv.cpu.baseline_rv32, + .riscv64 => &riscv.cpu.baseline_rv64, + .sparc, .sparcv9, .sparcel => &sparc.cpu.generic, + .s390x => &systemz.cpu.generic, + .i386 => &x86.cpu.pentium4, + .x86_64 => &x86.cpu.x86_64, + .nvptx, .nvptx64 => &nvptx.cpu.sm_20, + .wasm32, .wasm64 => &wasm.cpu.generic, + + else => &S.generic_cpu, + }; + return CpuFeatures.initFromCpu(arch, cpu); + } + + /// All CPUs Zig is aware of, sorted lexicographically by name. + pub fn allCpus(arch: Arch) []const *const Cpu { + return switch (arch) { + .arm, .armeb, .thumb, .thumbeb => arm.all_cpus, + .aarch64, .aarch64_be, .aarch64_32 => aarch64.all_cpus, + .avr => avr.all_cpus, + .bpfel, .bpfeb => bpf.all_cpus, + .hexagon => hexagon.all_cpus, + .mips, .mipsel, .mips64, .mips64el => mips.all_cpus, + .msp430 => msp430.all_cpus, + .powerpc, .powerpc64, .powerpc64le => powerpc.all_cpus, + .amdgcn => amdgpu.all_cpus, + .riscv32, .riscv64 => riscv.all_cpus, + .sparc, .sparcv9, .sparcel => sparc.all_cpus, + .s390x => systemz.all_cpus, + .i386, .x86_64 => x86.all_cpus, + .nvptx, .nvptx64 => nvptx.all_cpus, + .wasm32, .wasm64 => wasm.all_cpus, + + else => &[0]*const Cpu{}, + }; + } }; pub const Abi = enum { @@ -325,6 +536,109 @@ pub const Target = union(enum) { macabi, }; + pub const Cpu = struct { + name: []const u8, + llvm_name: ?[:0]const u8, + features: Feature.Set, + + pub const Feature = struct { + /// The bit index into `Set`. Has a default value of `undefined` because the canonical + /// structures are populated via comptime logic. + index: Set.Index = undefined, + + /// Has a default value of `undefined` because the canonical + /// structures are populated via comptime logic. + name: []const u8 = undefined, + + /// If this corresponds to an LLVM-recognized feature, this will be populated; + /// otherwise null. + llvm_name: ?[:0]const u8, + + /// Human-friendly UTF-8 text. + description: []const u8, + + /// Sparse `Set` of features this depends on. + dependencies: Set, + + /// A bit set of all the features. + pub const Set = struct { + ints: [usize_count]usize, + + pub const needed_bit_count = 174; + pub const byte_count = (needed_bit_count + 7) / 8; + pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize); + pub const Index = std.math.Log2Int(@IntType(false, usize_count * @bitSizeOf(usize))); + pub const ShiftInt = std.math.Log2Int(usize); + + pub const empty = Set{ .ints = [1]usize{0} ** usize_count }; + pub fn empty_workaround() Set { + return Set{ .ints = [1]usize{0} ** usize_count }; + } + + pub fn isEnabled(set: Set, arch_feature_index: Index) bool { + const usize_index = arch_feature_index / @bitSizeOf(usize); + const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize)); + return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0; + } + + /// Adds the specified feature but not its dependencies. + pub fn addFeature(set: *Set, arch_feature_index: Index) void { + const usize_index = arch_feature_index / @bitSizeOf(usize); + const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize)); + set.ints[usize_index] |= @as(usize, 1) << bit_index; + } + + /// Removes the specified feature but not its dependents. + pub fn removeFeature(set: *Set, arch_feature_index: Index) void { + const usize_index = arch_feature_index / @bitSizeOf(usize); + const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize)); + set.ints[usize_index] &= ~(@as(usize, 1) << bit_index); + } + + pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void { + var old = set.ints; + while (true) { + for (all_features_list) |feature, index_usize| { + const index = @intCast(Index, index_usize); + if (set.isEnabled(index)) { + set.ints = @as(@Vector(usize_count, usize), set.ints) | + @as(@Vector(usize_count, usize), feature.dependencies.ints); + } + } + const nothing_changed = mem.eql(usize, &old, &set.ints); + if (nothing_changed) return; + old = set.ints; + } + } + + pub fn asBytes(set: *const Set) *const [byte_count]u8 { + return @ptrCast(*const [byte_count]u8, &set.ints); + } + + pub fn eql(set: Set, other: Set) bool { + return mem.eql(usize, &set.ints, &other.ints); + } + }; + + pub fn feature_set_fns(comptime F: type) type { + return struct { + /// Populates only the feature bits specified. + pub fn featureSet(features: []const F) Set { + var x = Set.empty_workaround(); // TODO remove empty_workaround + for (features) |feature| { + x.addFeature(@enumToInt(feature)); + } + return x; + } + + pub fn featureSetHas(set: Set, feature: F) bool { + return set.isEnabled(@enumToInt(feature)); + } + }; + } + }; + }; + pub const ObjectFormat = enum { unknown, coff, @@ -348,6 +662,28 @@ pub const Target = union(enum) { arch: Arch, os: Os, abi: Abi, + cpu_features: CpuFeatures, + }; + + pub const CpuFeatures = struct { + /// The CPU to target. It has a set of features + /// which are overridden with the `features` field. + cpu: *const Cpu, + + /// Explicitly provide the entire CPU feature set. + features: Cpu.Feature.Set, + + pub fn initFromCpu(arch: Arch, cpu: *const Cpu) CpuFeatures { + var features = cpu.features; + if (arch.subArchFeature()) |sub_arch_index| { + features.addFeature(sub_arch_index); + } + features.populateDependencies(arch.allFeaturesList()); + return CpuFeatures{ + .cpu = cpu, + .features = features, + }; + } }; pub const current = Target{ @@ -355,11 +691,19 @@ pub const Target = union(enum) { .arch = builtin.arch, .os = builtin.os, .abi = builtin.abi, + .cpu_features = builtin.cpu_features, }, }; pub const stack_align = 16; + pub fn getCpuFeatures(self: Target) CpuFeatures { + return switch (self) { + .Native => builtin.cpu_features, + .Cross => |cross| cross.cpu_features, + }; + } + pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 { return std.fmt.allocPrint(allocator, "{}{}-{}-{}", .{ @tagName(self.getArch()), @@ -425,14 +769,18 @@ pub const Target = union(enum) { }); } + /// TODO: Support CPU features here? + /// https://github.com/ziglang/zig/issues/4261 pub fn parse(text: []const u8) !Target { var it = mem.separate(text, "-"); const arch_name = it.next() orelse return error.MissingArchitecture; const os_name = it.next() orelse return error.MissingOperatingSystem; const abi_name = it.next(); + const arch = try parseArchSub(arch_name); var cross = Cross{ - .arch = try parseArchSub(arch_name), + .arch = arch, + .cpu_features = arch.getBaselineCpuFeatures(), .os = try parseOs(os_name), .abi = undefined, }; @@ -498,7 +846,7 @@ pub const Target = union(enum) { pub fn parseArchSub(text: []const u8) ParseArchSubError!Arch { const info = @typeInfo(Arch); inline for (info.Union.fields) |field| { - if (mem.eql(u8, text, field.name)) { + if (mem.startsWith(u8, text, field.name)) { if (field.field_type == void) { return @as(Arch, @field(Arch, field.name)); } else { @@ -819,3 +1167,15 @@ pub const Target = union(enum) { return .unavailable; } }; + +test "parseCpuFeatureSet" { + const arch: Target.Arch = .x86_64; + const baseline = arch.getBaselineCpuFeatures(); + const set = try arch.parseCpuFeatureSet(baseline.cpu, "-sse,-avx,-cx8"); + std.testing.expect(!Target.x86.featureSetHas(set, .sse)); + std.testing.expect(!Target.x86.featureSetHas(set, .avx)); + std.testing.expect(!Target.x86.featureSetHas(set, .cx8)); + // These are expected because they are part of the baseline + std.testing.expect(Target.x86.featureSetHas(set, .cmov)); + std.testing.expect(Target.x86.featureSetHas(set, .fxsr)); +} diff --git a/lib/std/target/aarch64.zig b/lib/std/target/aarch64.zig new file mode 100644 index 0000000000..d2878e2423 --- /dev/null +++ b/lib/std/target/aarch64.zig @@ -0,0 +1,1450 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + a35, + a53, + a55, + a57, + a72, + a73, + a75, + a76, + aes, + aggressive_fma, + alternate_sextload_cvt_f32_pattern, + altnzcv, + am, + arith_bcc_fusion, + arith_cbz_fusion, + balance_fp_ops, + bti, + call_saved_x10, + call_saved_x11, + call_saved_x12, + call_saved_x13, + call_saved_x14, + call_saved_x15, + call_saved_x18, + call_saved_x8, + call_saved_x9, + ccdp, + ccidx, + ccpp, + complxnum, + crc, + crypto, + custom_cheap_as_move, + cyclone, + disable_latency_sched_heuristic, + dit, + dotprod, + exynos_cheap_as_move, + exynosm1, + exynosm2, + exynosm3, + exynosm4, + falkor, + fmi, + force_32bit_jump_tables, + fp_armv8, + fp16fml, + fptoint, + fullfp16, + fuse_address, + fuse_aes, + fuse_arith_logic, + fuse_crypto_eor, + fuse_csel, + fuse_literals, + jsconv, + kryo, + lor, + lse, + lsl_fast, + mpam, + mte, + neon, + no_neg_immediates, + nv, + pa, + pan, + pan_rwv, + perfmon, + predictable_select_expensive, + predres, + rand, + ras, + rasv8_4, + rcpc, + rcpc_immo, + rdm, + reserve_x1, + reserve_x10, + reserve_x11, + reserve_x12, + reserve_x13, + reserve_x14, + reserve_x15, + reserve_x18, + reserve_x2, + reserve_x20, + reserve_x21, + reserve_x22, + reserve_x23, + reserve_x24, + reserve_x25, + reserve_x26, + reserve_x27, + reserve_x28, + reserve_x3, + reserve_x4, + reserve_x5, + reserve_x6, + reserve_x7, + reserve_x9, + saphira, + sb, + sel2, + sha2, + sha3, + slow_misaligned_128store, + slow_paired_128, + slow_strqro_store, + sm4, + spe, + specrestrict, + ssbs, + strict_align, + sve, + sve2, + sve2_aes, + sve2_bitperm, + sve2_sha3, + sve2_sm4, + thunderx, + thunderx2t99, + thunderxt81, + thunderxt83, + thunderxt88, + tlb_rmi, + tpidr_el1, + tpidr_el2, + tpidr_el3, + tracev8_4, + tsv110, + uaops, + use_aa, + use_postra_scheduler, + use_reciprocal_square_root, + v8a, + v8_1a, + v8_2a, + v8_3a, + v8_4a, + v8_5a, + vh, + zcm, + zcz, + zcz_fp, + zcz_fp_workaround, + zcz_gp, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + @setEvalBranchQuota(2000); + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.a35)] = .{ + .llvm_name = "a35", + .description = "Cortex-A35 ARM processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .fp_armv8, + .neon, + .perfmon, + }), + }; + result[@enumToInt(Feature.a53)] = .{ + .llvm_name = "a53", + .description = "Cortex-A53 ARM processors", + .dependencies = featureSet(&[_]Feature{ + .balance_fp_ops, + .crc, + .crypto, + .custom_cheap_as_move, + .fp_armv8, + .fuse_aes, + .neon, + .perfmon, + .use_aa, + .use_postra_scheduler, + }), + }; + result[@enumToInt(Feature.a55)] = .{ + .llvm_name = "a55", + .description = "Cortex-A55 ARM processors", + .dependencies = featureSet(&[_]Feature{ + .crypto, + .dotprod, + .fp_armv8, + .fullfp16, + .fuse_aes, + .neon, + .perfmon, + .rcpc, + .v8_2a, + }), + }; + result[@enumToInt(Feature.a57)] = .{ + .llvm_name = "a57", + .description = "Cortex-A57 ARM processors", + .dependencies = featureSet(&[_]Feature{ + .balance_fp_ops, + .crc, + .crypto, + .custom_cheap_as_move, + .fp_armv8, + .fuse_aes, + .fuse_literals, + .neon, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + }), + }; + result[@enumToInt(Feature.a72)] = .{ + .llvm_name = "a72", + .description = "Cortex-A72 ARM processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .fp_armv8, + .fuse_aes, + .neon, + .perfmon, + }), + }; + result[@enumToInt(Feature.a73)] = .{ + .llvm_name = "a73", + .description = "Cortex-A73 ARM processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .fp_armv8, + .fuse_aes, + .neon, + .perfmon, + }), + }; + result[@enumToInt(Feature.a75)] = .{ + .llvm_name = "a75", + .description = "Cortex-A75 ARM processors", + .dependencies = featureSet(&[_]Feature{ + .crypto, + .dotprod, + .fp_armv8, + .fullfp16, + .fuse_aes, + .neon, + .perfmon, + .rcpc, + .v8_2a, + }), + }; + result[@enumToInt(Feature.a76)] = .{ + .llvm_name = "a76", + .description = "Cortex-A76 ARM processors", + .dependencies = featureSet(&[_]Feature{ + .crypto, + .dotprod, + .fp_armv8, + .fullfp16, + .neon, + .rcpc, + .ssbs, + .v8_2a, + }), + }; + result[@enumToInt(Feature.aes)] = .{ + .llvm_name = "aes", + .description = "Enable AES support", + .dependencies = featureSet(&[_]Feature{ + .neon, + }), + }; + result[@enumToInt(Feature.aggressive_fma)] = .{ + .llvm_name = "aggressive-fma", + .description = "Enable Aggressive FMA for floating-point.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.alternate_sextload_cvt_f32_pattern)] = .{ + .llvm_name = "alternate-sextload-cvt-f32-pattern", + .description = "Use alternative pattern for sextload convert to f32", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.altnzcv)] = .{ + .llvm_name = "altnzcv", + .description = "Enable alternative NZCV format for floating point comparisons", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.am)] = .{ + .llvm_name = "am", + .description = "Enable v8.4-A Activity Monitors extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.arith_bcc_fusion)] = .{ + .llvm_name = "arith-bcc-fusion", + .description = "CPU fuses arithmetic+bcc operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.arith_cbz_fusion)] = .{ + .llvm_name = "arith-cbz-fusion", + .description = "CPU fuses arithmetic + cbz/cbnz operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.balance_fp_ops)] = .{ + .llvm_name = "balance-fp-ops", + .description = "balance mix of odd and even D-registers for fp multiply(-accumulate) ops", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.bti)] = .{ + .llvm_name = "bti", + .description = "Enable Branch Target Identification", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.call_saved_x10)] = .{ + .llvm_name = "call-saved-x10", + .description = "Make X10 callee saved.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.call_saved_x11)] = .{ + .llvm_name = "call-saved-x11", + .description = "Make X11 callee saved.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.call_saved_x12)] = .{ + .llvm_name = "call-saved-x12", + .description = "Make X12 callee saved.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.call_saved_x13)] = .{ + .llvm_name = "call-saved-x13", + .description = "Make X13 callee saved.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.call_saved_x14)] = .{ + .llvm_name = "call-saved-x14", + .description = "Make X14 callee saved.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.call_saved_x15)] = .{ + .llvm_name = "call-saved-x15", + .description = "Make X15 callee saved.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.call_saved_x18)] = .{ + .llvm_name = "call-saved-x18", + .description = "Make X18 callee saved.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.call_saved_x8)] = .{ + .llvm_name = "call-saved-x8", + .description = "Make X8 callee saved.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.call_saved_x9)] = .{ + .llvm_name = "call-saved-x9", + .description = "Make X9 callee saved.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ccdp)] = .{ + .llvm_name = "ccdp", + .description = "Enable v8.5 Cache Clean to Point of Deep Persistence", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ccidx)] = .{ + .llvm_name = "ccidx", + .description = "Enable v8.3-A Extend of the CCSIDR number of sets", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ccpp)] = .{ + .llvm_name = "ccpp", + .description = "Enable v8.2 data Cache Clean to Point of Persistence", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.complxnum)] = .{ + .llvm_name = "complxnum", + .description = "Enable v8.3-A Floating-point complex number support", + .dependencies = featureSet(&[_]Feature{ + .neon, + }), + }; + result[@enumToInt(Feature.crc)] = .{ + .llvm_name = "crc", + .description = "Enable ARMv8 CRC-32 checksum instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.crypto)] = .{ + .llvm_name = "crypto", + .description = "Enable cryptographic instructions", + .dependencies = featureSet(&[_]Feature{ + .aes, + .neon, + .sha2, + }), + }; + result[@enumToInt(Feature.custom_cheap_as_move)] = .{ + .llvm_name = "custom-cheap-as-move", + .description = "Use custom handling of cheap instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.cyclone)] = .{ + .llvm_name = "cyclone", + .description = "Cyclone", + .dependencies = featureSet(&[_]Feature{ + .alternate_sextload_cvt_f32_pattern, + .arith_bcc_fusion, + .arith_cbz_fusion, + .crypto, + .disable_latency_sched_heuristic, + .fp_armv8, + .fuse_aes, + .fuse_crypto_eor, + .neon, + .perfmon, + .zcm, + .zcz, + .zcz_fp_workaround, + }), + }; + result[@enumToInt(Feature.disable_latency_sched_heuristic)] = .{ + .llvm_name = "disable-latency-sched-heuristic", + .description = "Disable latency scheduling heuristic", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dit)] = .{ + .llvm_name = "dit", + .description = "Enable v8.4-A Data Independent Timing instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dotprod)] = .{ + .llvm_name = "dotprod", + .description = "Enable dot product support", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.exynos_cheap_as_move)] = .{ + .llvm_name = "exynos-cheap-as-move", + .description = "Use Exynos specific handling of cheap instructions", + .dependencies = featureSet(&[_]Feature{ + .custom_cheap_as_move, + }), + }; + result[@enumToInt(Feature.exynosm1)] = .{ + .llvm_name = "exynosm1", + .description = "Samsung Exynos-M1 processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .exynos_cheap_as_move, + .force_32bit_jump_tables, + .fuse_aes, + .perfmon, + .slow_misaligned_128store, + .slow_paired_128, + .use_postra_scheduler, + .use_reciprocal_square_root, + .zcz_fp, + }), + }; + result[@enumToInt(Feature.exynosm2)] = .{ + .llvm_name = "exynosm2", + .description = "Samsung Exynos-M2 processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .exynos_cheap_as_move, + .force_32bit_jump_tables, + .fuse_aes, + .perfmon, + .slow_misaligned_128store, + .slow_paired_128, + .use_postra_scheduler, + .zcz_fp, + }), + }; + result[@enumToInt(Feature.exynosm3)] = .{ + .llvm_name = "exynosm3", + .description = "Samsung Exynos-M3 processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .exynos_cheap_as_move, + .force_32bit_jump_tables, + .fuse_address, + .fuse_aes, + .fuse_csel, + .fuse_literals, + .lsl_fast, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + .zcz_fp, + }), + }; + result[@enumToInt(Feature.exynosm4)] = .{ + .llvm_name = "exynosm4", + .description = "Samsung Exynos-M4 processors", + .dependencies = featureSet(&[_]Feature{ + .arith_bcc_fusion, + .arith_cbz_fusion, + .crypto, + .dotprod, + .exynos_cheap_as_move, + .force_32bit_jump_tables, + .fullfp16, + .fuse_address, + .fuse_aes, + .fuse_arith_logic, + .fuse_csel, + .fuse_literals, + .lsl_fast, + .perfmon, + .use_postra_scheduler, + .v8_2a, + .zcz, + }), + }; + result[@enumToInt(Feature.falkor)] = .{ + .llvm_name = "falkor", + .description = "Qualcomm Falkor processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .custom_cheap_as_move, + .fp_armv8, + .lsl_fast, + .neon, + .perfmon, + .predictable_select_expensive, + .rdm, + .slow_strqro_store, + .use_postra_scheduler, + .zcz, + }), + }; + result[@enumToInt(Feature.fmi)] = .{ + .llvm_name = "fmi", + .description = "Enable v8.4-A Flag Manipulation Instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.force_32bit_jump_tables)] = .{ + .llvm_name = "force-32bit-jump-tables", + .description = "Force jump table entries to be 32-bits wide except at MinSize", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fp_armv8)] = .{ + .llvm_name = "fp-armv8", + .description = "Enable ARMv8 FP", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fp16fml)] = .{ + .llvm_name = "fp16fml", + .description = "Enable FP16 FML instructions", + .dependencies = featureSet(&[_]Feature{ + .fullfp16, + }), + }; + result[@enumToInt(Feature.fptoint)] = .{ + .llvm_name = "fptoint", + .description = "Enable FRInt[32|64][Z|X] instructions that round a floating-point number to an integer (in FP format) forcing it to fit into a 32- or 64-bit int", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fullfp16)] = .{ + .llvm_name = "fullfp16", + .description = "Full FP16", + .dependencies = featureSet(&[_]Feature{ + .fp_armv8, + }), + }; + result[@enumToInt(Feature.fuse_address)] = .{ + .llvm_name = "fuse-address", + .description = "CPU fuses address generation and memory operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fuse_aes)] = .{ + .llvm_name = "fuse-aes", + .description = "CPU fuses AES crypto operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fuse_arith_logic)] = .{ + .llvm_name = "fuse-arith-logic", + .description = "CPU fuses arithmetic and logic operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fuse_crypto_eor)] = .{ + .llvm_name = "fuse-crypto-eor", + .description = "CPU fuses AES/PMULL and EOR operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fuse_csel)] = .{ + .llvm_name = "fuse-csel", + .description = "CPU fuses conditional select operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fuse_literals)] = .{ + .llvm_name = "fuse-literals", + .description = "CPU fuses literal generation operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.jsconv)] = .{ + .llvm_name = "jsconv", + .description = "Enable v8.3-A JavaScript FP conversion enchancement", + .dependencies = featureSet(&[_]Feature{ + .fp_armv8, + }), + }; + result[@enumToInt(Feature.kryo)] = .{ + .llvm_name = "kryo", + .description = "Qualcomm Kryo processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .custom_cheap_as_move, + .fp_armv8, + .lsl_fast, + .neon, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + .zcz, + }), + }; + result[@enumToInt(Feature.lor)] = .{ + .llvm_name = "lor", + .description = "Enables ARM v8.1 Limited Ordering Regions extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lse)] = .{ + .llvm_name = "lse", + .description = "Enable ARMv8.1 Large System Extension (LSE) atomic instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lsl_fast)] = .{ + .llvm_name = "lsl-fast", + .description = "CPU has a fastpath logical shift of up to 3 places", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mpam)] = .{ + .llvm_name = "mpam", + .description = "Enable v8.4-A Memory system Partitioning and Monitoring extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mte)] = .{ + .llvm_name = "mte", + .description = "Enable Memory Tagging Extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.neon)] = .{ + .llvm_name = "neon", + .description = "Enable Advanced SIMD instructions", + .dependencies = featureSet(&[_]Feature{ + .fp_armv8, + }), + }; + result[@enumToInt(Feature.no_neg_immediates)] = .{ + .llvm_name = "no-neg-immediates", + .description = "Convert immediates and instructions to their negated or complemented equivalent when the immediate does not fit in the encoding.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.nv)] = .{ + .llvm_name = "nv", + .description = "Enable v8.4-A Nested Virtualization Enchancement", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.pa)] = .{ + .llvm_name = "pa", + .description = "Enable v8.3-A Pointer Authentication enchancement", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.pan)] = .{ + .llvm_name = "pan", + .description = "Enables ARM v8.1 Privileged Access-Never extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.pan_rwv)] = .{ + .llvm_name = "pan-rwv", + .description = "Enable v8.2 PAN s1e1R and s1e1W Variants", + .dependencies = featureSet(&[_]Feature{ + .pan, + }), + }; + result[@enumToInt(Feature.perfmon)] = .{ + .llvm_name = "perfmon", + .description = "Enable ARMv8 PMUv3 Performance Monitors extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.predictable_select_expensive)] = .{ + .llvm_name = "predictable-select-expensive", + .description = "Prefer likely predicted branches over selects", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.predres)] = .{ + .llvm_name = "predres", + .description = "Enable v8.5a execution and data prediction invalidation instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.rand)] = .{ + .llvm_name = "rand", + .description = "Enable Random Number generation instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ras)] = .{ + .llvm_name = "ras", + .description = "Enable ARMv8 Reliability, Availability and Serviceability Extensions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.rasv8_4)] = .{ + .llvm_name = "rasv8_4", + .description = "Enable v8.4-A Reliability, Availability and Serviceability extension", + .dependencies = featureSet(&[_]Feature{ + .ras, + }), + }; + result[@enumToInt(Feature.rcpc)] = .{ + .llvm_name = "rcpc", + .description = "Enable support for RCPC extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.rcpc_immo)] = .{ + .llvm_name = "rcpc-immo", + .description = "Enable v8.4-A RCPC instructions with Immediate Offsets", + .dependencies = featureSet(&[_]Feature{ + .rcpc, + }), + }; + result[@enumToInt(Feature.rdm)] = .{ + .llvm_name = "rdm", + .description = "Enable ARMv8.1 Rounding Double Multiply Add/Subtract instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x1)] = .{ + .llvm_name = "reserve-x1", + .description = "Reserve X1, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x10)] = .{ + .llvm_name = "reserve-x10", + .description = "Reserve X10, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x11)] = .{ + .llvm_name = "reserve-x11", + .description = "Reserve X11, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x12)] = .{ + .llvm_name = "reserve-x12", + .description = "Reserve X12, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x13)] = .{ + .llvm_name = "reserve-x13", + .description = "Reserve X13, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x14)] = .{ + .llvm_name = "reserve-x14", + .description = "Reserve X14, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x15)] = .{ + .llvm_name = "reserve-x15", + .description = "Reserve X15, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x18)] = .{ + .llvm_name = "reserve-x18", + .description = "Reserve X18, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x2)] = .{ + .llvm_name = "reserve-x2", + .description = "Reserve X2, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x20)] = .{ + .llvm_name = "reserve-x20", + .description = "Reserve X20, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x21)] = .{ + .llvm_name = "reserve-x21", + .description = "Reserve X21, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x22)] = .{ + .llvm_name = "reserve-x22", + .description = "Reserve X22, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x23)] = .{ + .llvm_name = "reserve-x23", + .description = "Reserve X23, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x24)] = .{ + .llvm_name = "reserve-x24", + .description = "Reserve X24, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x25)] = .{ + .llvm_name = "reserve-x25", + .description = "Reserve X25, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x26)] = .{ + .llvm_name = "reserve-x26", + .description = "Reserve X26, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x27)] = .{ + .llvm_name = "reserve-x27", + .description = "Reserve X27, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x28)] = .{ + .llvm_name = "reserve-x28", + .description = "Reserve X28, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x3)] = .{ + .llvm_name = "reserve-x3", + .description = "Reserve X3, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x4)] = .{ + .llvm_name = "reserve-x4", + .description = "Reserve X4, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x5)] = .{ + .llvm_name = "reserve-x5", + .description = "Reserve X5, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x6)] = .{ + .llvm_name = "reserve-x6", + .description = "Reserve X6, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x7)] = .{ + .llvm_name = "reserve-x7", + .description = "Reserve X7, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_x9)] = .{ + .llvm_name = "reserve-x9", + .description = "Reserve X9, making it unavailable as a GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.saphira)] = .{ + .llvm_name = "saphira", + .description = "Qualcomm Saphira processors", + .dependencies = featureSet(&[_]Feature{ + .crypto, + .custom_cheap_as_move, + .fp_armv8, + .lsl_fast, + .neon, + .perfmon, + .predictable_select_expensive, + .spe, + .use_postra_scheduler, + .v8_4a, + .zcz, + }), + }; + result[@enumToInt(Feature.sb)] = .{ + .llvm_name = "sb", + .description = "Enable v8.5 Speculation Barrier", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sel2)] = .{ + .llvm_name = "sel2", + .description = "Enable v8.4-A Secure Exception Level 2 extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sha2)] = .{ + .llvm_name = "sha2", + .description = "Enable SHA1 and SHA256 support", + .dependencies = featureSet(&[_]Feature{ + .neon, + }), + }; + result[@enumToInt(Feature.sha3)] = .{ + .llvm_name = "sha3", + .description = "Enable SHA512 and SHA3 support", + .dependencies = featureSet(&[_]Feature{ + .neon, + .sha2, + }), + }; + result[@enumToInt(Feature.slow_misaligned_128store)] = .{ + .llvm_name = "slow-misaligned-128store", + .description = "Misaligned 128 bit stores are slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_paired_128)] = .{ + .llvm_name = "slow-paired-128", + .description = "Paired 128 bit loads and stores are slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_strqro_store)] = .{ + .llvm_name = "slow-strqro-store", + .description = "STR of Q register with register offset is slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm4)] = .{ + .llvm_name = "sm4", + .description = "Enable SM3 and SM4 support", + .dependencies = featureSet(&[_]Feature{ + .neon, + }), + }; + result[@enumToInt(Feature.spe)] = .{ + .llvm_name = "spe", + .description = "Enable Statistical Profiling extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.specrestrict)] = .{ + .llvm_name = "specrestrict", + .description = "Enable architectural speculation restriction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ssbs)] = .{ + .llvm_name = "ssbs", + .description = "Enable Speculative Store Bypass Safe bit", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.strict_align)] = .{ + .llvm_name = "strict-align", + .description = "Disallow all unaligned memory access", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sve)] = .{ + .llvm_name = "sve", + .description = "Enable Scalable Vector Extension (SVE) instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sve2)] = .{ + .llvm_name = "sve2", + .description = "Enable Scalable Vector Extension 2 (SVE2) instructions", + .dependencies = featureSet(&[_]Feature{ + .sve, + }), + }; + result[@enumToInt(Feature.sve2_aes)] = .{ + .llvm_name = "sve2-aes", + .description = "Enable AES SVE2 instructions", + .dependencies = featureSet(&[_]Feature{ + .aes, + .sve2, + }), + }; + result[@enumToInt(Feature.sve2_bitperm)] = .{ + .llvm_name = "sve2-bitperm", + .description = "Enable bit permutation SVE2 instructions", + .dependencies = featureSet(&[_]Feature{ + .sve2, + }), + }; + result[@enumToInt(Feature.sve2_sha3)] = .{ + .llvm_name = "sve2-sha3", + .description = "Enable SHA3 SVE2 instructions", + .dependencies = featureSet(&[_]Feature{ + .sha3, + .sve2, + }), + }; + result[@enumToInt(Feature.sve2_sm4)] = .{ + .llvm_name = "sve2-sm4", + .description = "Enable SM4 SVE2 instructions", + .dependencies = featureSet(&[_]Feature{ + .sm4, + .sve2, + }), + }; + result[@enumToInt(Feature.thunderx)] = .{ + .llvm_name = "thunderx", + .description = "Cavium ThunderX processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .fp_armv8, + .neon, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + }), + }; + result[@enumToInt(Feature.thunderx2t99)] = .{ + .llvm_name = "thunderx2t99", + .description = "Cavium ThunderX2 processors", + .dependencies = featureSet(&[_]Feature{ + .aggressive_fma, + .arith_bcc_fusion, + .crc, + .crypto, + .fp_armv8, + .lse, + .neon, + .predictable_select_expensive, + .use_postra_scheduler, + .v8_1a, + }), + }; + result[@enumToInt(Feature.thunderxt81)] = .{ + .llvm_name = "thunderxt81", + .description = "Cavium ThunderX processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .fp_armv8, + .neon, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + }), + }; + result[@enumToInt(Feature.thunderxt83)] = .{ + .llvm_name = "thunderxt83", + .description = "Cavium ThunderX processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .fp_armv8, + .neon, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + }), + }; + result[@enumToInt(Feature.thunderxt88)] = .{ + .llvm_name = "thunderxt88", + .description = "Cavium ThunderX processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .fp_armv8, + .neon, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + }), + }; + result[@enumToInt(Feature.tlb_rmi)] = .{ + .llvm_name = "tlb-rmi", + .description = "Enable v8.4-A TLB Range and Maintenance Instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.tpidr_el1)] = .{ + .llvm_name = "tpidr-el1", + .description = "Permit use of TPIDR_EL1 for the TLS base", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.tpidr_el2)] = .{ + .llvm_name = "tpidr-el2", + .description = "Permit use of TPIDR_EL2 for the TLS base", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.tpidr_el3)] = .{ + .llvm_name = "tpidr-el3", + .description = "Permit use of TPIDR_EL3 for the TLS base", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.tracev8_4)] = .{ + .llvm_name = "tracev8.4", + .description = "Enable v8.4-A Trace extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.tsv110)] = .{ + .llvm_name = "tsv110", + .description = "HiSilicon TS-V110 processors", + .dependencies = featureSet(&[_]Feature{ + .crypto, + .custom_cheap_as_move, + .dotprod, + .fp_armv8, + .fp16fml, + .fullfp16, + .fuse_aes, + .neon, + .perfmon, + .spe, + .use_postra_scheduler, + .v8_2a, + }), + }; + result[@enumToInt(Feature.uaops)] = .{ + .llvm_name = "uaops", + .description = "Enable v8.2 UAO PState", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.use_aa)] = .{ + .llvm_name = "use-aa", + .description = "Use alias analysis during codegen", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.use_postra_scheduler)] = .{ + .llvm_name = "use-postra-scheduler", + .description = "Schedule again after register allocation", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.use_reciprocal_square_root)] = .{ + .llvm_name = "use-reciprocal-square-root", + .description = "Use the reciprocal square root approximation", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v8a)] = .{ + .llvm_name = null, + .description = "Support ARM v8a instructions", + .dependencies = featureSet(&[_]Feature{ + .fp_armv8, + .neon, + }), + }; + result[@enumToInt(Feature.v8_1a)] = .{ + .llvm_name = "v8.1a", + .description = "Support ARM v8.1a instructions", + .dependencies = featureSet(&[_]Feature{ + .crc, + .lor, + .lse, + .pan, + .rdm, + .vh, + .v8a, + }), + }; + result[@enumToInt(Feature.v8_2a)] = .{ + .llvm_name = "v8.2a", + .description = "Support ARM v8.2a instructions", + .dependencies = featureSet(&[_]Feature{ + .ccpp, + .pan_rwv, + .ras, + .uaops, + .v8_1a, + }), + }; + result[@enumToInt(Feature.v8_3a)] = .{ + .llvm_name = "v8.3a", + .description = "Support ARM v8.3a instructions", + .dependencies = featureSet(&[_]Feature{ + .ccidx, + .complxnum, + .jsconv, + .pa, + .rcpc, + .v8_2a, + }), + }; + result[@enumToInt(Feature.v8_4a)] = .{ + .llvm_name = "v8.4a", + .description = "Support ARM v8.4a instructions", + .dependencies = featureSet(&[_]Feature{ + .am, + .dit, + .dotprod, + .fmi, + .mpam, + .nv, + .rasv8_4, + .rcpc_immo, + .sel2, + .tlb_rmi, + .tracev8_4, + .v8_3a, + }), + }; + result[@enumToInt(Feature.v8_5a)] = .{ + .llvm_name = "v8.5a", + .description = "Support ARM v8.5a instructions", + .dependencies = featureSet(&[_]Feature{ + .altnzcv, + .bti, + .ccdp, + .fptoint, + .predres, + .sb, + .specrestrict, + .ssbs, + .v8_4a, + }), + }; + result[@enumToInt(Feature.vh)] = .{ + .llvm_name = "vh", + .description = "Enables ARM v8.1 Virtual Host extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.zcm)] = .{ + .llvm_name = "zcm", + .description = "Has zero-cycle register moves", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.zcz)] = .{ + .llvm_name = "zcz", + .description = "Has zero-cycle zeroing instructions", + .dependencies = featureSet(&[_]Feature{ + .zcz_fp, + .zcz_gp, + }), + }; + result[@enumToInt(Feature.zcz_fp)] = .{ + .llvm_name = "zcz-fp", + .description = "Has zero-cycle zeroing instructions for FP registers", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.zcz_fp_workaround)] = .{ + .llvm_name = "zcz-fp-workaround", + .description = "The zero-cycle floating-point zeroing instruction has a bug", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.zcz_gp)] = .{ + .llvm_name = "zcz-gp", + .description = "Has zero-cycle zeroing instructions for generic registers", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const apple_latest = Cpu{ + .name = "apple_latest", + .llvm_name = "apple-latest", + .features = featureSet(&[_]Feature{ + .cyclone, + }), + }; + pub const cortex_a35 = Cpu{ + .name = "cortex_a35", + .llvm_name = "cortex-a35", + .features = featureSet(&[_]Feature{ + .a35, + }), + }; + pub const cortex_a53 = Cpu{ + .name = "cortex_a53", + .llvm_name = "cortex-a53", + .features = featureSet(&[_]Feature{ + .a53, + }), + }; + pub const cortex_a55 = Cpu{ + .name = "cortex_a55", + .llvm_name = "cortex-a55", + .features = featureSet(&[_]Feature{ + .a55, + }), + }; + pub const cortex_a57 = Cpu{ + .name = "cortex_a57", + .llvm_name = "cortex-a57", + .features = featureSet(&[_]Feature{ + .a57, + }), + }; + pub const cortex_a72 = Cpu{ + .name = "cortex_a72", + .llvm_name = "cortex-a72", + .features = featureSet(&[_]Feature{ + .a72, + }), + }; + pub const cortex_a73 = Cpu{ + .name = "cortex_a73", + .llvm_name = "cortex-a73", + .features = featureSet(&[_]Feature{ + .a73, + }), + }; + pub const cortex_a75 = Cpu{ + .name = "cortex_a75", + .llvm_name = "cortex-a75", + .features = featureSet(&[_]Feature{ + .a75, + }), + }; + pub const cortex_a76 = Cpu{ + .name = "cortex_a76", + .llvm_name = "cortex-a76", + .features = featureSet(&[_]Feature{ + .a76, + }), + }; + pub const cortex_a76ae = Cpu{ + .name = "cortex_a76ae", + .llvm_name = "cortex-a76ae", + .features = featureSet(&[_]Feature{ + .a76, + }), + }; + pub const cyclone = Cpu{ + .name = "cyclone", + .llvm_name = "cyclone", + .features = featureSet(&[_]Feature{ + .cyclone, + }), + }; + pub const exynos_m1 = Cpu{ + .name = "exynos_m1", + .llvm_name = "exynos-m1", + .features = featureSet(&[_]Feature{ + .exynosm1, + }), + }; + pub const exynos_m2 = Cpu{ + .name = "exynos_m2", + .llvm_name = "exynos-m2", + .features = featureSet(&[_]Feature{ + .exynosm2, + }), + }; + pub const exynos_m3 = Cpu{ + .name = "exynos_m3", + .llvm_name = "exynos-m3", + .features = featureSet(&[_]Feature{ + .exynosm3, + }), + }; + pub const exynos_m4 = Cpu{ + .name = "exynos_m4", + .llvm_name = "exynos-m4", + .features = featureSet(&[_]Feature{ + .exynosm4, + }), + }; + pub const exynos_m5 = Cpu{ + .name = "exynos_m5", + .llvm_name = "exynos-m5", + .features = featureSet(&[_]Feature{ + .exynosm4, + }), + }; + pub const falkor = Cpu{ + .name = "falkor", + .llvm_name = "falkor", + .features = featureSet(&[_]Feature{ + .falkor, + }), + }; + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{ + .fp_armv8, + .fuse_aes, + .neon, + .perfmon, + .use_postra_scheduler, + }), + }; + pub const kryo = Cpu{ + .name = "kryo", + .llvm_name = "kryo", + .features = featureSet(&[_]Feature{ + .kryo, + }), + }; + pub const saphira = Cpu{ + .name = "saphira", + .llvm_name = "saphira", + .features = featureSet(&[_]Feature{ + .saphira, + }), + }; + pub const thunderx = Cpu{ + .name = "thunderx", + .llvm_name = "thunderx", + .features = featureSet(&[_]Feature{ + .thunderx, + }), + }; + pub const thunderx2t99 = Cpu{ + .name = "thunderx2t99", + .llvm_name = "thunderx2t99", + .features = featureSet(&[_]Feature{ + .thunderx2t99, + }), + }; + pub const thunderxt81 = Cpu{ + .name = "thunderxt81", + .llvm_name = "thunderxt81", + .features = featureSet(&[_]Feature{ + .thunderxt81, + }), + }; + pub const thunderxt83 = Cpu{ + .name = "thunderxt83", + .llvm_name = "thunderxt83", + .features = featureSet(&[_]Feature{ + .thunderxt83, + }), + }; + pub const thunderxt88 = Cpu{ + .name = "thunderxt88", + .llvm_name = "thunderxt88", + .features = featureSet(&[_]Feature{ + .thunderxt88, + }), + }; + pub const tsv110 = Cpu{ + .name = "tsv110", + .llvm_name = "tsv110", + .features = featureSet(&[_]Feature{ + .tsv110, + }), + }; +}; + +/// All aarch64 CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.apple_latest, + &cpu.cortex_a35, + &cpu.cortex_a53, + &cpu.cortex_a55, + &cpu.cortex_a57, + &cpu.cortex_a72, + &cpu.cortex_a73, + &cpu.cortex_a75, + &cpu.cortex_a76, + &cpu.cortex_a76ae, + &cpu.cyclone, + &cpu.exynos_m1, + &cpu.exynos_m2, + &cpu.exynos_m3, + &cpu.exynos_m4, + &cpu.exynos_m5, + &cpu.falkor, + &cpu.generic, + &cpu.kryo, + &cpu.saphira, + &cpu.thunderx, + &cpu.thunderx2t99, + &cpu.thunderxt81, + &cpu.thunderxt83, + &cpu.thunderxt88, + &cpu.tsv110, +}; diff --git a/lib/std/target/amdgpu.zig b/lib/std/target/amdgpu.zig new file mode 100644 index 0000000000..182b9fa453 --- /dev/null +++ b/lib/std/target/amdgpu.zig @@ -0,0 +1,1315 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + @"16_bit_insts", + DumpCode, + add_no_carry_insts, + aperture_regs, + atomic_fadd_insts, + auto_waitcnt_before_barrier, + ci_insts, + code_object_v3, + cumode, + dl_insts, + dot1_insts, + dot2_insts, + dot3_insts, + dot4_insts, + dot5_insts, + dot6_insts, + dpp, + dpp8, + dumpcode, + enable_ds128, + enable_prt_strict_null, + fast_fmaf, + flat_address_space, + flat_for_global, + flat_global_insts, + flat_inst_offsets, + flat_scratch_insts, + flat_segment_offset_bug, + fma_mix_insts, + fmaf, + fp_exceptions, + fp16_denormals, + fp32_denormals, + fp64, + fp64_denormals, + fp64_fp16_denormals, + gcn3_encoding, + gfx10, + gfx10_insts, + gfx7_gfx8_gfx9_insts, + gfx8_insts, + gfx9, + gfx9_insts, + half_rate_64_ops, + inst_fwd_prefetch_bug, + int_clamp_insts, + inv_2pi_inline_imm, + lds_branch_vmem_war_hazard, + lds_misaligned_bug, + ldsbankcount16, + ldsbankcount32, + load_store_opt, + localmemorysize0, + localmemorysize32768, + localmemorysize65536, + mad_mix_insts, + mai_insts, + max_private_element_size_16, + max_private_element_size_4, + max_private_element_size_8, + mimg_r128, + movrel, + no_data_dep_hazard, + no_sdst_cmpx, + no_sram_ecc_support, + no_xnack_support, + nsa_encoding, + nsa_to_vmem_bug, + offset_3f_bug, + pk_fmac_f16_inst, + promote_alloca, + r128_a16, + register_banking, + s_memrealtime, + scalar_atomics, + scalar_flat_scratch_insts, + scalar_stores, + sdwa, + sdwa_mav, + sdwa_omod, + sdwa_out_mods_vopc, + sdwa_scalar, + sdwa_sdst, + sea_islands, + sgpr_init_bug, + si_scheduler, + smem_to_vector_write_hazard, + southern_islands, + sram_ecc, + trap_handler, + trig_reduced_range, + unaligned_buffer_access, + unaligned_scratch_access, + unpacked_d16_vmem, + unsafe_ds_offset_folding, + vcmpx_exec_war_hazard, + vcmpx_permlane_hazard, + vgpr_index_mode, + vmem_to_scalar_write_hazard, + volcanic_islands, + vop3_literal, + vop3p, + vscnt, + wavefrontsize16, + wavefrontsize32, + wavefrontsize64, + xnack, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.@"16_bit_insts")] = .{ + .llvm_name = "16-bit-insts", + .description = "Has i16/f16 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.DumpCode)] = .{ + .llvm_name = "DumpCode", + .description = "Dump MachineInstrs in the CodeEmitter", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.add_no_carry_insts)] = .{ + .llvm_name = "add-no-carry-insts", + .description = "Have VALU add/sub instructions without carry out", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.aperture_regs)] = .{ + .llvm_name = "aperture-regs", + .description = "Has Memory Aperture Base and Size Registers", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.atomic_fadd_insts)] = .{ + .llvm_name = "atomic-fadd-insts", + .description = "Has buffer_atomic_add_f32, buffer_atomic_pk_add_f16, global_atomic_add_f32, global_atomic_pk_add_f16 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.auto_waitcnt_before_barrier)] = .{ + .llvm_name = "auto-waitcnt-before-barrier", + .description = "Hardware automatically inserts waitcnt before barrier", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ci_insts)] = .{ + .llvm_name = "ci-insts", + .description = "Additional instructions for CI+", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.code_object_v3)] = .{ + .llvm_name = "code-object-v3", + .description = "Generate code object version 3", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.cumode)] = .{ + .llvm_name = "cumode", + .description = "Enable CU wavefront execution mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dl_insts)] = .{ + .llvm_name = "dl-insts", + .description = "Has v_fmac_f32 and v_xnor_b32 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dot1_insts)] = .{ + .llvm_name = "dot1-insts", + .description = "Has v_dot4_i32_i8 and v_dot8_i32_i4 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dot2_insts)] = .{ + .llvm_name = "dot2-insts", + .description = "Has v_dot2_f32_f16, v_dot2_i32_i16, v_dot2_u32_u16, v_dot4_u32_u8, v_dot8_u32_u4 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dot3_insts)] = .{ + .llvm_name = "dot3-insts", + .description = "Has v_dot8c_i32_i4 instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dot4_insts)] = .{ + .llvm_name = "dot4-insts", + .description = "Has v_dot2c_i32_i16 instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dot5_insts)] = .{ + .llvm_name = "dot5-insts", + .description = "Has v_dot2c_f32_f16 instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dot6_insts)] = .{ + .llvm_name = "dot6-insts", + .description = "Has v_dot4c_i32_i8 instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dpp)] = .{ + .llvm_name = "dpp", + .description = "Support DPP (Data Parallel Primitives) extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dpp8)] = .{ + .llvm_name = "dpp8", + .description = "Support DPP8 (Data Parallel Primitives) extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dumpcode)] = .{ + .llvm_name = "dumpcode", + .description = "Dump MachineInstrs in the CodeEmitter", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.enable_ds128)] = .{ + .llvm_name = "enable-ds128", + .description = "Use ds_read|write_b128", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.enable_prt_strict_null)] = .{ + .llvm_name = "enable-prt-strict-null", + .description = "Enable zeroing of result registers for sparse texture fetches", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_fmaf)] = .{ + .llvm_name = "fast-fmaf", + .description = "Assuming f32 fma is at least as fast as mul + add", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.flat_address_space)] = .{ + .llvm_name = "flat-address-space", + .description = "Support flat address space", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.flat_for_global)] = .{ + .llvm_name = "flat-for-global", + .description = "Force to generate flat instruction for global", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.flat_global_insts)] = .{ + .llvm_name = "flat-global-insts", + .description = "Have global_* flat memory instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.flat_inst_offsets)] = .{ + .llvm_name = "flat-inst-offsets", + .description = "Flat instructions have immediate offset addressing mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.flat_scratch_insts)] = .{ + .llvm_name = "flat-scratch-insts", + .description = "Have scratch_* flat memory instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.flat_segment_offset_bug)] = .{ + .llvm_name = "flat-segment-offset-bug", + .description = "GFX10 bug, inst_offset ignored in flat segment", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fma_mix_insts)] = .{ + .llvm_name = "fma-mix-insts", + .description = "Has v_fma_mix_f32, v_fma_mixlo_f16, v_fma_mixhi_f16 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fmaf)] = .{ + .llvm_name = "fmaf", + .description = "Enable single precision FMA (not as fast as mul+add, but fused)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fp_exceptions)] = .{ + .llvm_name = "fp-exceptions", + .description = "Enable floating point exceptions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fp16_denormals)] = .{ + .llvm_name = "fp16-denormals", + .description = "Enable half precision denormal handling", + .dependencies = featureSet(&[_]Feature{ + .fp64_fp16_denormals, + }), + }; + result[@enumToInt(Feature.fp32_denormals)] = .{ + .llvm_name = "fp32-denormals", + .description = "Enable single precision denormal handling", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fp64)] = .{ + .llvm_name = "fp64", + .description = "Enable double precision operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fp64_denormals)] = .{ + .llvm_name = "fp64-denormals", + .description = "Enable double and half precision denormal handling", + .dependencies = featureSet(&[_]Feature{ + .fp64, + .fp64_fp16_denormals, + }), + }; + result[@enumToInt(Feature.fp64_fp16_denormals)] = .{ + .llvm_name = "fp64-fp16-denormals", + .description = "Enable double and half precision denormal handling", + .dependencies = featureSet(&[_]Feature{ + .fp64, + }), + }; + result[@enumToInt(Feature.gcn3_encoding)] = .{ + .llvm_name = "gcn3-encoding", + .description = "Encoding format for VI", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.gfx10)] = .{ + .llvm_name = "gfx10", + .description = "GFX10 GPU generation", + .dependencies = featureSet(&[_]Feature{ + .@"16_bit_insts", + .add_no_carry_insts, + .aperture_regs, + .ci_insts, + .dpp, + .dpp8, + .fast_fmaf, + .flat_address_space, + .flat_global_insts, + .flat_inst_offsets, + .flat_scratch_insts, + .fma_mix_insts, + .fp64, + .gfx10_insts, + .gfx8_insts, + .gfx9_insts, + .int_clamp_insts, + .inv_2pi_inline_imm, + .localmemorysize65536, + .mimg_r128, + .movrel, + .no_data_dep_hazard, + .no_sdst_cmpx, + .no_sram_ecc_support, + .pk_fmac_f16_inst, + .register_banking, + .s_memrealtime, + .sdwa, + .sdwa_omod, + .sdwa_scalar, + .sdwa_sdst, + .vop3_literal, + .vop3p, + .vscnt, + }), + }; + result[@enumToInt(Feature.gfx10_insts)] = .{ + .llvm_name = "gfx10-insts", + .description = "Additional instructions for GFX10+", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.gfx7_gfx8_gfx9_insts)] = .{ + .llvm_name = "gfx7-gfx8-gfx9-insts", + .description = "Instructions shared in GFX7, GFX8, GFX9", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.gfx8_insts)] = .{ + .llvm_name = "gfx8-insts", + .description = "Additional instructions for GFX8+", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.gfx9)] = .{ + .llvm_name = "gfx9", + .description = "GFX9 GPU generation", + .dependencies = featureSet(&[_]Feature{ + .@"16_bit_insts", + .add_no_carry_insts, + .aperture_regs, + .ci_insts, + .dpp, + .fast_fmaf, + .flat_address_space, + .flat_global_insts, + .flat_inst_offsets, + .flat_scratch_insts, + .fp64, + .gcn3_encoding, + .gfx7_gfx8_gfx9_insts, + .gfx8_insts, + .gfx9_insts, + .int_clamp_insts, + .inv_2pi_inline_imm, + .localmemorysize65536, + .r128_a16, + .s_memrealtime, + .scalar_atomics, + .scalar_flat_scratch_insts, + .scalar_stores, + .sdwa, + .sdwa_omod, + .sdwa_scalar, + .sdwa_sdst, + .vgpr_index_mode, + .vop3p, + .wavefrontsize64, + }), + }; + result[@enumToInt(Feature.gfx9_insts)] = .{ + .llvm_name = "gfx9-insts", + .description = "Additional instructions for GFX9+", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.half_rate_64_ops)] = .{ + .llvm_name = "half-rate-64-ops", + .description = "Most fp64 instructions are half rate instead of quarter", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.inst_fwd_prefetch_bug)] = .{ + .llvm_name = "inst-fwd-prefetch-bug", + .description = "S_INST_PREFETCH instruction causes shader to hang", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.int_clamp_insts)] = .{ + .llvm_name = "int-clamp-insts", + .description = "Support clamp for integer destination", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.inv_2pi_inline_imm)] = .{ + .llvm_name = "inv-2pi-inline-imm", + .description = "Has 1 / (2 * pi) as inline immediate", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lds_branch_vmem_war_hazard)] = .{ + .llvm_name = "lds-branch-vmem-war-hazard", + .description = "Switching between LDS and VMEM-tex not waiting VM_VSRC=0", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lds_misaligned_bug)] = .{ + .llvm_name = "lds-misaligned-bug", + .description = "Some GFX10 bug with misaligned multi-dword LDS access in WGP mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ldsbankcount16)] = .{ + .llvm_name = "ldsbankcount16", + .description = "The number of LDS banks per compute unit.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ldsbankcount32)] = .{ + .llvm_name = "ldsbankcount32", + .description = "The number of LDS banks per compute unit.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.load_store_opt)] = .{ + .llvm_name = "load-store-opt", + .description = "Enable SI load/store optimizer pass", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.localmemorysize0)] = .{ + .llvm_name = "localmemorysize0", + .description = "The size of local memory in bytes", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.localmemorysize32768)] = .{ + .llvm_name = "localmemorysize32768", + .description = "The size of local memory in bytes", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.localmemorysize65536)] = .{ + .llvm_name = "localmemorysize65536", + .description = "The size of local memory in bytes", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mad_mix_insts)] = .{ + .llvm_name = "mad-mix-insts", + .description = "Has v_mad_mix_f32, v_mad_mixlo_f16, v_mad_mixhi_f16 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mai_insts)] = .{ + .llvm_name = "mai-insts", + .description = "Has mAI instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.max_private_element_size_16)] = .{ + .llvm_name = "max-private-element-size-16", + .description = "Maximum private access size may be 16", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.max_private_element_size_4)] = .{ + .llvm_name = "max-private-element-size-4", + .description = "Maximum private access size may be 4", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.max_private_element_size_8)] = .{ + .llvm_name = "max-private-element-size-8", + .description = "Maximum private access size may be 8", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mimg_r128)] = .{ + .llvm_name = "mimg-r128", + .description = "Support 128-bit texture resources", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.movrel)] = .{ + .llvm_name = "movrel", + .description = "Has v_movrel*_b32 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.no_data_dep_hazard)] = .{ + .llvm_name = "no-data-dep-hazard", + .description = "Does not need SW waitstates", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.no_sdst_cmpx)] = .{ + .llvm_name = "no-sdst-cmpx", + .description = "V_CMPX does not write VCC/SGPR in addition to EXEC", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.no_sram_ecc_support)] = .{ + .llvm_name = "no-sram-ecc-support", + .description = "Hardware does not support SRAM ECC", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.no_xnack_support)] = .{ + .llvm_name = "no-xnack-support", + .description = "Hardware does not support XNACK", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.nsa_encoding)] = .{ + .llvm_name = "nsa-encoding", + .description = "Support NSA encoding for image instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.nsa_to_vmem_bug)] = .{ + .llvm_name = "nsa-to-vmem-bug", + .description = "MIMG-NSA followed by VMEM fail if EXEC_LO or EXEC_HI equals zero", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.offset_3f_bug)] = .{ + .llvm_name = "offset-3f-bug", + .description = "Branch offset of 3f hardware bug", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.pk_fmac_f16_inst)] = .{ + .llvm_name = "pk-fmac-f16-inst", + .description = "Has v_pk_fmac_f16 instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.promote_alloca)] = .{ + .llvm_name = "promote-alloca", + .description = "Enable promote alloca pass", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.r128_a16)] = .{ + .llvm_name = "r128-a16", + .description = "Support 16 bit coordindates/gradients/lod/clamp/mip types on gfx9", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.register_banking)] = .{ + .llvm_name = "register-banking", + .description = "Has register banking", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.s_memrealtime)] = .{ + .llvm_name = "s-memrealtime", + .description = "Has s_memrealtime instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.scalar_atomics)] = .{ + .llvm_name = "scalar-atomics", + .description = "Has atomic scalar memory instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.scalar_flat_scratch_insts)] = .{ + .llvm_name = "scalar-flat-scratch-insts", + .description = "Have s_scratch_* flat memory instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.scalar_stores)] = .{ + .llvm_name = "scalar-stores", + .description = "Has store scalar memory instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sdwa)] = .{ + .llvm_name = "sdwa", + .description = "Support SDWA (Sub-DWORD Addressing) extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sdwa_mav)] = .{ + .llvm_name = "sdwa-mav", + .description = "Support v_mac_f32/f16 with SDWA (Sub-DWORD Addressing) extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sdwa_omod)] = .{ + .llvm_name = "sdwa-omod", + .description = "Support OMod with SDWA (Sub-DWORD Addressing) extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sdwa_out_mods_vopc)] = .{ + .llvm_name = "sdwa-out-mods-vopc", + .description = "Support clamp for VOPC with SDWA (Sub-DWORD Addressing) extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sdwa_scalar)] = .{ + .llvm_name = "sdwa-scalar", + .description = "Support scalar register with SDWA (Sub-DWORD Addressing) extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sdwa_sdst)] = .{ + .llvm_name = "sdwa-sdst", + .description = "Support scalar dst for VOPC with SDWA (Sub-DWORD Addressing) extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sea_islands)] = .{ + .llvm_name = "sea-islands", + .description = "SEA_ISLANDS GPU generation", + .dependencies = featureSet(&[_]Feature{ + .ci_insts, + .flat_address_space, + .fp64, + .gfx7_gfx8_gfx9_insts, + .localmemorysize65536, + .mimg_r128, + .movrel, + .no_sram_ecc_support, + .trig_reduced_range, + .wavefrontsize64, + }), + }; + result[@enumToInt(Feature.sgpr_init_bug)] = .{ + .llvm_name = "sgpr-init-bug", + .description = "VI SGPR initialization bug requiring a fixed SGPR allocation size", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.si_scheduler)] = .{ + .llvm_name = "si-scheduler", + .description = "Enable SI Machine Scheduler", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.smem_to_vector_write_hazard)] = .{ + .llvm_name = "smem-to-vector-write-hazard", + .description = "s_load_dword followed by v_cmp page faults", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.southern_islands)] = .{ + .llvm_name = "southern-islands", + .description = "SOUTHERN_ISLANDS GPU generation", + .dependencies = featureSet(&[_]Feature{ + .fp64, + .ldsbankcount32, + .localmemorysize32768, + .mimg_r128, + .movrel, + .no_sram_ecc_support, + .no_xnack_support, + .trig_reduced_range, + .wavefrontsize64, + }), + }; + result[@enumToInt(Feature.sram_ecc)] = .{ + .llvm_name = "sram-ecc", + .description = "Enable SRAM ECC", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.trap_handler)] = .{ + .llvm_name = "trap-handler", + .description = "Trap handler support", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.trig_reduced_range)] = .{ + .llvm_name = "trig-reduced-range", + .description = "Requires use of fract on arguments to trig instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.unaligned_buffer_access)] = .{ + .llvm_name = "unaligned-buffer-access", + .description = "Support unaligned global loads and stores", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.unaligned_scratch_access)] = .{ + .llvm_name = "unaligned-scratch-access", + .description = "Support unaligned scratch loads and stores", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.unpacked_d16_vmem)] = .{ + .llvm_name = "unpacked-d16-vmem", + .description = "Has unpacked d16 vmem instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.unsafe_ds_offset_folding)] = .{ + .llvm_name = "unsafe-ds-offset-folding", + .description = "Force using DS instruction immediate offsets on SI", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vcmpx_exec_war_hazard)] = .{ + .llvm_name = "vcmpx-exec-war-hazard", + .description = "V_CMPX WAR hazard on EXEC (V_CMPX issue ONLY)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vcmpx_permlane_hazard)] = .{ + .llvm_name = "vcmpx-permlane-hazard", + .description = "TODO: describe me", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vgpr_index_mode)] = .{ + .llvm_name = "vgpr-index-mode", + .description = "Has VGPR mode register indexing", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vmem_to_scalar_write_hazard)] = .{ + .llvm_name = "vmem-to-scalar-write-hazard", + .description = "VMEM instruction followed by scalar writing to EXEC mask, M0 or SGPR leads to incorrect execution.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.volcanic_islands)] = .{ + .llvm_name = "volcanic-islands", + .description = "VOLCANIC_ISLANDS GPU generation", + .dependencies = featureSet(&[_]Feature{ + .@"16_bit_insts", + .ci_insts, + .dpp, + .flat_address_space, + .fp64, + .gcn3_encoding, + .gfx7_gfx8_gfx9_insts, + .gfx8_insts, + .int_clamp_insts, + .inv_2pi_inline_imm, + .localmemorysize65536, + .mimg_r128, + .movrel, + .no_sram_ecc_support, + .s_memrealtime, + .scalar_stores, + .sdwa, + .sdwa_mav, + .sdwa_out_mods_vopc, + .trig_reduced_range, + .vgpr_index_mode, + .wavefrontsize64, + }), + }; + result[@enumToInt(Feature.vop3_literal)] = .{ + .llvm_name = "vop3-literal", + .description = "Can use one literal in VOP3", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vop3p)] = .{ + .llvm_name = "vop3p", + .description = "Has VOP3P packed instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vscnt)] = .{ + .llvm_name = "vscnt", + .description = "Has separate store vscnt counter", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.wavefrontsize16)] = .{ + .llvm_name = "wavefrontsize16", + .description = "The number of threads per wavefront", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.wavefrontsize32)] = .{ + .llvm_name = "wavefrontsize32", + .description = "The number of threads per wavefront", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.wavefrontsize64)] = .{ + .llvm_name = "wavefrontsize64", + .description = "The number of threads per wavefront", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.xnack)] = .{ + .llvm_name = "xnack", + .description = "Enable XNACK support", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const bonaire = Cpu{ + .name = "bonaire", + .llvm_name = "bonaire", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .sea_islands, + }), + }; + pub const carrizo = Cpu{ + .name = "carrizo", + .llvm_name = "carrizo", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .fast_fmaf, + .half_rate_64_ops, + .ldsbankcount32, + .unpacked_d16_vmem, + .volcanic_islands, + .xnack, + }), + }; + pub const fiji = Cpu{ + .name = "fiji", + .llvm_name = "fiji", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .unpacked_d16_vmem, + .volcanic_islands, + }), + }; + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{ + .wavefrontsize64, + }), + }; + pub const generic_hsa = Cpu{ + .name = "generic_hsa", + .llvm_name = "generic-hsa", + .features = featureSet(&[_]Feature{ + .flat_address_space, + .wavefrontsize64, + }), + }; + pub const gfx1010 = Cpu{ + .name = "gfx1010", + .llvm_name = "gfx1010", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .dl_insts, + .flat_segment_offset_bug, + .gfx10, + .inst_fwd_prefetch_bug, + .lds_branch_vmem_war_hazard, + .lds_misaligned_bug, + .ldsbankcount32, + .no_xnack_support, + .nsa_encoding, + .nsa_to_vmem_bug, + .offset_3f_bug, + .scalar_atomics, + .scalar_flat_scratch_insts, + .scalar_stores, + .smem_to_vector_write_hazard, + .vcmpx_exec_war_hazard, + .vcmpx_permlane_hazard, + .vmem_to_scalar_write_hazard, + .wavefrontsize32, + }), + }; + pub const gfx1011 = Cpu{ + .name = "gfx1011", + .llvm_name = "gfx1011", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .dl_insts, + .dot1_insts, + .dot2_insts, + .dot5_insts, + .dot6_insts, + .flat_segment_offset_bug, + .gfx10, + .inst_fwd_prefetch_bug, + .lds_branch_vmem_war_hazard, + .ldsbankcount32, + .no_xnack_support, + .nsa_encoding, + .nsa_to_vmem_bug, + .offset_3f_bug, + .scalar_atomics, + .scalar_flat_scratch_insts, + .scalar_stores, + .smem_to_vector_write_hazard, + .vcmpx_exec_war_hazard, + .vcmpx_permlane_hazard, + .vmem_to_scalar_write_hazard, + .wavefrontsize32, + }), + }; + pub const gfx1012 = Cpu{ + .name = "gfx1012", + .llvm_name = "gfx1012", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .dl_insts, + .dot1_insts, + .dot2_insts, + .dot5_insts, + .dot6_insts, + .flat_segment_offset_bug, + .gfx10, + .inst_fwd_prefetch_bug, + .lds_branch_vmem_war_hazard, + .lds_misaligned_bug, + .ldsbankcount32, + .no_xnack_support, + .nsa_encoding, + .nsa_to_vmem_bug, + .offset_3f_bug, + .scalar_atomics, + .scalar_flat_scratch_insts, + .scalar_stores, + .smem_to_vector_write_hazard, + .vcmpx_exec_war_hazard, + .vcmpx_permlane_hazard, + .vmem_to_scalar_write_hazard, + .wavefrontsize32, + }), + }; + pub const gfx600 = Cpu{ + .name = "gfx600", + .llvm_name = "gfx600", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .fast_fmaf, + .half_rate_64_ops, + .ldsbankcount32, + .no_xnack_support, + .southern_islands, + }), + }; + pub const gfx601 = Cpu{ + .name = "gfx601", + .llvm_name = "gfx601", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .southern_islands, + }), + }; + pub const gfx700 = Cpu{ + .name = "gfx700", + .llvm_name = "gfx700", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .sea_islands, + }), + }; + pub const gfx701 = Cpu{ + .name = "gfx701", + .llvm_name = "gfx701", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .fast_fmaf, + .half_rate_64_ops, + .ldsbankcount32, + .no_xnack_support, + .sea_islands, + }), + }; + pub const gfx702 = Cpu{ + .name = "gfx702", + .llvm_name = "gfx702", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .fast_fmaf, + .ldsbankcount16, + .no_xnack_support, + .sea_islands, + }), + }; + pub const gfx703 = Cpu{ + .name = "gfx703", + .llvm_name = "gfx703", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount16, + .no_xnack_support, + .sea_islands, + }), + }; + pub const gfx704 = Cpu{ + .name = "gfx704", + .llvm_name = "gfx704", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .sea_islands, + }), + }; + pub const gfx801 = Cpu{ + .name = "gfx801", + .llvm_name = "gfx801", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .fast_fmaf, + .half_rate_64_ops, + .ldsbankcount32, + .unpacked_d16_vmem, + .volcanic_islands, + .xnack, + }), + }; + pub const gfx802 = Cpu{ + .name = "gfx802", + .llvm_name = "gfx802", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .sgpr_init_bug, + .unpacked_d16_vmem, + .volcanic_islands, + }), + }; + pub const gfx803 = Cpu{ + .name = "gfx803", + .llvm_name = "gfx803", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .unpacked_d16_vmem, + .volcanic_islands, + }), + }; + pub const gfx810 = Cpu{ + .name = "gfx810", + .llvm_name = "gfx810", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount16, + .volcanic_islands, + .xnack, + }), + }; + pub const gfx900 = Cpu{ + .name = "gfx900", + .llvm_name = "gfx900", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .gfx9, + .ldsbankcount32, + .mad_mix_insts, + .no_sram_ecc_support, + .no_xnack_support, + }), + }; + pub const gfx902 = Cpu{ + .name = "gfx902", + .llvm_name = "gfx902", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .gfx9, + .ldsbankcount32, + .mad_mix_insts, + .no_sram_ecc_support, + .xnack, + }), + }; + pub const gfx904 = Cpu{ + .name = "gfx904", + .llvm_name = "gfx904", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .fma_mix_insts, + .gfx9, + .ldsbankcount32, + .no_sram_ecc_support, + .no_xnack_support, + }), + }; + pub const gfx906 = Cpu{ + .name = "gfx906", + .llvm_name = "gfx906", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .dl_insts, + .dot1_insts, + .dot2_insts, + .fma_mix_insts, + .gfx9, + .half_rate_64_ops, + .ldsbankcount32, + .no_xnack_support, + }), + }; + pub const gfx908 = Cpu{ + .name = "gfx908", + .llvm_name = "gfx908", + .features = featureSet(&[_]Feature{ + .atomic_fadd_insts, + .code_object_v3, + .dl_insts, + .dot1_insts, + .dot2_insts, + .dot3_insts, + .dot4_insts, + .dot5_insts, + .dot6_insts, + .fma_mix_insts, + .gfx9, + .half_rate_64_ops, + .ldsbankcount32, + .mai_insts, + .pk_fmac_f16_inst, + .sram_ecc, + }), + }; + pub const gfx909 = Cpu{ + .name = "gfx909", + .llvm_name = "gfx909", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .gfx9, + .ldsbankcount32, + .mad_mix_insts, + .xnack, + }), + }; + pub const hainan = Cpu{ + .name = "hainan", + .llvm_name = "hainan", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .southern_islands, + }), + }; + pub const hawaii = Cpu{ + .name = "hawaii", + .llvm_name = "hawaii", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .fast_fmaf, + .half_rate_64_ops, + .ldsbankcount32, + .no_xnack_support, + .sea_islands, + }), + }; + pub const iceland = Cpu{ + .name = "iceland", + .llvm_name = "iceland", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .sgpr_init_bug, + .unpacked_d16_vmem, + .volcanic_islands, + }), + }; + pub const kabini = Cpu{ + .name = "kabini", + .llvm_name = "kabini", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount16, + .no_xnack_support, + .sea_islands, + }), + }; + pub const kaveri = Cpu{ + .name = "kaveri", + .llvm_name = "kaveri", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .sea_islands, + }), + }; + pub const mullins = Cpu{ + .name = "mullins", + .llvm_name = "mullins", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount16, + .no_xnack_support, + .sea_islands, + }), + }; + pub const oland = Cpu{ + .name = "oland", + .llvm_name = "oland", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .southern_islands, + }), + }; + pub const pitcairn = Cpu{ + .name = "pitcairn", + .llvm_name = "pitcairn", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .southern_islands, + }), + }; + pub const polaris10 = Cpu{ + .name = "polaris10", + .llvm_name = "polaris10", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .unpacked_d16_vmem, + .volcanic_islands, + }), + }; + pub const polaris11 = Cpu{ + .name = "polaris11", + .llvm_name = "polaris11", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .unpacked_d16_vmem, + .volcanic_islands, + }), + }; + pub const stoney = Cpu{ + .name = "stoney", + .llvm_name = "stoney", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount16, + .volcanic_islands, + .xnack, + }), + }; + pub const tahiti = Cpu{ + .name = "tahiti", + .llvm_name = "tahiti", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .fast_fmaf, + .half_rate_64_ops, + .ldsbankcount32, + .no_xnack_support, + .southern_islands, + }), + }; + pub const tonga = Cpu{ + .name = "tonga", + .llvm_name = "tonga", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .sgpr_init_bug, + .unpacked_d16_vmem, + .volcanic_islands, + }), + }; + pub const verde = Cpu{ + .name = "verde", + .llvm_name = "verde", + .features = featureSet(&[_]Feature{ + .code_object_v3, + .ldsbankcount32, + .no_xnack_support, + .southern_islands, + }), + }; +}; + +/// All amdgpu CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.bonaire, + &cpu.carrizo, + &cpu.fiji, + &cpu.generic, + &cpu.generic_hsa, + &cpu.gfx1010, + &cpu.gfx1011, + &cpu.gfx1012, + &cpu.gfx600, + &cpu.gfx601, + &cpu.gfx700, + &cpu.gfx701, + &cpu.gfx702, + &cpu.gfx703, + &cpu.gfx704, + &cpu.gfx801, + &cpu.gfx802, + &cpu.gfx803, + &cpu.gfx810, + &cpu.gfx900, + &cpu.gfx902, + &cpu.gfx904, + &cpu.gfx906, + &cpu.gfx908, + &cpu.gfx909, + &cpu.hainan, + &cpu.hawaii, + &cpu.iceland, + &cpu.kabini, + &cpu.kaveri, + &cpu.mullins, + &cpu.oland, + &cpu.pitcairn, + &cpu.polaris10, + &cpu.polaris11, + &cpu.stoney, + &cpu.tahiti, + &cpu.tonga, + &cpu.verde, +}; diff --git a/lib/std/target/arm.zig b/lib/std/target/arm.zig new file mode 100644 index 0000000000..62a4e1e835 --- /dev/null +++ b/lib/std/target/arm.zig @@ -0,0 +1,2333 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + @"32bit", + @"8msecext", + a12, + a15, + a17, + a32, + a35, + a5, + a53, + a55, + a57, + a7, + a72, + a73, + a75, + a76, + a8, + a9, + aclass, + acquire_release, + aes, + armv2, + armv2a, + armv3, + armv3m, + armv4, + armv4t, + armv5t, + armv5te, + armv5tej, + armv6, + armv6_m, + armv6j, + armv6k, + armv6kz, + armv6s_m, + armv6t2, + armv7_a, + armv7_m, + armv7_r, + armv7e_m, + armv7k, + armv7s, + armv7ve, + armv8_a, + armv8_m_base, + armv8_m_main, + armv8_r, + armv8_1_a, + armv8_1_m_main, + armv8_2_a, + armv8_3_a, + armv8_4_a, + armv8_5_a, + avoid_movs_shop, + avoid_partial_cpsr, + cheap_predicable_cpsr, + crc, + crypto, + d32, + db, + dfb, + disable_postra_scheduler, + dont_widen_vmovs, + dotprod, + dsp, + execute_only, + expand_fp_mlx, + exynos, + fp_armv8, + fp_armv8d16, + fp_armv8d16sp, + fp_armv8sp, + fp16, + fp16fml, + fp64, + fpao, + fpregs, + fpregs16, + fpregs64, + fullfp16, + fuse_aes, + fuse_literals, + hwdiv, + hwdiv_arm, + iwmmxt, + iwmmxt2, + krait, + kryo, + lob, + long_calls, + loop_align, + m3, + mclass, + mp, + muxed_units, + mve, + mve_fp, + nacl_trap, + neon, + neon_fpmovs, + neonfp, + no_branch_predictor, + no_movt, + no_neg_immediates, + noarm, + nonpipelined_vfp, + perfmon, + prefer_ishst, + prefer_vmovsr, + prof_unpr, + r4, + r5, + r52, + r7, + ras, + rclass, + read_tp_hard, + reserve_r9, + ret_addr_stack, + sb, + sha2, + slow_fp_brcc, + slow_load_D_subreg, + slow_odd_reg, + slow_vdup32, + slow_vgetlni32, + slowfpvmlx, + soft_float, + splat_vfp_neon, + strict_align, + swift, + thumb_mode, + thumb2, + trustzone, + use_aa, + use_misched, + v4t, + v5t, + v5te, + v6, + v6k, + v6m, + v6t2, + v7, + v7clrex, + v8, + v8_1a, + v8_1m_main, + v8_2a, + v8_3a, + v8_4a, + v8_5a, + v8m, + v8m_main, + vfp2, + vfp2d16, + vfp2d16sp, + vfp2sp, + vfp3, + vfp3d16, + vfp3d16sp, + vfp3sp, + vfp4, + vfp4d16, + vfp4d16sp, + vfp4sp, + virtualization, + vldn_align, + vmlx_forwarding, + vmlx_hazards, + wide_stride_vfp, + xscale, + zcz, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + @setEvalBranchQuota(10000); + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.@"32bit")] = .{ + .llvm_name = "32bit", + .description = "Prefer 32-bit Thumb instrs", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.@"8msecext")] = .{ + .llvm_name = "8msecext", + .description = "Enable support for ARMv8-M Security Extensions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a12)] = .{ + .llvm_name = "a12", + .description = "Cortex-A12 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a15)] = .{ + .llvm_name = "a15", + .description = "Cortex-A15 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a17)] = .{ + .llvm_name = "a17", + .description = "Cortex-A17 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a32)] = .{ + .llvm_name = "a32", + .description = "Cortex-A32 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a35)] = .{ + .llvm_name = "a35", + .description = "Cortex-A35 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a5)] = .{ + .llvm_name = "a5", + .description = "Cortex-A5 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a53)] = .{ + .llvm_name = "a53", + .description = "Cortex-A53 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a55)] = .{ + .llvm_name = "a55", + .description = "Cortex-A55 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a57)] = .{ + .llvm_name = "a57", + .description = "Cortex-A57 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a7)] = .{ + .llvm_name = "a7", + .description = "Cortex-A7 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a72)] = .{ + .llvm_name = "a72", + .description = "Cortex-A72 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a73)] = .{ + .llvm_name = "a73", + .description = "Cortex-A73 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a75)] = .{ + .llvm_name = "a75", + .description = "Cortex-A75 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a76)] = .{ + .llvm_name = "a76", + .description = "Cortex-A76 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a8)] = .{ + .llvm_name = "a8", + .description = "Cortex-A8 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a9)] = .{ + .llvm_name = "a9", + .description = "Cortex-A9 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.aclass)] = .{ + .llvm_name = "aclass", + .description = "Is application profile ('A' series)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.acquire_release)] = .{ + .llvm_name = "acquire-release", + .description = "Has v8 acquire/release (lda/ldaex etc) instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.aes)] = .{ + .llvm_name = "aes", + .description = "Enable AES support", + .dependencies = featureSet(&[_]Feature{ + .neon, + }), + }; + result[@enumToInt(Feature.armv2)] = .{ + .llvm_name = "armv2", + .description = "ARMv2 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.armv2a)] = .{ + .llvm_name = "armv2a", + .description = "ARMv2a architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.armv3)] = .{ + .llvm_name = "armv3", + .description = "ARMv3 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.armv3m)] = .{ + .llvm_name = "armv3m", + .description = "ARMv3m architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.armv4)] = .{ + .llvm_name = "armv4", + .description = "ARMv4 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.armv4t)] = .{ + .llvm_name = "armv4t", + .description = "ARMv4t architecture", + .dependencies = featureSet(&[_]Feature{ + .v4t, + }), + }; + result[@enumToInt(Feature.armv5t)] = .{ + .llvm_name = "armv5t", + .description = "ARMv5t architecture", + .dependencies = featureSet(&[_]Feature{ + .v5t, + }), + }; + result[@enumToInt(Feature.armv5te)] = .{ + .llvm_name = "armv5te", + .description = "ARMv5te architecture", + .dependencies = featureSet(&[_]Feature{ + .v5te, + }), + }; + result[@enumToInt(Feature.armv5tej)] = .{ + .llvm_name = "armv5tej", + .description = "ARMv5tej architecture", + .dependencies = featureSet(&[_]Feature{ + .v5te, + }), + }; + result[@enumToInt(Feature.armv6)] = .{ + .llvm_name = "armv6", + .description = "ARMv6 architecture", + .dependencies = featureSet(&[_]Feature{ + .dsp, + .v6, + }), + }; + result[@enumToInt(Feature.armv6_m)] = .{ + .llvm_name = "armv6-m", + .description = "ARMv6m architecture", + .dependencies = featureSet(&[_]Feature{ + .db, + .mclass, + .noarm, + .strict_align, + .thumb_mode, + .v6m, + }), + }; + result[@enumToInt(Feature.armv6j)] = .{ + .llvm_name = "armv6j", + .description = "ARMv7a architecture", + .dependencies = featureSet(&[_]Feature{ + .armv6, + }), + }; + result[@enumToInt(Feature.armv6k)] = .{ + .llvm_name = "armv6k", + .description = "ARMv6k architecture", + .dependencies = featureSet(&[_]Feature{ + .v6k, + }), + }; + result[@enumToInt(Feature.armv6kz)] = .{ + .llvm_name = "armv6kz", + .description = "ARMv6kz architecture", + .dependencies = featureSet(&[_]Feature{ + .trustzone, + .v6k, + }), + }; + result[@enumToInt(Feature.armv6s_m)] = .{ + .llvm_name = "armv6s-m", + .description = "ARMv6sm architecture", + .dependencies = featureSet(&[_]Feature{ + .db, + .mclass, + .noarm, + .strict_align, + .thumb_mode, + .v6m, + }), + }; + result[@enumToInt(Feature.armv6t2)] = .{ + .llvm_name = "armv6t2", + .description = "ARMv6t2 architecture", + .dependencies = featureSet(&[_]Feature{ + .dsp, + .v6t2, + }), + }; + result[@enumToInt(Feature.armv7_a)] = .{ + .llvm_name = "armv7-a", + .description = "ARMv7a architecture", + .dependencies = featureSet(&[_]Feature{ + .aclass, + .db, + .dsp, + .neon, + .v7, + }), + }; + result[@enumToInt(Feature.armv7_m)] = .{ + .llvm_name = "armv7-m", + .description = "ARMv7m architecture", + .dependencies = featureSet(&[_]Feature{ + .db, + .hwdiv, + .mclass, + .noarm, + .thumb_mode, + .thumb2, + .v7, + }), + }; + result[@enumToInt(Feature.armv7_r)] = .{ + .llvm_name = "armv7-r", + .description = "ARMv7r architecture", + .dependencies = featureSet(&[_]Feature{ + .db, + .dsp, + .hwdiv, + .rclass, + .v7, + }), + }; + result[@enumToInt(Feature.armv7e_m)] = .{ + .llvm_name = "armv7e-m", + .description = "ARMv7em architecture", + .dependencies = featureSet(&[_]Feature{ + .db, + .dsp, + .hwdiv, + .mclass, + .noarm, + .thumb_mode, + .thumb2, + .v7, + }), + }; + result[@enumToInt(Feature.armv7k)] = .{ + .llvm_name = "armv7k", + .description = "ARMv7a architecture", + .dependencies = featureSet(&[_]Feature{ + .armv7_a, + }), + }; + result[@enumToInt(Feature.armv7s)] = .{ + .llvm_name = "armv7s", + .description = "ARMv7a architecture", + .dependencies = featureSet(&[_]Feature{ + .armv7_a, + }), + }; + result[@enumToInt(Feature.armv7ve)] = .{ + .llvm_name = "armv7ve", + .description = "ARMv7ve architecture", + .dependencies = featureSet(&[_]Feature{ + .aclass, + .db, + .dsp, + .mp, + .neon, + .trustzone, + .v7, + .virtualization, + }), + }; + result[@enumToInt(Feature.armv8_a)] = .{ + .llvm_name = "armv8-a", + .description = "ARMv8a architecture", + .dependencies = featureSet(&[_]Feature{ + .aclass, + .crc, + .crypto, + .db, + .dsp, + .fp_armv8, + .mp, + .neon, + .trustzone, + .v8, + .virtualization, + }), + }; + result[@enumToInt(Feature.armv8_m_base)] = .{ + .llvm_name = "armv8-m.base", + .description = "ARMv8mBaseline architecture", + .dependencies = featureSet(&[_]Feature{ + .@"8msecext", + .acquire_release, + .db, + .hwdiv, + .mclass, + .noarm, + .strict_align, + .thumb_mode, + .v7clrex, + .v8m, + }), + }; + result[@enumToInt(Feature.armv8_m_main)] = .{ + .llvm_name = "armv8-m.main", + .description = "ARMv8mMainline architecture", + .dependencies = featureSet(&[_]Feature{ + .@"8msecext", + .acquire_release, + .db, + .hwdiv, + .mclass, + .noarm, + .thumb_mode, + .v8m_main, + }), + }; + result[@enumToInt(Feature.armv8_r)] = .{ + .llvm_name = "armv8-r", + .description = "ARMv8r architecture", + .dependencies = featureSet(&[_]Feature{ + .crc, + .db, + .dfb, + .dsp, + .fp_armv8, + .mp, + .neon, + .rclass, + .v8, + .virtualization, + }), + }; + result[@enumToInt(Feature.armv8_1_a)] = .{ + .llvm_name = "armv8.1-a", + .description = "ARMv81a architecture", + .dependencies = featureSet(&[_]Feature{ + .aclass, + .crc, + .crypto, + .db, + .dsp, + .fp_armv8, + .mp, + .neon, + .trustzone, + .v8_1a, + .virtualization, + }), + }; + result[@enumToInt(Feature.armv8_1_m_main)] = .{ + .llvm_name = "armv8.1-m.main", + .description = "ARMv81mMainline architecture", + .dependencies = featureSet(&[_]Feature{ + .@"8msecext", + .acquire_release, + .db, + .hwdiv, + .lob, + .mclass, + .noarm, + .ras, + .thumb_mode, + .v8_1m_main, + }), + }; + result[@enumToInt(Feature.armv8_2_a)] = .{ + .llvm_name = "armv8.2-a", + .description = "ARMv82a architecture", + .dependencies = featureSet(&[_]Feature{ + .aclass, + .crc, + .crypto, + .db, + .dsp, + .fp_armv8, + .mp, + .neon, + .ras, + .trustzone, + .v8_2a, + .virtualization, + }), + }; + result[@enumToInt(Feature.armv8_3_a)] = .{ + .llvm_name = "armv8.3-a", + .description = "ARMv83a architecture", + .dependencies = featureSet(&[_]Feature{ + .aclass, + .crc, + .crypto, + .db, + .dsp, + .fp_armv8, + .mp, + .neon, + .ras, + .trustzone, + .v8_3a, + .virtualization, + }), + }; + result[@enumToInt(Feature.armv8_4_a)] = .{ + .llvm_name = "armv8.4-a", + .description = "ARMv84a architecture", + .dependencies = featureSet(&[_]Feature{ + .aclass, + .crc, + .crypto, + .db, + .dotprod, + .dsp, + .fp_armv8, + .mp, + .neon, + .ras, + .trustzone, + .v8_4a, + .virtualization, + }), + }; + result[@enumToInt(Feature.armv8_5_a)] = .{ + .llvm_name = "armv8.5-a", + .description = "ARMv85a architecture", + .dependencies = featureSet(&[_]Feature{ + .aclass, + .crc, + .crypto, + .db, + .dotprod, + .dsp, + .fp_armv8, + .mp, + .neon, + .ras, + .trustzone, + .v8_5a, + .virtualization, + }), + }; + result[@enumToInt(Feature.avoid_movs_shop)] = .{ + .llvm_name = "avoid-movs-shop", + .description = "Avoid movs instructions with shifter operand", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.avoid_partial_cpsr)] = .{ + .llvm_name = "avoid-partial-cpsr", + .description = "Avoid CPSR partial update for OOO execution", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.cheap_predicable_cpsr)] = .{ + .llvm_name = "cheap-predicable-cpsr", + .description = "Disable +1 predication cost for instructions updating CPSR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.crc)] = .{ + .llvm_name = "crc", + .description = "Enable support for CRC instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.crypto)] = .{ + .llvm_name = "crypto", + .description = "Enable support for Cryptography extensions", + .dependencies = featureSet(&[_]Feature{ + .aes, + .neon, + .sha2, + }), + }; + result[@enumToInt(Feature.d32)] = .{ + .llvm_name = "d32", + .description = "Extend FP to 32 double registers", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.db)] = .{ + .llvm_name = "db", + .description = "Has data barrier (dmb/dsb) instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dfb)] = .{ + .llvm_name = "dfb", + .description = "Has full data barrier (dfb) instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.disable_postra_scheduler)] = .{ + .llvm_name = "disable-postra-scheduler", + .description = "Don't schedule again after register allocation", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dont_widen_vmovs)] = .{ + .llvm_name = "dont-widen-vmovs", + .description = "Don't widen VMOVS to VMOVD", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dotprod)] = .{ + .llvm_name = "dotprod", + .description = "Enable support for dot product instructions", + .dependencies = featureSet(&[_]Feature{ + .neon, + }), + }; + result[@enumToInt(Feature.dsp)] = .{ + .llvm_name = "dsp", + .description = "Supports DSP instructions in ARM and/or Thumb2", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.execute_only)] = .{ + .llvm_name = "execute-only", + .description = "Enable the generation of execute only code.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.expand_fp_mlx)] = .{ + .llvm_name = "expand-fp-mlx", + .description = "Expand VFP/NEON MLA/MLS instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.exynos)] = .{ + .llvm_name = "exynos", + .description = "Samsung Exynos processors", + .dependencies = featureSet(&[_]Feature{ + .crc, + .crypto, + .expand_fp_mlx, + .fuse_aes, + .fuse_literals, + .hwdiv, + .hwdiv_arm, + .prof_unpr, + .ret_addr_stack, + .slow_fp_brcc, + .slow_vdup32, + .slow_vgetlni32, + .slowfpvmlx, + .splat_vfp_neon, + .use_aa, + .wide_stride_vfp, + .zcz, + }), + }; + result[@enumToInt(Feature.fp_armv8)] = .{ + .llvm_name = "fp-armv8", + .description = "Enable ARMv8 FP", + .dependencies = featureSet(&[_]Feature{ + .fp_armv8d16, + .fp_armv8sp, + .vfp4, + }), + }; + result[@enumToInt(Feature.fp_armv8d16)] = .{ + .llvm_name = "fp-armv8d16", + .description = "Enable ARMv8 FP with only 16 d-registers", + .dependencies = featureSet(&[_]Feature{ + .fp_armv8d16sp, + .fp64, + .vfp4d16, + }), + }; + result[@enumToInt(Feature.fp_armv8d16sp)] = .{ + .llvm_name = "fp-armv8d16sp", + .description = "Enable ARMv8 FP with only 16 d-registers and no double precision", + .dependencies = featureSet(&[_]Feature{ + .vfp4d16sp, + }), + }; + result[@enumToInt(Feature.fp_armv8sp)] = .{ + .llvm_name = "fp-armv8sp", + .description = "Enable ARMv8 FP with no double precision", + .dependencies = featureSet(&[_]Feature{ + .d32, + .fp_armv8d16sp, + .vfp4sp, + }), + }; + result[@enumToInt(Feature.fp16)] = .{ + .llvm_name = "fp16", + .description = "Enable half-precision floating point", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fp16fml)] = .{ + .llvm_name = "fp16fml", + .description = "Enable full half-precision floating point fml instructions", + .dependencies = featureSet(&[_]Feature{ + .fullfp16, + }), + }; + result[@enumToInt(Feature.fp64)] = .{ + .llvm_name = "fp64", + .description = "Floating point unit supports double precision", + .dependencies = featureSet(&[_]Feature{ + .fpregs64, + }), + }; + result[@enumToInt(Feature.fpao)] = .{ + .llvm_name = "fpao", + .description = "Enable fast computation of positive address offsets", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fpregs)] = .{ + .llvm_name = "fpregs", + .description = "Enable FP registers", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fpregs16)] = .{ + .llvm_name = "fpregs16", + .description = "Enable 16-bit FP registers", + .dependencies = featureSet(&[_]Feature{ + .fpregs, + }), + }; + result[@enumToInt(Feature.fpregs64)] = .{ + .llvm_name = "fpregs64", + .description = "Enable 64-bit FP registers", + .dependencies = featureSet(&[_]Feature{ + .fpregs, + }), + }; + result[@enumToInt(Feature.fullfp16)] = .{ + .llvm_name = "fullfp16", + .description = "Enable full half-precision floating point", + .dependencies = featureSet(&[_]Feature{ + .fp_armv8d16sp, + .fpregs16, + }), + }; + result[@enumToInt(Feature.fuse_aes)] = .{ + .llvm_name = "fuse-aes", + .description = "CPU fuses AES crypto operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fuse_literals)] = .{ + .llvm_name = "fuse-literals", + .description = "CPU fuses literal generation operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.hwdiv)] = .{ + .llvm_name = "hwdiv", + .description = "Enable divide instructions in Thumb", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.hwdiv_arm)] = .{ + .llvm_name = "hwdiv-arm", + .description = "Enable divide instructions in ARM mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.iwmmxt)] = .{ + .llvm_name = "iwmmxt", + .description = "ARMv5te architecture", + .dependencies = featureSet(&[_]Feature{ + .armv5te, + }), + }; + result[@enumToInt(Feature.iwmmxt2)] = .{ + .llvm_name = "iwmmxt2", + .description = "ARMv5te architecture", + .dependencies = featureSet(&[_]Feature{ + .armv5te, + }), + }; + result[@enumToInt(Feature.krait)] = .{ + .llvm_name = "krait", + .description = "Qualcomm Krait processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.kryo)] = .{ + .llvm_name = "kryo", + .description = "Qualcomm Kryo processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lob)] = .{ + .llvm_name = "lob", + .description = "Enable Low Overhead Branch extensions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.long_calls)] = .{ + .llvm_name = "long-calls", + .description = "Generate calls via indirect call instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.loop_align)] = .{ + .llvm_name = "loop-align", + .description = "Prefer 32-bit alignment for loops", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.m3)] = .{ + .llvm_name = "m3", + .description = "Cortex-M3 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mclass)] = .{ + .llvm_name = "mclass", + .description = "Is microcontroller profile ('M' series)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mp)] = .{ + .llvm_name = "mp", + .description = "Supports Multiprocessing extension", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.muxed_units)] = .{ + .llvm_name = "muxed-units", + .description = "Has muxed AGU and NEON/FPU", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mve)] = .{ + .llvm_name = "mve", + .description = "Support M-Class Vector Extension with integer ops", + .dependencies = featureSet(&[_]Feature{ + .dsp, + .fpregs16, + .fpregs64, + .v8_1m_main, + }), + }; + result[@enumToInt(Feature.mve_fp)] = .{ + .llvm_name = "mve.fp", + .description = "Support M-Class Vector Extension with integer and floating ops", + .dependencies = featureSet(&[_]Feature{ + .fp_armv8d16sp, + .fullfp16, + .mve, + }), + }; + result[@enumToInt(Feature.nacl_trap)] = .{ + .llvm_name = "nacl-trap", + .description = "NaCl trap", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.neon)] = .{ + .llvm_name = "neon", + .description = "Enable NEON instructions", + .dependencies = featureSet(&[_]Feature{ + .vfp3, + }), + }; + result[@enumToInt(Feature.neon_fpmovs)] = .{ + .llvm_name = "neon-fpmovs", + .description = "Convert VMOVSR, VMOVRS, VMOVS to NEON", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.neonfp)] = .{ + .llvm_name = "neonfp", + .description = "Use NEON for single precision FP", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.no_branch_predictor)] = .{ + .llvm_name = "no-branch-predictor", + .description = "Has no branch predictor", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.no_movt)] = .{ + .llvm_name = "no-movt", + .description = "Don't use movt/movw pairs for 32-bit imms", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.no_neg_immediates)] = .{ + .llvm_name = "no-neg-immediates", + .description = "Convert immediates and instructions to their negated or complemented equivalent when the immediate does not fit in the encoding.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.noarm)] = .{ + .llvm_name = "noarm", + .description = "Does not support ARM mode execution", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.nonpipelined_vfp)] = .{ + .llvm_name = "nonpipelined-vfp", + .description = "VFP instructions are not pipelined", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.perfmon)] = .{ + .llvm_name = "perfmon", + .description = "Enable support for Performance Monitor extensions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.prefer_ishst)] = .{ + .llvm_name = "prefer-ishst", + .description = "Prefer ISHST barriers", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.prefer_vmovsr)] = .{ + .llvm_name = "prefer-vmovsr", + .description = "Prefer VMOVSR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.prof_unpr)] = .{ + .llvm_name = "prof-unpr", + .description = "Is profitable to unpredicate", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.r4)] = .{ + .llvm_name = "r4", + .description = "Cortex-R4 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.r5)] = .{ + .llvm_name = "r5", + .description = "Cortex-R5 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.r52)] = .{ + .llvm_name = "r52", + .description = "Cortex-R52 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.r7)] = .{ + .llvm_name = "r7", + .description = "Cortex-R7 ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ras)] = .{ + .llvm_name = "ras", + .description = "Enable Reliability, Availability and Serviceability extensions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.rclass)] = .{ + .llvm_name = "rclass", + .description = "Is realtime profile ('R' series)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.read_tp_hard)] = .{ + .llvm_name = "read-tp-hard", + .description = "Reading thread pointer from register", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserve_r9)] = .{ + .llvm_name = "reserve-r9", + .description = "Reserve R9, making it unavailable as GPR", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ret_addr_stack)] = .{ + .llvm_name = "ret-addr-stack", + .description = "Has return address stack", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sb)] = .{ + .llvm_name = "sb", + .description = "Enable v8.5a Speculation Barrier", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sha2)] = .{ + .llvm_name = "sha2", + .description = "Enable SHA1 and SHA256 support", + .dependencies = featureSet(&[_]Feature{ + .neon, + }), + }; + result[@enumToInt(Feature.slow_fp_brcc)] = .{ + .llvm_name = "slow-fp-brcc", + .description = "FP compare + branch is slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_load_D_subreg)] = .{ + .llvm_name = "slow-load-D-subreg", + .description = "Loading into D subregs is slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_odd_reg)] = .{ + .llvm_name = "slow-odd-reg", + .description = "VLDM/VSTM starting with an odd register is slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_vdup32)] = .{ + .llvm_name = "slow-vdup32", + .description = "Has slow VDUP32 - prefer VMOV", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_vgetlni32)] = .{ + .llvm_name = "slow-vgetlni32", + .description = "Has slow VGETLNi32 - prefer VMOV", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slowfpvmlx)] = .{ + .llvm_name = "slowfpvmlx", + .description = "Disable VFP / NEON MAC instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.soft_float)] = .{ + .llvm_name = "soft-float", + .description = "Use software floating point features.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.splat_vfp_neon)] = .{ + .llvm_name = "splat-vfp-neon", + .description = "Splat register from VFP to NEON", + .dependencies = featureSet(&[_]Feature{ + .dont_widen_vmovs, + }), + }; + result[@enumToInt(Feature.strict_align)] = .{ + .llvm_name = "strict-align", + .description = "Disallow all unaligned memory access", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.swift)] = .{ + .llvm_name = "swift", + .description = "Swift ARM processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.thumb_mode)] = .{ + .llvm_name = "thumb-mode", + .description = "Thumb mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.thumb2)] = .{ + .llvm_name = "thumb2", + .description = "Enable Thumb2 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.trustzone)] = .{ + .llvm_name = "trustzone", + .description = "Enable support for TrustZone security extensions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.use_aa)] = .{ + .llvm_name = "use-aa", + .description = "Use alias analysis during codegen", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.use_misched)] = .{ + .llvm_name = "use-misched", + .description = "Use the MachineScheduler", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v4t)] = .{ + .llvm_name = "v4t", + .description = "Support ARM v4T instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v5t)] = .{ + .llvm_name = "v5t", + .description = "Support ARM v5T instructions", + .dependencies = featureSet(&[_]Feature{ + .v4t, + }), + }; + result[@enumToInt(Feature.v5te)] = .{ + .llvm_name = "v5te", + .description = "Support ARM v5TE, v5TEj, and v5TExp instructions", + .dependencies = featureSet(&[_]Feature{ + .v5t, + }), + }; + result[@enumToInt(Feature.v6)] = .{ + .llvm_name = "v6", + .description = "Support ARM v6 instructions", + .dependencies = featureSet(&[_]Feature{ + .v5te, + }), + }; + result[@enumToInt(Feature.v6k)] = .{ + .llvm_name = "v6k", + .description = "Support ARM v6k instructions", + .dependencies = featureSet(&[_]Feature{ + .v6, + }), + }; + result[@enumToInt(Feature.v6m)] = .{ + .llvm_name = "v6m", + .description = "Support ARM v6M instructions", + .dependencies = featureSet(&[_]Feature{ + .v6, + }), + }; + result[@enumToInt(Feature.v6t2)] = .{ + .llvm_name = "v6t2", + .description = "Support ARM v6t2 instructions", + .dependencies = featureSet(&[_]Feature{ + .thumb2, + .v6k, + .v8m, + }), + }; + result[@enumToInt(Feature.v7)] = .{ + .llvm_name = "v7", + .description = "Support ARM v7 instructions", + .dependencies = featureSet(&[_]Feature{ + .perfmon, + .v6t2, + .v7clrex, + }), + }; + result[@enumToInt(Feature.v7clrex)] = .{ + .llvm_name = "v7clrex", + .description = "Has v7 clrex instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v8)] = .{ + .llvm_name = "v8", + .description = "Support ARM v8 instructions", + .dependencies = featureSet(&[_]Feature{ + .acquire_release, + .v7, + }), + }; + result[@enumToInt(Feature.v8_1a)] = .{ + .llvm_name = "v8.1a", + .description = "Support ARM v8.1a instructions", + .dependencies = featureSet(&[_]Feature{ + .v8, + }), + }; + result[@enumToInt(Feature.v8_1m_main)] = .{ + .llvm_name = "v8.1m.main", + .description = "Support ARM v8-1M Mainline instructions", + .dependencies = featureSet(&[_]Feature{ + .v8m_main, + }), + }; + result[@enumToInt(Feature.v8_2a)] = .{ + .llvm_name = "v8.2a", + .description = "Support ARM v8.2a instructions", + .dependencies = featureSet(&[_]Feature{ + .v8_1a, + }), + }; + result[@enumToInt(Feature.v8_3a)] = .{ + .llvm_name = "v8.3a", + .description = "Support ARM v8.3a instructions", + .dependencies = featureSet(&[_]Feature{ + .v8_2a, + }), + }; + result[@enumToInt(Feature.v8_4a)] = .{ + .llvm_name = "v8.4a", + .description = "Support ARM v8.4a instructions", + .dependencies = featureSet(&[_]Feature{ + .dotprod, + .v8_3a, + }), + }; + result[@enumToInt(Feature.v8_5a)] = .{ + .llvm_name = "v8.5a", + .description = "Support ARM v8.5a instructions", + .dependencies = featureSet(&[_]Feature{ + .sb, + .v8_4a, + }), + }; + result[@enumToInt(Feature.v8m)] = .{ + .llvm_name = "v8m", + .description = "Support ARM v8M Baseline instructions", + .dependencies = featureSet(&[_]Feature{ + .v6m, + }), + }; + result[@enumToInt(Feature.v8m_main)] = .{ + .llvm_name = "v8m.main", + .description = "Support ARM v8M Mainline instructions", + .dependencies = featureSet(&[_]Feature{ + .v7, + }), + }; + result[@enumToInt(Feature.vfp2)] = .{ + .llvm_name = "vfp2", + .description = "Enable VFP2 instructions", + .dependencies = featureSet(&[_]Feature{ + .vfp2d16, + .vfp2sp, + }), + }; + result[@enumToInt(Feature.vfp2d16)] = .{ + .llvm_name = "vfp2d16", + .description = "Enable VFP2 instructions", + .dependencies = featureSet(&[_]Feature{ + .fp64, + .vfp2d16sp, + }), + }; + result[@enumToInt(Feature.vfp2d16sp)] = .{ + .llvm_name = "vfp2d16sp", + .description = "Enable VFP2 instructions with no double precision", + .dependencies = featureSet(&[_]Feature{ + .fpregs, + }), + }; + result[@enumToInt(Feature.vfp2sp)] = .{ + .llvm_name = "vfp2sp", + .description = "Enable VFP2 instructions with no double precision", + .dependencies = featureSet(&[_]Feature{ + .vfp2d16sp, + }), + }; + result[@enumToInt(Feature.vfp3)] = .{ + .llvm_name = "vfp3", + .description = "Enable VFP3 instructions", + .dependencies = featureSet(&[_]Feature{ + .vfp3d16, + .vfp3sp, + }), + }; + result[@enumToInt(Feature.vfp3d16)] = .{ + .llvm_name = "vfp3d16", + .description = "Enable VFP3 instructions with only 16 d-registers", + .dependencies = featureSet(&[_]Feature{ + .fp64, + .vfp2, + .vfp3d16sp, + }), + }; + result[@enumToInt(Feature.vfp3d16sp)] = .{ + .llvm_name = "vfp3d16sp", + .description = "Enable VFP3 instructions with only 16 d-registers and no double precision", + .dependencies = featureSet(&[_]Feature{ + .vfp2sp, + }), + }; + result[@enumToInt(Feature.vfp3sp)] = .{ + .llvm_name = "vfp3sp", + .description = "Enable VFP3 instructions with no double precision", + .dependencies = featureSet(&[_]Feature{ + .d32, + .vfp3d16sp, + }), + }; + result[@enumToInt(Feature.vfp4)] = .{ + .llvm_name = "vfp4", + .description = "Enable VFP4 instructions", + .dependencies = featureSet(&[_]Feature{ + .fp16, + .vfp3, + .vfp4d16, + .vfp4sp, + }), + }; + result[@enumToInt(Feature.vfp4d16)] = .{ + .llvm_name = "vfp4d16", + .description = "Enable VFP4 instructions with only 16 d-registers", + .dependencies = featureSet(&[_]Feature{ + .fp16, + .fp64, + .vfp3d16, + .vfp4d16sp, + }), + }; + result[@enumToInt(Feature.vfp4d16sp)] = .{ + .llvm_name = "vfp4d16sp", + .description = "Enable VFP4 instructions with only 16 d-registers and no double precision", + .dependencies = featureSet(&[_]Feature{ + .fp16, + .vfp3d16sp, + }), + }; + result[@enumToInt(Feature.vfp4sp)] = .{ + .llvm_name = "vfp4sp", + .description = "Enable VFP4 instructions with no double precision", + .dependencies = featureSet(&[_]Feature{ + .d32, + .fp16, + .vfp3sp, + .vfp4d16sp, + }), + }; + result[@enumToInt(Feature.virtualization)] = .{ + .llvm_name = "virtualization", + .description = "Supports Virtualization extension", + .dependencies = featureSet(&[_]Feature{ + .hwdiv, + .hwdiv_arm, + }), + }; + result[@enumToInt(Feature.vldn_align)] = .{ + .llvm_name = "vldn-align", + .description = "Check for VLDn unaligned access", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vmlx_forwarding)] = .{ + .llvm_name = "vmlx-forwarding", + .description = "Has multiplier accumulator forwarding", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vmlx_hazards)] = .{ + .llvm_name = "vmlx-hazards", + .description = "Has VMLx hazards", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.wide_stride_vfp)] = .{ + .llvm_name = "wide-stride-vfp", + .description = "Use a wide stride when allocating VFP registers", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.xscale)] = .{ + .llvm_name = "xscale", + .description = "ARMv5te architecture", + .dependencies = featureSet(&[_]Feature{ + .armv5te, + }), + }; + result[@enumToInt(Feature.zcz)] = .{ + .llvm_name = "zcz", + .description = "Has zero-cycle zeroing instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const arm1020e = Cpu{ + .name = "arm1020e", + .llvm_name = "arm1020e", + .features = featureSet(&[_]Feature{ + .armv5te, + }), + }; + pub const arm1020t = Cpu{ + .name = "arm1020t", + .llvm_name = "arm1020t", + .features = featureSet(&[_]Feature{ + .armv5t, + }), + }; + pub const arm1022e = Cpu{ + .name = "arm1022e", + .llvm_name = "arm1022e", + .features = featureSet(&[_]Feature{ + .armv5te, + }), + }; + pub const arm10e = Cpu{ + .name = "arm10e", + .llvm_name = "arm10e", + .features = featureSet(&[_]Feature{ + .armv5te, + }), + }; + pub const arm10tdmi = Cpu{ + .name = "arm10tdmi", + .llvm_name = "arm10tdmi", + .features = featureSet(&[_]Feature{ + .armv5t, + }), + }; + pub const arm1136j_s = Cpu{ + .name = "arm1136j_s", + .llvm_name = "arm1136j-s", + .features = featureSet(&[_]Feature{ + .armv6, + }), + }; + pub const arm1136jf_s = Cpu{ + .name = "arm1136jf_s", + .llvm_name = "arm1136jf-s", + .features = featureSet(&[_]Feature{ + .armv6, + .slowfpvmlx, + .vfp2, + }), + }; + pub const arm1156t2_s = Cpu{ + .name = "arm1156t2_s", + .llvm_name = "arm1156t2-s", + .features = featureSet(&[_]Feature{ + .armv6t2, + }), + }; + pub const arm1156t2f_s = Cpu{ + .name = "arm1156t2f_s", + .llvm_name = "arm1156t2f-s", + .features = featureSet(&[_]Feature{ + .armv6t2, + .slowfpvmlx, + .vfp2, + }), + }; + pub const arm1176j_s = Cpu{ + .name = "arm1176j_s", + .llvm_name = "arm1176j-s", + .features = featureSet(&[_]Feature{ + .armv6kz, + }), + }; + pub const arm1176jz_s = Cpu{ + .name = "arm1176jz_s", + .llvm_name = "arm1176jz-s", + .features = featureSet(&[_]Feature{ + .armv6kz, + }), + }; + pub const arm1176jzf_s = Cpu{ + .name = "arm1176jzf_s", + .llvm_name = "arm1176jzf-s", + .features = featureSet(&[_]Feature{ + .armv6kz, + .slowfpvmlx, + .vfp2, + }), + }; + pub const arm710t = Cpu{ + .name = "arm710t", + .llvm_name = "arm710t", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const arm720t = Cpu{ + .name = "arm720t", + .llvm_name = "arm720t", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const arm7tdmi = Cpu{ + .name = "arm7tdmi", + .llvm_name = "arm7tdmi", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const arm7tdmi_s = Cpu{ + .name = "arm7tdmi_s", + .llvm_name = "arm7tdmi-s", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const arm8 = Cpu{ + .name = "arm8", + .llvm_name = "arm8", + .features = featureSet(&[_]Feature{ + .armv4, + }), + }; + pub const arm810 = Cpu{ + .name = "arm810", + .llvm_name = "arm810", + .features = featureSet(&[_]Feature{ + .armv4, + }), + }; + pub const arm9 = Cpu{ + .name = "arm9", + .llvm_name = "arm9", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const arm920 = Cpu{ + .name = "arm920", + .llvm_name = "arm920", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const arm920t = Cpu{ + .name = "arm920t", + .llvm_name = "arm920t", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const arm922t = Cpu{ + .name = "arm922t", + .llvm_name = "arm922t", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const arm926ej_s = Cpu{ + .name = "arm926ej_s", + .llvm_name = "arm926ej-s", + .features = featureSet(&[_]Feature{ + .armv5te, + }), + }; + pub const arm940t = Cpu{ + .name = "arm940t", + .llvm_name = "arm940t", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const arm946e_s = Cpu{ + .name = "arm946e_s", + .llvm_name = "arm946e-s", + .features = featureSet(&[_]Feature{ + .armv5te, + }), + }; + pub const arm966e_s = Cpu{ + .name = "arm966e_s", + .llvm_name = "arm966e-s", + .features = featureSet(&[_]Feature{ + .armv5te, + }), + }; + pub const arm968e_s = Cpu{ + .name = "arm968e_s", + .llvm_name = "arm968e-s", + .features = featureSet(&[_]Feature{ + .armv5te, + }), + }; + pub const arm9e = Cpu{ + .name = "arm9e", + .llvm_name = "arm9e", + .features = featureSet(&[_]Feature{ + .armv5te, + }), + }; + pub const arm9tdmi = Cpu{ + .name = "arm9tdmi", + .llvm_name = "arm9tdmi", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const cortex_a12 = Cpu{ + .name = "cortex_a12", + .llvm_name = "cortex-a12", + .features = featureSet(&[_]Feature{ + .a12, + .armv7_a, + .avoid_partial_cpsr, + .mp, + .ret_addr_stack, + .trustzone, + .vfp4, + .virtualization, + .vmlx_forwarding, + }), + }; + pub const cortex_a15 = Cpu{ + .name = "cortex_a15", + .llvm_name = "cortex-a15", + .features = featureSet(&[_]Feature{ + .a15, + .armv7_a, + .avoid_partial_cpsr, + .dont_widen_vmovs, + .mp, + .muxed_units, + .ret_addr_stack, + .splat_vfp_neon, + .trustzone, + .vfp4, + .virtualization, + .vldn_align, + }), + }; + pub const cortex_a17 = Cpu{ + .name = "cortex_a17", + .llvm_name = "cortex-a17", + .features = featureSet(&[_]Feature{ + .a17, + .armv7_a, + .avoid_partial_cpsr, + .mp, + .ret_addr_stack, + .trustzone, + .vfp4, + .virtualization, + .vmlx_forwarding, + }), + }; + pub const cortex_a32 = Cpu{ + .name = "cortex_a32", + .llvm_name = "cortex-a32", + .features = featureSet(&[_]Feature{ + .armv8_a, + .crc, + .crypto, + .hwdiv, + .hwdiv_arm, + }), + }; + pub const cortex_a35 = Cpu{ + .name = "cortex_a35", + .llvm_name = "cortex-a35", + .features = featureSet(&[_]Feature{ + .a35, + .armv8_a, + .crc, + .crypto, + .hwdiv, + .hwdiv_arm, + }), + }; + pub const cortex_a5 = Cpu{ + .name = "cortex_a5", + .llvm_name = "cortex-a5", + .features = featureSet(&[_]Feature{ + .a5, + .armv7_a, + .mp, + .ret_addr_stack, + .slow_fp_brcc, + .slowfpvmlx, + .trustzone, + .vfp4, + .vmlx_forwarding, + }), + }; + pub const cortex_a53 = Cpu{ + .name = "cortex_a53", + .llvm_name = "cortex-a53", + .features = featureSet(&[_]Feature{ + .a53, + .armv8_a, + .crc, + .crypto, + .fpao, + .hwdiv, + .hwdiv_arm, + }), + }; + pub const cortex_a55 = Cpu{ + .name = "cortex_a55", + .llvm_name = "cortex-a55", + .features = featureSet(&[_]Feature{ + .a55, + .armv8_2_a, + .dotprod, + .hwdiv, + .hwdiv_arm, + }), + }; + pub const cortex_a57 = Cpu{ + .name = "cortex_a57", + .llvm_name = "cortex-a57", + .features = featureSet(&[_]Feature{ + .a57, + .armv8_a, + .avoid_partial_cpsr, + .cheap_predicable_cpsr, + .crc, + .crypto, + .fpao, + .hwdiv, + .hwdiv_arm, + }), + }; + pub const cortex_a7 = Cpu{ + .name = "cortex_a7", + .llvm_name = "cortex-a7", + .features = featureSet(&[_]Feature{ + .a7, + .armv7_a, + .mp, + .ret_addr_stack, + .slow_fp_brcc, + .slowfpvmlx, + .trustzone, + .vfp4, + .virtualization, + .vmlx_forwarding, + .vmlx_hazards, + }), + }; + pub const cortex_a72 = Cpu{ + .name = "cortex_a72", + .llvm_name = "cortex-a72", + .features = featureSet(&[_]Feature{ + .a72, + .armv8_a, + .crc, + .crypto, + .hwdiv, + .hwdiv_arm, + }), + }; + pub const cortex_a73 = Cpu{ + .name = "cortex_a73", + .llvm_name = "cortex-a73", + .features = featureSet(&[_]Feature{ + .a73, + .armv8_a, + .crc, + .crypto, + .hwdiv, + .hwdiv_arm, + }), + }; + pub const cortex_a75 = Cpu{ + .name = "cortex_a75", + .llvm_name = "cortex-a75", + .features = featureSet(&[_]Feature{ + .a75, + .armv8_2_a, + .dotprod, + .hwdiv, + .hwdiv_arm, + }), + }; + pub const cortex_a76 = Cpu{ + .name = "cortex_a76", + .llvm_name = "cortex-a76", + .features = featureSet(&[_]Feature{ + .a76, + .armv8_2_a, + .crc, + .crypto, + .dotprod, + .fullfp16, + .hwdiv, + .hwdiv_arm, + }), + }; + pub const cortex_a76ae = Cpu{ + .name = "cortex_a76ae", + .llvm_name = "cortex-a76ae", + .features = featureSet(&[_]Feature{ + .a76, + .armv8_2_a, + .crc, + .crypto, + .dotprod, + .fullfp16, + .hwdiv, + .hwdiv_arm, + }), + }; + pub const cortex_a8 = Cpu{ + .name = "cortex_a8", + .llvm_name = "cortex-a8", + .features = featureSet(&[_]Feature{ + .a8, + .armv7_a, + .nonpipelined_vfp, + .ret_addr_stack, + .slow_fp_brcc, + .slowfpvmlx, + .trustzone, + .vmlx_forwarding, + .vmlx_hazards, + }), + }; + pub const cortex_a9 = Cpu{ + .name = "cortex_a9", + .llvm_name = "cortex-a9", + .features = featureSet(&[_]Feature{ + .a9, + .armv7_a, + .avoid_partial_cpsr, + .expand_fp_mlx, + .fp16, + .mp, + .muxed_units, + .neon_fpmovs, + .prefer_vmovsr, + .ret_addr_stack, + .trustzone, + .vldn_align, + .vmlx_forwarding, + .vmlx_hazards, + }), + }; + pub const cortex_m0 = Cpu{ + .name = "cortex_m0", + .llvm_name = "cortex-m0", + .features = featureSet(&[_]Feature{ + .armv6_m, + }), + }; + pub const cortex_m0plus = Cpu{ + .name = "cortex_m0plus", + .llvm_name = "cortex-m0plus", + .features = featureSet(&[_]Feature{ + .armv6_m, + }), + }; + pub const cortex_m1 = Cpu{ + .name = "cortex_m1", + .llvm_name = "cortex-m1", + .features = featureSet(&[_]Feature{ + .armv6_m, + }), + }; + pub const cortex_m23 = Cpu{ + .name = "cortex_m23", + .llvm_name = "cortex-m23", + .features = featureSet(&[_]Feature{ + .armv8_m_base, + .no_movt, + }), + }; + pub const cortex_m3 = Cpu{ + .name = "cortex_m3", + .llvm_name = "cortex-m3", + .features = featureSet(&[_]Feature{ + .armv7_m, + .loop_align, + .m3, + .no_branch_predictor, + .use_aa, + .use_misched, + }), + }; + pub const cortex_m33 = Cpu{ + .name = "cortex_m33", + .llvm_name = "cortex-m33", + .features = featureSet(&[_]Feature{ + .armv8_m_main, + .dsp, + .fp_armv8d16sp, + .loop_align, + .no_branch_predictor, + .slowfpvmlx, + .use_aa, + .use_misched, + }), + }; + pub const cortex_m35p = Cpu{ + .name = "cortex_m35p", + .llvm_name = "cortex-m35p", + .features = featureSet(&[_]Feature{ + .armv8_m_main, + .dsp, + .fp_armv8d16sp, + .loop_align, + .no_branch_predictor, + .slowfpvmlx, + .use_aa, + .use_misched, + }), + }; + pub const cortex_m4 = Cpu{ + .name = "cortex_m4", + .llvm_name = "cortex-m4", + .features = featureSet(&[_]Feature{ + .armv7e_m, + .loop_align, + .no_branch_predictor, + .slowfpvmlx, + .use_aa, + .use_misched, + .vfp4d16sp, + }), + }; + pub const cortex_m7 = Cpu{ + .name = "cortex_m7", + .llvm_name = "cortex-m7", + .features = featureSet(&[_]Feature{ + .armv7e_m, + .fp_armv8d16, + }), + }; + pub const cortex_r4 = Cpu{ + .name = "cortex_r4", + .llvm_name = "cortex-r4", + .features = featureSet(&[_]Feature{ + .armv7_r, + .avoid_partial_cpsr, + .r4, + .ret_addr_stack, + }), + }; + pub const cortex_r4f = Cpu{ + .name = "cortex_r4f", + .llvm_name = "cortex-r4f", + .features = featureSet(&[_]Feature{ + .armv7_r, + .avoid_partial_cpsr, + .r4, + .ret_addr_stack, + .slow_fp_brcc, + .slowfpvmlx, + .vfp3d16, + }), + }; + pub const cortex_r5 = Cpu{ + .name = "cortex_r5", + .llvm_name = "cortex-r5", + .features = featureSet(&[_]Feature{ + .armv7_r, + .avoid_partial_cpsr, + .hwdiv_arm, + .r5, + .ret_addr_stack, + .slow_fp_brcc, + .slowfpvmlx, + .vfp3d16, + }), + }; + pub const cortex_r52 = Cpu{ + .name = "cortex_r52", + .llvm_name = "cortex-r52", + .features = featureSet(&[_]Feature{ + .armv8_r, + .fpao, + .r52, + .use_aa, + .use_misched, + }), + }; + pub const cortex_r7 = Cpu{ + .name = "cortex_r7", + .llvm_name = "cortex-r7", + .features = featureSet(&[_]Feature{ + .armv7_r, + .avoid_partial_cpsr, + .fp16, + .hwdiv_arm, + .mp, + .r7, + .ret_addr_stack, + .slow_fp_brcc, + .slowfpvmlx, + .vfp3d16, + }), + }; + pub const cortex_r8 = Cpu{ + .name = "cortex_r8", + .llvm_name = "cortex-r8", + .features = featureSet(&[_]Feature{ + .armv7_r, + .avoid_partial_cpsr, + .fp16, + .hwdiv_arm, + .mp, + .ret_addr_stack, + .slow_fp_brcc, + .slowfpvmlx, + .vfp3d16, + }), + }; + pub const cyclone = Cpu{ + .name = "cyclone", + .llvm_name = "cyclone", + .features = featureSet(&[_]Feature{ + .armv8_a, + .avoid_movs_shop, + .avoid_partial_cpsr, + .crypto, + .disable_postra_scheduler, + .hwdiv, + .hwdiv_arm, + .mp, + .neonfp, + .ret_addr_stack, + .slowfpvmlx, + .swift, + .use_misched, + .vfp4, + .zcz, + }), + }; + pub const ep9312 = Cpu{ + .name = "ep9312", + .llvm_name = "ep9312", + .features = featureSet(&[_]Feature{ + .armv4t, + }), + }; + pub const exynos_m1 = Cpu{ + .name = "exynos_m1", + .llvm_name = "exynos-m1", + .features = featureSet(&[_]Feature{ + .armv8_a, + .exynos, + }), + }; + pub const exynos_m2 = Cpu{ + .name = "exynos_m2", + .llvm_name = "exynos-m2", + .features = featureSet(&[_]Feature{ + .armv8_a, + .exynos, + }), + }; + pub const exynos_m3 = Cpu{ + .name = "exynos_m3", + .llvm_name = "exynos-m3", + .features = featureSet(&[_]Feature{ + .armv8_a, + .exynos, + }), + }; + pub const exynos_m4 = Cpu{ + .name = "exynos_m4", + .llvm_name = "exynos-m4", + .features = featureSet(&[_]Feature{ + .armv8_2_a, + .dotprod, + .exynos, + .fullfp16, + }), + }; + pub const exynos_m5 = Cpu{ + .name = "exynos_m5", + .llvm_name = "exynos-m5", + .features = featureSet(&[_]Feature{ + .armv8_2_a, + .dotprod, + .exynos, + .fullfp16, + }), + }; + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{}), + }; + pub const iwmmxt = Cpu{ + .name = "iwmmxt", + .llvm_name = "iwmmxt", + .features = featureSet(&[_]Feature{ + .armv5te, + }), + }; + pub const krait = Cpu{ + .name = "krait", + .llvm_name = "krait", + .features = featureSet(&[_]Feature{ + .armv7_a, + .avoid_partial_cpsr, + .fp16, + .hwdiv, + .hwdiv_arm, + .krait, + .muxed_units, + .ret_addr_stack, + .vfp4, + .vldn_align, + .vmlx_forwarding, + }), + }; + pub const kryo = Cpu{ + .name = "kryo", + .llvm_name = "kryo", + .features = featureSet(&[_]Feature{ + .armv8_a, + .crc, + .crypto, + .hwdiv, + .hwdiv_arm, + .kryo, + }), + }; + pub const mpcore = Cpu{ + .name = "mpcore", + .llvm_name = "mpcore", + .features = featureSet(&[_]Feature{ + .armv6k, + .slowfpvmlx, + .vfp2, + }), + }; + pub const mpcorenovfp = Cpu{ + .name = "mpcorenovfp", + .llvm_name = "mpcorenovfp", + .features = featureSet(&[_]Feature{ + .armv6k, + }), + }; + pub const sc000 = Cpu{ + .name = "sc000", + .llvm_name = "sc000", + .features = featureSet(&[_]Feature{ + .armv6_m, + }), + }; + pub const sc300 = Cpu{ + .name = "sc300", + .llvm_name = "sc300", + .features = featureSet(&[_]Feature{ + .armv7_m, + .m3, + .no_branch_predictor, + .use_aa, + .use_misched, + }), + }; + pub const strongarm = Cpu{ + .name = "strongarm", + .llvm_name = "strongarm", + .features = featureSet(&[_]Feature{ + .armv4, + }), + }; + pub const strongarm110 = Cpu{ + .name = "strongarm110", + .llvm_name = "strongarm110", + .features = featureSet(&[_]Feature{ + .armv4, + }), + }; + pub const strongarm1100 = Cpu{ + .name = "strongarm1100", + .llvm_name = "strongarm1100", + .features = featureSet(&[_]Feature{ + .armv4, + }), + }; + pub const strongarm1110 = Cpu{ + .name = "strongarm1110", + .llvm_name = "strongarm1110", + .features = featureSet(&[_]Feature{ + .armv4, + }), + }; + pub const swift = Cpu{ + .name = "swift", + .llvm_name = "swift", + .features = featureSet(&[_]Feature{ + .armv7_a, + .avoid_movs_shop, + .avoid_partial_cpsr, + .disable_postra_scheduler, + .hwdiv, + .hwdiv_arm, + .mp, + .neonfp, + .prefer_ishst, + .prof_unpr, + .ret_addr_stack, + .slow_load_D_subreg, + .slow_odd_reg, + .slow_vdup32, + .slow_vgetlni32, + .slowfpvmlx, + .swift, + .use_misched, + .vfp4, + .vmlx_hazards, + .wide_stride_vfp, + }), + }; + pub const xscale = Cpu{ + .name = "xscale", + .llvm_name = "xscale", + .features = featureSet(&[_]Feature{ + .armv5te, + }), + }; +}; + +/// All arm CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.arm1020e, + &cpu.arm1020t, + &cpu.arm1022e, + &cpu.arm10e, + &cpu.arm10tdmi, + &cpu.arm1136j_s, + &cpu.arm1136jf_s, + &cpu.arm1156t2_s, + &cpu.arm1156t2f_s, + &cpu.arm1176j_s, + &cpu.arm1176jz_s, + &cpu.arm1176jzf_s, + &cpu.arm710t, + &cpu.arm720t, + &cpu.arm7tdmi, + &cpu.arm7tdmi_s, + &cpu.arm8, + &cpu.arm810, + &cpu.arm9, + &cpu.arm920, + &cpu.arm920t, + &cpu.arm922t, + &cpu.arm926ej_s, + &cpu.arm940t, + &cpu.arm946e_s, + &cpu.arm966e_s, + &cpu.arm968e_s, + &cpu.arm9e, + &cpu.arm9tdmi, + &cpu.cortex_a12, + &cpu.cortex_a15, + &cpu.cortex_a17, + &cpu.cortex_a32, + &cpu.cortex_a35, + &cpu.cortex_a5, + &cpu.cortex_a53, + &cpu.cortex_a55, + &cpu.cortex_a57, + &cpu.cortex_a7, + &cpu.cortex_a72, + &cpu.cortex_a73, + &cpu.cortex_a75, + &cpu.cortex_a76, + &cpu.cortex_a76ae, + &cpu.cortex_a8, + &cpu.cortex_a9, + &cpu.cortex_m0, + &cpu.cortex_m0plus, + &cpu.cortex_m1, + &cpu.cortex_m23, + &cpu.cortex_m3, + &cpu.cortex_m33, + &cpu.cortex_m35p, + &cpu.cortex_m4, + &cpu.cortex_m7, + &cpu.cortex_r4, + &cpu.cortex_r4f, + &cpu.cortex_r5, + &cpu.cortex_r52, + &cpu.cortex_r7, + &cpu.cortex_r8, + &cpu.cyclone, + &cpu.ep9312, + &cpu.exynos_m1, + &cpu.exynos_m2, + &cpu.exynos_m3, + &cpu.exynos_m4, + &cpu.exynos_m5, + &cpu.generic, + &cpu.iwmmxt, + &cpu.krait, + &cpu.kryo, + &cpu.mpcore, + &cpu.mpcorenovfp, + &cpu.sc000, + &cpu.sc300, + &cpu.strongarm, + &cpu.strongarm110, + &cpu.strongarm1100, + &cpu.strongarm1110, + &cpu.swift, + &cpu.xscale, +}; diff --git a/lib/std/target/avr.zig b/lib/std/target/avr.zig new file mode 100644 index 0000000000..3902a3860f --- /dev/null +++ b/lib/std/target/avr.zig @@ -0,0 +1,2380 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + addsubiw, + avr0, + avr1, + avr2, + avr25, + avr3, + avr31, + avr35, + avr4, + avr5, + avr51, + avr6, + avrtiny, + @"break", + des, + eijmpcall, + elpm, + elpmx, + ijmpcall, + jmpcall, + lpm, + lpmx, + movw, + mul, + rmw, + smallstack, + special, + spm, + spmx, + sram, + tinyencoding, + xmega, + xmegau, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.addsubiw)] = .{ + .llvm_name = "addsubiw", + .description = "Enable 16-bit register-immediate addition and subtraction instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.avr0)] = .{ + .llvm_name = "avr0", + .description = "The device is a part of the avr0 family", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.avr1)] = .{ + .llvm_name = "avr1", + .description = "The device is a part of the avr1 family", + .dependencies = featureSet(&[_]Feature{ + .avr0, + .lpm, + }), + }; + result[@enumToInt(Feature.avr2)] = .{ + .llvm_name = "avr2", + .description = "The device is a part of the avr2 family", + .dependencies = featureSet(&[_]Feature{ + .addsubiw, + .avr1, + .ijmpcall, + .sram, + }), + }; + result[@enumToInt(Feature.avr25)] = .{ + .llvm_name = "avr25", + .description = "The device is a part of the avr25 family", + .dependencies = featureSet(&[_]Feature{ + .avr2, + .@"break", + .lpmx, + .movw, + .spm, + }), + }; + result[@enumToInt(Feature.avr3)] = .{ + .llvm_name = "avr3", + .description = "The device is a part of the avr3 family", + .dependencies = featureSet(&[_]Feature{ + .avr2, + .jmpcall, + }), + }; + result[@enumToInt(Feature.avr31)] = .{ + .llvm_name = "avr31", + .description = "The device is a part of the avr31 family", + .dependencies = featureSet(&[_]Feature{ + .avr3, + .elpm, + }), + }; + result[@enumToInt(Feature.avr35)] = .{ + .llvm_name = "avr35", + .description = "The device is a part of the avr35 family", + .dependencies = featureSet(&[_]Feature{ + .avr3, + .@"break", + .lpmx, + .movw, + .spm, + }), + }; + result[@enumToInt(Feature.avr4)] = .{ + .llvm_name = "avr4", + .description = "The device is a part of the avr4 family", + .dependencies = featureSet(&[_]Feature{ + .avr2, + .@"break", + .lpmx, + .movw, + .mul, + .spm, + }), + }; + result[@enumToInt(Feature.avr5)] = .{ + .llvm_name = "avr5", + .description = "The device is a part of the avr5 family", + .dependencies = featureSet(&[_]Feature{ + .avr3, + .@"break", + .lpmx, + .movw, + .mul, + .spm, + }), + }; + result[@enumToInt(Feature.avr51)] = .{ + .llvm_name = "avr51", + .description = "The device is a part of the avr51 family", + .dependencies = featureSet(&[_]Feature{ + .avr5, + .elpm, + .elpmx, + }), + }; + result[@enumToInt(Feature.avr6)] = .{ + .llvm_name = "avr6", + .description = "The device is a part of the avr6 family", + .dependencies = featureSet(&[_]Feature{ + .avr51, + }), + }; + result[@enumToInt(Feature.avrtiny)] = .{ + .llvm_name = "avrtiny", + .description = "The device is a part of the avrtiny family", + .dependencies = featureSet(&[_]Feature{ + .avr0, + .@"break", + .sram, + .tinyencoding, + }), + }; + result[@enumToInt(Feature.@"break")] = .{ + .llvm_name = "break", + .description = "The device supports the `BREAK` debugging instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.des)] = .{ + .llvm_name = "des", + .description = "The device supports the `DES k` encryption instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.eijmpcall)] = .{ + .llvm_name = "eijmpcall", + .description = "The device supports the `EIJMP`/`EICALL` instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.elpm)] = .{ + .llvm_name = "elpm", + .description = "The device supports the ELPM instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.elpmx)] = .{ + .llvm_name = "elpmx", + .description = "The device supports the `ELPM Rd, Z[+]` instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ijmpcall)] = .{ + .llvm_name = "ijmpcall", + .description = "The device supports `IJMP`/`ICALL`instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.jmpcall)] = .{ + .llvm_name = "jmpcall", + .description = "The device supports the `JMP` and `CALL` instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lpm)] = .{ + .llvm_name = "lpm", + .description = "The device supports the `LPM` instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lpmx)] = .{ + .llvm_name = "lpmx", + .description = "The device supports the `LPM Rd, Z[+]` instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.movw)] = .{ + .llvm_name = "movw", + .description = "The device supports the 16-bit MOVW instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mul)] = .{ + .llvm_name = "mul", + .description = "The device supports the multiplication instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.rmw)] = .{ + .llvm_name = "rmw", + .description = "The device supports the read-write-modify instructions: XCH, LAS, LAC, LAT", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.smallstack)] = .{ + .llvm_name = "smallstack", + .description = "The device has an 8-bit stack pointer", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.special)] = .{ + .llvm_name = "special", + .description = "Enable use of the entire instruction set - used for debugging", + .dependencies = featureSet(&[_]Feature{ + .addsubiw, + .@"break", + .des, + .eijmpcall, + .elpm, + .elpmx, + .ijmpcall, + .jmpcall, + .lpm, + .lpmx, + .movw, + .mul, + .rmw, + .spm, + .spmx, + .sram, + }), + }; + result[@enumToInt(Feature.spm)] = .{ + .llvm_name = "spm", + .description = "The device supports the `SPM` instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.spmx)] = .{ + .llvm_name = "spmx", + .description = "The device supports the `SPM Z+` instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sram)] = .{ + .llvm_name = "sram", + .description = "The device has random access memory", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.tinyencoding)] = .{ + .llvm_name = "tinyencoding", + .description = "The device has Tiny core specific instruction encodings", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.xmega)] = .{ + .llvm_name = "xmega", + .description = "The device is a part of the xmega family", + .dependencies = featureSet(&[_]Feature{ + .avr51, + .des, + .eijmpcall, + .spmx, + }), + }; + result[@enumToInt(Feature.xmegau)] = .{ + .llvm_name = "xmegau", + .description = "The device is a part of the xmegau family", + .dependencies = featureSet(&[_]Feature{ + .rmw, + .xmega, + }), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const at43usb320 = Cpu{ + .name = "at43usb320", + .llvm_name = "at43usb320", + .features = featureSet(&[_]Feature{ + .avr31, + }), + }; + pub const at43usb355 = Cpu{ + .name = "at43usb355", + .llvm_name = "at43usb355", + .features = featureSet(&[_]Feature{ + .avr3, + }), + }; + pub const at76c711 = Cpu{ + .name = "at76c711", + .llvm_name = "at76c711", + .features = featureSet(&[_]Feature{ + .avr3, + }), + }; + pub const at86rf401 = Cpu{ + .name = "at86rf401", + .llvm_name = "at86rf401", + .features = featureSet(&[_]Feature{ + .avr2, + .lpmx, + .movw, + }), + }; + pub const at90c8534 = Cpu{ + .name = "at90c8534", + .llvm_name = "at90c8534", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const at90can128 = Cpu{ + .name = "at90can128", + .llvm_name = "at90can128", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const at90can32 = Cpu{ + .name = "at90can32", + .llvm_name = "at90can32", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const at90can64 = Cpu{ + .name = "at90can64", + .llvm_name = "at90can64", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const at90pwm1 = Cpu{ + .name = "at90pwm1", + .llvm_name = "at90pwm1", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const at90pwm161 = Cpu{ + .name = "at90pwm161", + .llvm_name = "at90pwm161", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const at90pwm2 = Cpu{ + .name = "at90pwm2", + .llvm_name = "at90pwm2", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const at90pwm216 = Cpu{ + .name = "at90pwm216", + .llvm_name = "at90pwm216", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const at90pwm2b = Cpu{ + .name = "at90pwm2b", + .llvm_name = "at90pwm2b", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const at90pwm3 = Cpu{ + .name = "at90pwm3", + .llvm_name = "at90pwm3", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const at90pwm316 = Cpu{ + .name = "at90pwm316", + .llvm_name = "at90pwm316", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const at90pwm3b = Cpu{ + .name = "at90pwm3b", + .llvm_name = "at90pwm3b", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const at90pwm81 = Cpu{ + .name = "at90pwm81", + .llvm_name = "at90pwm81", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const at90s1200 = Cpu{ + .name = "at90s1200", + .llvm_name = "at90s1200", + .features = featureSet(&[_]Feature{ + .avr0, + }), + }; + pub const at90s2313 = Cpu{ + .name = "at90s2313", + .llvm_name = "at90s2313", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const at90s2323 = Cpu{ + .name = "at90s2323", + .llvm_name = "at90s2323", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const at90s2333 = Cpu{ + .name = "at90s2333", + .llvm_name = "at90s2333", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const at90s2343 = Cpu{ + .name = "at90s2343", + .llvm_name = "at90s2343", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const at90s4414 = Cpu{ + .name = "at90s4414", + .llvm_name = "at90s4414", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const at90s4433 = Cpu{ + .name = "at90s4433", + .llvm_name = "at90s4433", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const at90s4434 = Cpu{ + .name = "at90s4434", + .llvm_name = "at90s4434", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const at90s8515 = Cpu{ + .name = "at90s8515", + .llvm_name = "at90s8515", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const at90s8535 = Cpu{ + .name = "at90s8535", + .llvm_name = "at90s8535", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const at90scr100 = Cpu{ + .name = "at90scr100", + .llvm_name = "at90scr100", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const at90usb1286 = Cpu{ + .name = "at90usb1286", + .llvm_name = "at90usb1286", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const at90usb1287 = Cpu{ + .name = "at90usb1287", + .llvm_name = "at90usb1287", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const at90usb162 = Cpu{ + .name = "at90usb162", + .llvm_name = "at90usb162", + .features = featureSet(&[_]Feature{ + .avr35, + }), + }; + pub const at90usb646 = Cpu{ + .name = "at90usb646", + .llvm_name = "at90usb646", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const at90usb647 = Cpu{ + .name = "at90usb647", + .llvm_name = "at90usb647", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const at90usb82 = Cpu{ + .name = "at90usb82", + .llvm_name = "at90usb82", + .features = featureSet(&[_]Feature{ + .avr35, + }), + }; + pub const at94k = Cpu{ + .name = "at94k", + .llvm_name = "at94k", + .features = featureSet(&[_]Feature{ + .avr3, + .lpmx, + .movw, + .mul, + }), + }; + pub const ata5272 = Cpu{ + .name = "ata5272", + .llvm_name = "ata5272", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const ata5505 = Cpu{ + .name = "ata5505", + .llvm_name = "ata5505", + .features = featureSet(&[_]Feature{ + .avr35, + }), + }; + pub const ata5790 = Cpu{ + .name = "ata5790", + .llvm_name = "ata5790", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const ata5795 = Cpu{ + .name = "ata5795", + .llvm_name = "ata5795", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const ata6285 = Cpu{ + .name = "ata6285", + .llvm_name = "ata6285", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const ata6286 = Cpu{ + .name = "ata6286", + .llvm_name = "ata6286", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const ata6289 = Cpu{ + .name = "ata6289", + .llvm_name = "ata6289", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega103 = Cpu{ + .name = "atmega103", + .llvm_name = "atmega103", + .features = featureSet(&[_]Feature{ + .avr31, + }), + }; + pub const atmega128 = Cpu{ + .name = "atmega128", + .llvm_name = "atmega128", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const atmega1280 = Cpu{ + .name = "atmega1280", + .llvm_name = "atmega1280", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const atmega1281 = Cpu{ + .name = "atmega1281", + .llvm_name = "atmega1281", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const atmega1284 = Cpu{ + .name = "atmega1284", + .llvm_name = "atmega1284", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const atmega1284p = Cpu{ + .name = "atmega1284p", + .llvm_name = "atmega1284p", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const atmega1284rfr2 = Cpu{ + .name = "atmega1284rfr2", + .llvm_name = "atmega1284rfr2", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const atmega128a = Cpu{ + .name = "atmega128a", + .llvm_name = "atmega128a", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const atmega128rfa1 = Cpu{ + .name = "atmega128rfa1", + .llvm_name = "atmega128rfa1", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const atmega128rfr2 = Cpu{ + .name = "atmega128rfr2", + .llvm_name = "atmega128rfr2", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const atmega16 = Cpu{ + .name = "atmega16", + .llvm_name = "atmega16", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega161 = Cpu{ + .name = "atmega161", + .llvm_name = "atmega161", + .features = featureSet(&[_]Feature{ + .avr3, + .lpmx, + .movw, + .mul, + .spm, + }), + }; + pub const atmega162 = Cpu{ + .name = "atmega162", + .llvm_name = "atmega162", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega163 = Cpu{ + .name = "atmega163", + .llvm_name = "atmega163", + .features = featureSet(&[_]Feature{ + .avr3, + .lpmx, + .movw, + .mul, + .spm, + }), + }; + pub const atmega164a = Cpu{ + .name = "atmega164a", + .llvm_name = "atmega164a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega164p = Cpu{ + .name = "atmega164p", + .llvm_name = "atmega164p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega164pa = Cpu{ + .name = "atmega164pa", + .llvm_name = "atmega164pa", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega165 = Cpu{ + .name = "atmega165", + .llvm_name = "atmega165", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega165a = Cpu{ + .name = "atmega165a", + .llvm_name = "atmega165a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega165p = Cpu{ + .name = "atmega165p", + .llvm_name = "atmega165p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega165pa = Cpu{ + .name = "atmega165pa", + .llvm_name = "atmega165pa", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega168 = Cpu{ + .name = "atmega168", + .llvm_name = "atmega168", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega168a = Cpu{ + .name = "atmega168a", + .llvm_name = "atmega168a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega168p = Cpu{ + .name = "atmega168p", + .llvm_name = "atmega168p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega168pa = Cpu{ + .name = "atmega168pa", + .llvm_name = "atmega168pa", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega169 = Cpu{ + .name = "atmega169", + .llvm_name = "atmega169", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega169a = Cpu{ + .name = "atmega169a", + .llvm_name = "atmega169a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega169p = Cpu{ + .name = "atmega169p", + .llvm_name = "atmega169p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega169pa = Cpu{ + .name = "atmega169pa", + .llvm_name = "atmega169pa", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega16a = Cpu{ + .name = "atmega16a", + .llvm_name = "atmega16a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega16hva = Cpu{ + .name = "atmega16hva", + .llvm_name = "atmega16hva", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega16hva2 = Cpu{ + .name = "atmega16hva2", + .llvm_name = "atmega16hva2", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega16hvb = Cpu{ + .name = "atmega16hvb", + .llvm_name = "atmega16hvb", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega16hvbrevb = Cpu{ + .name = "atmega16hvbrevb", + .llvm_name = "atmega16hvbrevb", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega16m1 = Cpu{ + .name = "atmega16m1", + .llvm_name = "atmega16m1", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega16u2 = Cpu{ + .name = "atmega16u2", + .llvm_name = "atmega16u2", + .features = featureSet(&[_]Feature{ + .avr35, + }), + }; + pub const atmega16u4 = Cpu{ + .name = "atmega16u4", + .llvm_name = "atmega16u4", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega2560 = Cpu{ + .name = "atmega2560", + .llvm_name = "atmega2560", + .features = featureSet(&[_]Feature{ + .avr6, + }), + }; + pub const atmega2561 = Cpu{ + .name = "atmega2561", + .llvm_name = "atmega2561", + .features = featureSet(&[_]Feature{ + .avr6, + }), + }; + pub const atmega2564rfr2 = Cpu{ + .name = "atmega2564rfr2", + .llvm_name = "atmega2564rfr2", + .features = featureSet(&[_]Feature{ + .avr6, + }), + }; + pub const atmega256rfr2 = Cpu{ + .name = "atmega256rfr2", + .llvm_name = "atmega256rfr2", + .features = featureSet(&[_]Feature{ + .avr6, + }), + }; + pub const atmega32 = Cpu{ + .name = "atmega32", + .llvm_name = "atmega32", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega323 = Cpu{ + .name = "atmega323", + .llvm_name = "atmega323", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega324a = Cpu{ + .name = "atmega324a", + .llvm_name = "atmega324a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega324p = Cpu{ + .name = "atmega324p", + .llvm_name = "atmega324p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega324pa = Cpu{ + .name = "atmega324pa", + .llvm_name = "atmega324pa", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega325 = Cpu{ + .name = "atmega325", + .llvm_name = "atmega325", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega3250 = Cpu{ + .name = "atmega3250", + .llvm_name = "atmega3250", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega3250a = Cpu{ + .name = "atmega3250a", + .llvm_name = "atmega3250a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega3250p = Cpu{ + .name = "atmega3250p", + .llvm_name = "atmega3250p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega3250pa = Cpu{ + .name = "atmega3250pa", + .llvm_name = "atmega3250pa", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega325a = Cpu{ + .name = "atmega325a", + .llvm_name = "atmega325a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega325p = Cpu{ + .name = "atmega325p", + .llvm_name = "atmega325p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega325pa = Cpu{ + .name = "atmega325pa", + .llvm_name = "atmega325pa", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega328 = Cpu{ + .name = "atmega328", + .llvm_name = "atmega328", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega328p = Cpu{ + .name = "atmega328p", + .llvm_name = "atmega328p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega329 = Cpu{ + .name = "atmega329", + .llvm_name = "atmega329", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega3290 = Cpu{ + .name = "atmega3290", + .llvm_name = "atmega3290", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega3290a = Cpu{ + .name = "atmega3290a", + .llvm_name = "atmega3290a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega3290p = Cpu{ + .name = "atmega3290p", + .llvm_name = "atmega3290p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega3290pa = Cpu{ + .name = "atmega3290pa", + .llvm_name = "atmega3290pa", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega329a = Cpu{ + .name = "atmega329a", + .llvm_name = "atmega329a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega329p = Cpu{ + .name = "atmega329p", + .llvm_name = "atmega329p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega329pa = Cpu{ + .name = "atmega329pa", + .llvm_name = "atmega329pa", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega32a = Cpu{ + .name = "atmega32a", + .llvm_name = "atmega32a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega32c1 = Cpu{ + .name = "atmega32c1", + .llvm_name = "atmega32c1", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega32hvb = Cpu{ + .name = "atmega32hvb", + .llvm_name = "atmega32hvb", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega32hvbrevb = Cpu{ + .name = "atmega32hvbrevb", + .llvm_name = "atmega32hvbrevb", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega32m1 = Cpu{ + .name = "atmega32m1", + .llvm_name = "atmega32m1", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega32u2 = Cpu{ + .name = "atmega32u2", + .llvm_name = "atmega32u2", + .features = featureSet(&[_]Feature{ + .avr35, + }), + }; + pub const atmega32u4 = Cpu{ + .name = "atmega32u4", + .llvm_name = "atmega32u4", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega32u6 = Cpu{ + .name = "atmega32u6", + .llvm_name = "atmega32u6", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega406 = Cpu{ + .name = "atmega406", + .llvm_name = "atmega406", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega48 = Cpu{ + .name = "atmega48", + .llvm_name = "atmega48", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega48a = Cpu{ + .name = "atmega48a", + .llvm_name = "atmega48a", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega48p = Cpu{ + .name = "atmega48p", + .llvm_name = "atmega48p", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega48pa = Cpu{ + .name = "atmega48pa", + .llvm_name = "atmega48pa", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega64 = Cpu{ + .name = "atmega64", + .llvm_name = "atmega64", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega640 = Cpu{ + .name = "atmega640", + .llvm_name = "atmega640", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega644 = Cpu{ + .name = "atmega644", + .llvm_name = "atmega644", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega644a = Cpu{ + .name = "atmega644a", + .llvm_name = "atmega644a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega644p = Cpu{ + .name = "atmega644p", + .llvm_name = "atmega644p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega644pa = Cpu{ + .name = "atmega644pa", + .llvm_name = "atmega644pa", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega644rfr2 = Cpu{ + .name = "atmega644rfr2", + .llvm_name = "atmega644rfr2", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega645 = Cpu{ + .name = "atmega645", + .llvm_name = "atmega645", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega6450 = Cpu{ + .name = "atmega6450", + .llvm_name = "atmega6450", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega6450a = Cpu{ + .name = "atmega6450a", + .llvm_name = "atmega6450a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega6450p = Cpu{ + .name = "atmega6450p", + .llvm_name = "atmega6450p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega645a = Cpu{ + .name = "atmega645a", + .llvm_name = "atmega645a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega645p = Cpu{ + .name = "atmega645p", + .llvm_name = "atmega645p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega649 = Cpu{ + .name = "atmega649", + .llvm_name = "atmega649", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega6490 = Cpu{ + .name = "atmega6490", + .llvm_name = "atmega6490", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega6490a = Cpu{ + .name = "atmega6490a", + .llvm_name = "atmega6490a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega6490p = Cpu{ + .name = "atmega6490p", + .llvm_name = "atmega6490p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega649a = Cpu{ + .name = "atmega649a", + .llvm_name = "atmega649a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega649p = Cpu{ + .name = "atmega649p", + .llvm_name = "atmega649p", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega64a = Cpu{ + .name = "atmega64a", + .llvm_name = "atmega64a", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega64c1 = Cpu{ + .name = "atmega64c1", + .llvm_name = "atmega64c1", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega64hve = Cpu{ + .name = "atmega64hve", + .llvm_name = "atmega64hve", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega64m1 = Cpu{ + .name = "atmega64m1", + .llvm_name = "atmega64m1", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega64rfr2 = Cpu{ + .name = "atmega64rfr2", + .llvm_name = "atmega64rfr2", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const atmega8 = Cpu{ + .name = "atmega8", + .llvm_name = "atmega8", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega8515 = Cpu{ + .name = "atmega8515", + .llvm_name = "atmega8515", + .features = featureSet(&[_]Feature{ + .avr2, + .lpmx, + .movw, + .mul, + .spm, + }), + }; + pub const atmega8535 = Cpu{ + .name = "atmega8535", + .llvm_name = "atmega8535", + .features = featureSet(&[_]Feature{ + .avr2, + .lpmx, + .movw, + .mul, + .spm, + }), + }; + pub const atmega88 = Cpu{ + .name = "atmega88", + .llvm_name = "atmega88", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega88a = Cpu{ + .name = "atmega88a", + .llvm_name = "atmega88a", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega88p = Cpu{ + .name = "atmega88p", + .llvm_name = "atmega88p", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega88pa = Cpu{ + .name = "atmega88pa", + .llvm_name = "atmega88pa", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega8a = Cpu{ + .name = "atmega8a", + .llvm_name = "atmega8a", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega8hva = Cpu{ + .name = "atmega8hva", + .llvm_name = "atmega8hva", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const atmega8u2 = Cpu{ + .name = "atmega8u2", + .llvm_name = "atmega8u2", + .features = featureSet(&[_]Feature{ + .avr35, + }), + }; + pub const attiny10 = Cpu{ + .name = "attiny10", + .llvm_name = "attiny10", + .features = featureSet(&[_]Feature{ + .avrtiny, + }), + }; + pub const attiny102 = Cpu{ + .name = "attiny102", + .llvm_name = "attiny102", + .features = featureSet(&[_]Feature{ + .avrtiny, + }), + }; + pub const attiny104 = Cpu{ + .name = "attiny104", + .llvm_name = "attiny104", + .features = featureSet(&[_]Feature{ + .avrtiny, + }), + }; + pub const attiny11 = Cpu{ + .name = "attiny11", + .llvm_name = "attiny11", + .features = featureSet(&[_]Feature{ + .avr1, + }), + }; + pub const attiny12 = Cpu{ + .name = "attiny12", + .llvm_name = "attiny12", + .features = featureSet(&[_]Feature{ + .avr1, + }), + }; + pub const attiny13 = Cpu{ + .name = "attiny13", + .llvm_name = "attiny13", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny13a = Cpu{ + .name = "attiny13a", + .llvm_name = "attiny13a", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny15 = Cpu{ + .name = "attiny15", + .llvm_name = "attiny15", + .features = featureSet(&[_]Feature{ + .avr1, + }), + }; + pub const attiny1634 = Cpu{ + .name = "attiny1634", + .llvm_name = "attiny1634", + .features = featureSet(&[_]Feature{ + .avr35, + }), + }; + pub const attiny167 = Cpu{ + .name = "attiny167", + .llvm_name = "attiny167", + .features = featureSet(&[_]Feature{ + .avr35, + }), + }; + pub const attiny20 = Cpu{ + .name = "attiny20", + .llvm_name = "attiny20", + .features = featureSet(&[_]Feature{ + .avrtiny, + }), + }; + pub const attiny22 = Cpu{ + .name = "attiny22", + .llvm_name = "attiny22", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const attiny2313 = Cpu{ + .name = "attiny2313", + .llvm_name = "attiny2313", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny2313a = Cpu{ + .name = "attiny2313a", + .llvm_name = "attiny2313a", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny24 = Cpu{ + .name = "attiny24", + .llvm_name = "attiny24", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny24a = Cpu{ + .name = "attiny24a", + .llvm_name = "attiny24a", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny25 = Cpu{ + .name = "attiny25", + .llvm_name = "attiny25", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny26 = Cpu{ + .name = "attiny26", + .llvm_name = "attiny26", + .features = featureSet(&[_]Feature{ + .avr2, + .lpmx, + }), + }; + pub const attiny261 = Cpu{ + .name = "attiny261", + .llvm_name = "attiny261", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny261a = Cpu{ + .name = "attiny261a", + .llvm_name = "attiny261a", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny28 = Cpu{ + .name = "attiny28", + .llvm_name = "attiny28", + .features = featureSet(&[_]Feature{ + .avr1, + }), + }; + pub const attiny4 = Cpu{ + .name = "attiny4", + .llvm_name = "attiny4", + .features = featureSet(&[_]Feature{ + .avrtiny, + }), + }; + pub const attiny40 = Cpu{ + .name = "attiny40", + .llvm_name = "attiny40", + .features = featureSet(&[_]Feature{ + .avrtiny, + }), + }; + pub const attiny4313 = Cpu{ + .name = "attiny4313", + .llvm_name = "attiny4313", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny43u = Cpu{ + .name = "attiny43u", + .llvm_name = "attiny43u", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny44 = Cpu{ + .name = "attiny44", + .llvm_name = "attiny44", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny44a = Cpu{ + .name = "attiny44a", + .llvm_name = "attiny44a", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny45 = Cpu{ + .name = "attiny45", + .llvm_name = "attiny45", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny461 = Cpu{ + .name = "attiny461", + .llvm_name = "attiny461", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny461a = Cpu{ + .name = "attiny461a", + .llvm_name = "attiny461a", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny48 = Cpu{ + .name = "attiny48", + .llvm_name = "attiny48", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny5 = Cpu{ + .name = "attiny5", + .llvm_name = "attiny5", + .features = featureSet(&[_]Feature{ + .avrtiny, + }), + }; + pub const attiny828 = Cpu{ + .name = "attiny828", + .llvm_name = "attiny828", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny84 = Cpu{ + .name = "attiny84", + .llvm_name = "attiny84", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny84a = Cpu{ + .name = "attiny84a", + .llvm_name = "attiny84a", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny85 = Cpu{ + .name = "attiny85", + .llvm_name = "attiny85", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny861 = Cpu{ + .name = "attiny861", + .llvm_name = "attiny861", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny861a = Cpu{ + .name = "attiny861a", + .llvm_name = "attiny861a", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny87 = Cpu{ + .name = "attiny87", + .llvm_name = "attiny87", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny88 = Cpu{ + .name = "attiny88", + .llvm_name = "attiny88", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const attiny9 = Cpu{ + .name = "attiny9", + .llvm_name = "attiny9", + .features = featureSet(&[_]Feature{ + .avrtiny, + }), + }; + pub const atxmega128a1 = Cpu{ + .name = "atxmega128a1", + .llvm_name = "atxmega128a1", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega128a1u = Cpu{ + .name = "atxmega128a1u", + .llvm_name = "atxmega128a1u", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega128a3 = Cpu{ + .name = "atxmega128a3", + .llvm_name = "atxmega128a3", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega128a3u = Cpu{ + .name = "atxmega128a3u", + .llvm_name = "atxmega128a3u", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega128a4u = Cpu{ + .name = "atxmega128a4u", + .llvm_name = "atxmega128a4u", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega128b1 = Cpu{ + .name = "atxmega128b1", + .llvm_name = "atxmega128b1", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega128b3 = Cpu{ + .name = "atxmega128b3", + .llvm_name = "atxmega128b3", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega128c3 = Cpu{ + .name = "atxmega128c3", + .llvm_name = "atxmega128c3", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega128d3 = Cpu{ + .name = "atxmega128d3", + .llvm_name = "atxmega128d3", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega128d4 = Cpu{ + .name = "atxmega128d4", + .llvm_name = "atxmega128d4", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega16a4 = Cpu{ + .name = "atxmega16a4", + .llvm_name = "atxmega16a4", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega16a4u = Cpu{ + .name = "atxmega16a4u", + .llvm_name = "atxmega16a4u", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega16c4 = Cpu{ + .name = "atxmega16c4", + .llvm_name = "atxmega16c4", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega16d4 = Cpu{ + .name = "atxmega16d4", + .llvm_name = "atxmega16d4", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega16e5 = Cpu{ + .name = "atxmega16e5", + .llvm_name = "atxmega16e5", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega192a3 = Cpu{ + .name = "atxmega192a3", + .llvm_name = "atxmega192a3", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega192a3u = Cpu{ + .name = "atxmega192a3u", + .llvm_name = "atxmega192a3u", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega192c3 = Cpu{ + .name = "atxmega192c3", + .llvm_name = "atxmega192c3", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega192d3 = Cpu{ + .name = "atxmega192d3", + .llvm_name = "atxmega192d3", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega256a3 = Cpu{ + .name = "atxmega256a3", + .llvm_name = "atxmega256a3", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega256a3b = Cpu{ + .name = "atxmega256a3b", + .llvm_name = "atxmega256a3b", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega256a3bu = Cpu{ + .name = "atxmega256a3bu", + .llvm_name = "atxmega256a3bu", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega256a3u = Cpu{ + .name = "atxmega256a3u", + .llvm_name = "atxmega256a3u", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega256c3 = Cpu{ + .name = "atxmega256c3", + .llvm_name = "atxmega256c3", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega256d3 = Cpu{ + .name = "atxmega256d3", + .llvm_name = "atxmega256d3", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega32a4 = Cpu{ + .name = "atxmega32a4", + .llvm_name = "atxmega32a4", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega32a4u = Cpu{ + .name = "atxmega32a4u", + .llvm_name = "atxmega32a4u", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega32c4 = Cpu{ + .name = "atxmega32c4", + .llvm_name = "atxmega32c4", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega32d4 = Cpu{ + .name = "atxmega32d4", + .llvm_name = "atxmega32d4", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega32e5 = Cpu{ + .name = "atxmega32e5", + .llvm_name = "atxmega32e5", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega32x1 = Cpu{ + .name = "atxmega32x1", + .llvm_name = "atxmega32x1", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega384c3 = Cpu{ + .name = "atxmega384c3", + .llvm_name = "atxmega384c3", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega384d3 = Cpu{ + .name = "atxmega384d3", + .llvm_name = "atxmega384d3", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega64a1 = Cpu{ + .name = "atxmega64a1", + .llvm_name = "atxmega64a1", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega64a1u = Cpu{ + .name = "atxmega64a1u", + .llvm_name = "atxmega64a1u", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega64a3 = Cpu{ + .name = "atxmega64a3", + .llvm_name = "atxmega64a3", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega64a3u = Cpu{ + .name = "atxmega64a3u", + .llvm_name = "atxmega64a3u", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega64a4u = Cpu{ + .name = "atxmega64a4u", + .llvm_name = "atxmega64a4u", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega64b1 = Cpu{ + .name = "atxmega64b1", + .llvm_name = "atxmega64b1", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega64b3 = Cpu{ + .name = "atxmega64b3", + .llvm_name = "atxmega64b3", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega64c3 = Cpu{ + .name = "atxmega64c3", + .llvm_name = "atxmega64c3", + .features = featureSet(&[_]Feature{ + .xmegau, + }), + }; + pub const atxmega64d3 = Cpu{ + .name = "atxmega64d3", + .llvm_name = "atxmega64d3", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega64d4 = Cpu{ + .name = "atxmega64d4", + .llvm_name = "atxmega64d4", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const atxmega8e5 = Cpu{ + .name = "atxmega8e5", + .llvm_name = "atxmega8e5", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const avr1 = Cpu{ + .name = "avr1", + .llvm_name = "avr1", + .features = featureSet(&[_]Feature{ + .avr1, + }), + }; + pub const avr2 = Cpu{ + .name = "avr2", + .llvm_name = "avr2", + .features = featureSet(&[_]Feature{ + .avr2, + }), + }; + pub const avr25 = Cpu{ + .name = "avr25", + .llvm_name = "avr25", + .features = featureSet(&[_]Feature{ + .avr25, + }), + }; + pub const avr3 = Cpu{ + .name = "avr3", + .llvm_name = "avr3", + .features = featureSet(&[_]Feature{ + .avr3, + }), + }; + pub const avr31 = Cpu{ + .name = "avr31", + .llvm_name = "avr31", + .features = featureSet(&[_]Feature{ + .avr31, + }), + }; + pub const avr35 = Cpu{ + .name = "avr35", + .llvm_name = "avr35", + .features = featureSet(&[_]Feature{ + .avr35, + }), + }; + pub const avr4 = Cpu{ + .name = "avr4", + .llvm_name = "avr4", + .features = featureSet(&[_]Feature{ + .avr4, + }), + }; + pub const avr5 = Cpu{ + .name = "avr5", + .llvm_name = "avr5", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; + pub const avr51 = Cpu{ + .name = "avr51", + .llvm_name = "avr51", + .features = featureSet(&[_]Feature{ + .avr51, + }), + }; + pub const avr6 = Cpu{ + .name = "avr6", + .llvm_name = "avr6", + .features = featureSet(&[_]Feature{ + .avr6, + }), + }; + pub const avrtiny = Cpu{ + .name = "avrtiny", + .llvm_name = "avrtiny", + .features = featureSet(&[_]Feature{ + .avrtiny, + }), + }; + pub const avrxmega1 = Cpu{ + .name = "avrxmega1", + .llvm_name = "avrxmega1", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const avrxmega2 = Cpu{ + .name = "avrxmega2", + .llvm_name = "avrxmega2", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const avrxmega3 = Cpu{ + .name = "avrxmega3", + .llvm_name = "avrxmega3", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const avrxmega4 = Cpu{ + .name = "avrxmega4", + .llvm_name = "avrxmega4", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const avrxmega5 = Cpu{ + .name = "avrxmega5", + .llvm_name = "avrxmega5", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const avrxmega6 = Cpu{ + .name = "avrxmega6", + .llvm_name = "avrxmega6", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const avrxmega7 = Cpu{ + .name = "avrxmega7", + .llvm_name = "avrxmega7", + .features = featureSet(&[_]Feature{ + .xmega, + }), + }; + pub const m3000 = Cpu{ + .name = "m3000", + .llvm_name = "m3000", + .features = featureSet(&[_]Feature{ + .avr5, + }), + }; +}; + +/// All avr CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.at43usb320, + &cpu.at43usb355, + &cpu.at76c711, + &cpu.at86rf401, + &cpu.at90c8534, + &cpu.at90can128, + &cpu.at90can32, + &cpu.at90can64, + &cpu.at90pwm1, + &cpu.at90pwm161, + &cpu.at90pwm2, + &cpu.at90pwm216, + &cpu.at90pwm2b, + &cpu.at90pwm3, + &cpu.at90pwm316, + &cpu.at90pwm3b, + &cpu.at90pwm81, + &cpu.at90s1200, + &cpu.at90s2313, + &cpu.at90s2323, + &cpu.at90s2333, + &cpu.at90s2343, + &cpu.at90s4414, + &cpu.at90s4433, + &cpu.at90s4434, + &cpu.at90s8515, + &cpu.at90s8535, + &cpu.at90scr100, + &cpu.at90usb1286, + &cpu.at90usb1287, + &cpu.at90usb162, + &cpu.at90usb646, + &cpu.at90usb647, + &cpu.at90usb82, + &cpu.at94k, + &cpu.ata5272, + &cpu.ata5505, + &cpu.ata5790, + &cpu.ata5795, + &cpu.ata6285, + &cpu.ata6286, + &cpu.ata6289, + &cpu.atmega103, + &cpu.atmega128, + &cpu.atmega1280, + &cpu.atmega1281, + &cpu.atmega1284, + &cpu.atmega1284p, + &cpu.atmega1284rfr2, + &cpu.atmega128a, + &cpu.atmega128rfa1, + &cpu.atmega128rfr2, + &cpu.atmega16, + &cpu.atmega161, + &cpu.atmega162, + &cpu.atmega163, + &cpu.atmega164a, + &cpu.atmega164p, + &cpu.atmega164pa, + &cpu.atmega165, + &cpu.atmega165a, + &cpu.atmega165p, + &cpu.atmega165pa, + &cpu.atmega168, + &cpu.atmega168a, + &cpu.atmega168p, + &cpu.atmega168pa, + &cpu.atmega169, + &cpu.atmega169a, + &cpu.atmega169p, + &cpu.atmega169pa, + &cpu.atmega16a, + &cpu.atmega16hva, + &cpu.atmega16hva2, + &cpu.atmega16hvb, + &cpu.atmega16hvbrevb, + &cpu.atmega16m1, + &cpu.atmega16u2, + &cpu.atmega16u4, + &cpu.atmega2560, + &cpu.atmega2561, + &cpu.atmega2564rfr2, + &cpu.atmega256rfr2, + &cpu.atmega32, + &cpu.atmega323, + &cpu.atmega324a, + &cpu.atmega324p, + &cpu.atmega324pa, + &cpu.atmega325, + &cpu.atmega3250, + &cpu.atmega3250a, + &cpu.atmega3250p, + &cpu.atmega3250pa, + &cpu.atmega325a, + &cpu.atmega325p, + &cpu.atmega325pa, + &cpu.atmega328, + &cpu.atmega328p, + &cpu.atmega329, + &cpu.atmega3290, + &cpu.atmega3290a, + &cpu.atmega3290p, + &cpu.atmega3290pa, + &cpu.atmega329a, + &cpu.atmega329p, + &cpu.atmega329pa, + &cpu.atmega32a, + &cpu.atmega32c1, + &cpu.atmega32hvb, + &cpu.atmega32hvbrevb, + &cpu.atmega32m1, + &cpu.atmega32u2, + &cpu.atmega32u4, + &cpu.atmega32u6, + &cpu.atmega406, + &cpu.atmega48, + &cpu.atmega48a, + &cpu.atmega48p, + &cpu.atmega48pa, + &cpu.atmega64, + &cpu.atmega640, + &cpu.atmega644, + &cpu.atmega644a, + &cpu.atmega644p, + &cpu.atmega644pa, + &cpu.atmega644rfr2, + &cpu.atmega645, + &cpu.atmega6450, + &cpu.atmega6450a, + &cpu.atmega6450p, + &cpu.atmega645a, + &cpu.atmega645p, + &cpu.atmega649, + &cpu.atmega6490, + &cpu.atmega6490a, + &cpu.atmega6490p, + &cpu.atmega649a, + &cpu.atmega649p, + &cpu.atmega64a, + &cpu.atmega64c1, + &cpu.atmega64hve, + &cpu.atmega64m1, + &cpu.atmega64rfr2, + &cpu.atmega8, + &cpu.atmega8515, + &cpu.atmega8535, + &cpu.atmega88, + &cpu.atmega88a, + &cpu.atmega88p, + &cpu.atmega88pa, + &cpu.atmega8a, + &cpu.atmega8hva, + &cpu.atmega8u2, + &cpu.attiny10, + &cpu.attiny102, + &cpu.attiny104, + &cpu.attiny11, + &cpu.attiny12, + &cpu.attiny13, + &cpu.attiny13a, + &cpu.attiny15, + &cpu.attiny1634, + &cpu.attiny167, + &cpu.attiny20, + &cpu.attiny22, + &cpu.attiny2313, + &cpu.attiny2313a, + &cpu.attiny24, + &cpu.attiny24a, + &cpu.attiny25, + &cpu.attiny26, + &cpu.attiny261, + &cpu.attiny261a, + &cpu.attiny28, + &cpu.attiny4, + &cpu.attiny40, + &cpu.attiny4313, + &cpu.attiny43u, + &cpu.attiny44, + &cpu.attiny44a, + &cpu.attiny45, + &cpu.attiny461, + &cpu.attiny461a, + &cpu.attiny48, + &cpu.attiny5, + &cpu.attiny828, + &cpu.attiny84, + &cpu.attiny84a, + &cpu.attiny85, + &cpu.attiny861, + &cpu.attiny861a, + &cpu.attiny87, + &cpu.attiny88, + &cpu.attiny9, + &cpu.atxmega128a1, + &cpu.atxmega128a1u, + &cpu.atxmega128a3, + &cpu.atxmega128a3u, + &cpu.atxmega128a4u, + &cpu.atxmega128b1, + &cpu.atxmega128b3, + &cpu.atxmega128c3, + &cpu.atxmega128d3, + &cpu.atxmega128d4, + &cpu.atxmega16a4, + &cpu.atxmega16a4u, + &cpu.atxmega16c4, + &cpu.atxmega16d4, + &cpu.atxmega16e5, + &cpu.atxmega192a3, + &cpu.atxmega192a3u, + &cpu.atxmega192c3, + &cpu.atxmega192d3, + &cpu.atxmega256a3, + &cpu.atxmega256a3b, + &cpu.atxmega256a3bu, + &cpu.atxmega256a3u, + &cpu.atxmega256c3, + &cpu.atxmega256d3, + &cpu.atxmega32a4, + &cpu.atxmega32a4u, + &cpu.atxmega32c4, + &cpu.atxmega32d4, + &cpu.atxmega32e5, + &cpu.atxmega32x1, + &cpu.atxmega384c3, + &cpu.atxmega384d3, + &cpu.atxmega64a1, + &cpu.atxmega64a1u, + &cpu.atxmega64a3, + &cpu.atxmega64a3u, + &cpu.atxmega64a4u, + &cpu.atxmega64b1, + &cpu.atxmega64b3, + &cpu.atxmega64c3, + &cpu.atxmega64d3, + &cpu.atxmega64d4, + &cpu.atxmega8e5, + &cpu.avr1, + &cpu.avr2, + &cpu.avr25, + &cpu.avr3, + &cpu.avr31, + &cpu.avr35, + &cpu.avr4, + &cpu.avr5, + &cpu.avr51, + &cpu.avr6, + &cpu.avrtiny, + &cpu.avrxmega1, + &cpu.avrxmega2, + &cpu.avrxmega3, + &cpu.avrxmega4, + &cpu.avrxmega5, + &cpu.avrxmega6, + &cpu.avrxmega7, + &cpu.m3000, +}; diff --git a/lib/std/target/bpf.zig b/lib/std/target/bpf.zig new file mode 100644 index 0000000000..b6179075cc --- /dev/null +++ b/lib/std/target/bpf.zig @@ -0,0 +1,76 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + alu32, + dummy, + dwarfris, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.alu32)] = .{ + .llvm_name = "alu32", + .description = "Enable ALU32 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dummy)] = .{ + .llvm_name = "dummy", + .description = "unused feature", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dwarfris)] = .{ + .llvm_name = "dwarfris", + .description = "Disable MCAsmInfo DwarfUsesRelocationsAcrossSections", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{}), + }; + pub const probe = Cpu{ + .name = "probe", + .llvm_name = "probe", + .features = featureSet(&[_]Feature{}), + }; + pub const v1 = Cpu{ + .name = "v1", + .llvm_name = "v1", + .features = featureSet(&[_]Feature{}), + }; + pub const v2 = Cpu{ + .name = "v2", + .llvm_name = "v2", + .features = featureSet(&[_]Feature{}), + }; + pub const v3 = Cpu{ + .name = "v3", + .llvm_name = "v3", + .features = featureSet(&[_]Feature{}), + }; +}; + +/// All bpf CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.generic, + &cpu.probe, + &cpu.v1, + &cpu.v2, + &cpu.v3, +}; diff --git a/lib/std/target/hexagon.zig b/lib/std/target/hexagon.zig new file mode 100644 index 0000000000..f873237493 --- /dev/null +++ b/lib/std/target/hexagon.zig @@ -0,0 +1,312 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + duplex, + hvx, + hvx_length128b, + hvx_length64b, + hvxv60, + hvxv62, + hvxv65, + hvxv66, + long_calls, + mem_noshuf, + memops, + noreturn_stack_elim, + nvj, + nvs, + packets, + reserved_r19, + small_data, + v5, + v55, + v60, + v62, + v65, + v66, + zreg, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.duplex)] = .{ + .llvm_name = "duplex", + .description = "Enable generation of duplex instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.hvx)] = .{ + .llvm_name = "hvx", + .description = "Hexagon HVX instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.hvx_length128b)] = .{ + .llvm_name = "hvx-length128b", + .description = "Hexagon HVX 128B instructions", + .dependencies = featureSet(&[_]Feature{ + .hvx, + }), + }; + result[@enumToInt(Feature.hvx_length64b)] = .{ + .llvm_name = "hvx-length64b", + .description = "Hexagon HVX 64B instructions", + .dependencies = featureSet(&[_]Feature{ + .hvx, + }), + }; + result[@enumToInt(Feature.hvxv60)] = .{ + .llvm_name = "hvxv60", + .description = "Hexagon HVX instructions", + .dependencies = featureSet(&[_]Feature{ + .hvx, + }), + }; + result[@enumToInt(Feature.hvxv62)] = .{ + .llvm_name = "hvxv62", + .description = "Hexagon HVX instructions", + .dependencies = featureSet(&[_]Feature{ + .hvx, + .hvxv60, + }), + }; + result[@enumToInt(Feature.hvxv65)] = .{ + .llvm_name = "hvxv65", + .description = "Hexagon HVX instructions", + .dependencies = featureSet(&[_]Feature{ + .hvx, + .hvxv60, + .hvxv62, + }), + }; + result[@enumToInt(Feature.hvxv66)] = .{ + .llvm_name = "hvxv66", + .description = "Hexagon HVX instructions", + .dependencies = featureSet(&[_]Feature{ + .hvx, + .hvxv60, + .hvxv62, + .hvxv65, + .zreg, + }), + }; + result[@enumToInt(Feature.long_calls)] = .{ + .llvm_name = "long-calls", + .description = "Use constant-extended calls", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mem_noshuf)] = .{ + .llvm_name = "mem_noshuf", + .description = "Supports mem_noshuf feature", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.memops)] = .{ + .llvm_name = "memops", + .description = "Use memop instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.noreturn_stack_elim)] = .{ + .llvm_name = "noreturn-stack-elim", + .description = "Eliminate stack allocation in a noreturn function when possible", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.nvj)] = .{ + .llvm_name = "nvj", + .description = "Support for new-value jumps", + .dependencies = featureSet(&[_]Feature{ + .packets, + }), + }; + result[@enumToInt(Feature.nvs)] = .{ + .llvm_name = "nvs", + .description = "Support for new-value stores", + .dependencies = featureSet(&[_]Feature{ + .packets, + }), + }; + result[@enumToInt(Feature.packets)] = .{ + .llvm_name = "packets", + .description = "Support for instruction packets", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reserved_r19)] = .{ + .llvm_name = "reserved-r19", + .description = "Reserve register R19", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.small_data)] = .{ + .llvm_name = "small-data", + .description = "Allow GP-relative addressing of global variables", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v5)] = .{ + .llvm_name = "v5", + .description = "Enable Hexagon V5 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v55)] = .{ + .llvm_name = "v55", + .description = "Enable Hexagon V55 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v60)] = .{ + .llvm_name = "v60", + .description = "Enable Hexagon V60 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v62)] = .{ + .llvm_name = "v62", + .description = "Enable Hexagon V62 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v65)] = .{ + .llvm_name = "v65", + .description = "Enable Hexagon V65 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v66)] = .{ + .llvm_name = "v66", + .description = "Enable Hexagon V66 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.zreg)] = .{ + .llvm_name = "zreg", + .description = "Hexagon ZReg extension instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{ + .duplex, + .memops, + .nvj, + .nvs, + .packets, + .small_data, + .v5, + .v55, + .v60, + }), + }; + pub const hexagonv5 = Cpu{ + .name = "hexagonv5", + .llvm_name = "hexagonv5", + .features = featureSet(&[_]Feature{ + .duplex, + .memops, + .nvj, + .nvs, + .packets, + .small_data, + .v5, + }), + }; + pub const hexagonv55 = Cpu{ + .name = "hexagonv55", + .llvm_name = "hexagonv55", + .features = featureSet(&[_]Feature{ + .duplex, + .memops, + .nvj, + .nvs, + .packets, + .small_data, + .v5, + .v55, + }), + }; + pub const hexagonv60 = Cpu{ + .name = "hexagonv60", + .llvm_name = "hexagonv60", + .features = featureSet(&[_]Feature{ + .duplex, + .memops, + .nvj, + .nvs, + .packets, + .small_data, + .v5, + .v55, + .v60, + }), + }; + pub const hexagonv62 = Cpu{ + .name = "hexagonv62", + .llvm_name = "hexagonv62", + .features = featureSet(&[_]Feature{ + .duplex, + .memops, + .nvj, + .nvs, + .packets, + .small_data, + .v5, + .v55, + .v60, + .v62, + }), + }; + pub const hexagonv65 = Cpu{ + .name = "hexagonv65", + .llvm_name = "hexagonv65", + .features = featureSet(&[_]Feature{ + .duplex, + .mem_noshuf, + .memops, + .nvj, + .nvs, + .packets, + .small_data, + .v5, + .v55, + .v60, + .v62, + .v65, + }), + }; + pub const hexagonv66 = Cpu{ + .name = "hexagonv66", + .llvm_name = "hexagonv66", + .features = featureSet(&[_]Feature{ + .duplex, + .mem_noshuf, + .memops, + .nvj, + .nvs, + .packets, + .small_data, + .v5, + .v55, + .v60, + .v62, + .v65, + .v66, + }), + }; +}; + +/// All hexagon CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.generic, + &cpu.hexagonv5, + &cpu.hexagonv55, + &cpu.hexagonv60, + &cpu.hexagonv62, + &cpu.hexagonv65, + &cpu.hexagonv66, +}; diff --git a/lib/std/target/mips.zig b/lib/std/target/mips.zig new file mode 100644 index 0000000000..fce7c9ce36 --- /dev/null +++ b/lib/std/target/mips.zig @@ -0,0 +1,518 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + abs2008, + cnmips, + crc, + dsp, + dspr2, + dspr3, + eva, + fp64, + fpxx, + ginv, + gp64, + long_calls, + micromips, + mips1, + mips16, + mips2, + mips3, + mips32, + mips32r2, + mips32r3, + mips32r5, + mips32r6, + mips3_32, + mips3_32r2, + mips4, + mips4_32, + mips4_32r2, + mips5, + mips5_32r2, + mips64, + mips64r2, + mips64r3, + mips64r5, + mips64r6, + msa, + mt, + nan2008, + noabicalls, + nomadd4, + nooddspreg, + p5600, + ptr64, + single_float, + soft_float, + sym32, + use_indirect_jump_hazard, + use_tcc_in_div, + vfpu, + virt, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.abs2008)] = .{ + .llvm_name = "abs2008", + .description = "Disable IEEE 754-2008 abs.fmt mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.cnmips)] = .{ + .llvm_name = "cnmips", + .description = "Octeon cnMIPS Support", + .dependencies = featureSet(&[_]Feature{ + .mips64r2, + }), + }; + result[@enumToInt(Feature.crc)] = .{ + .llvm_name = "crc", + .description = "Mips R6 CRC ASE", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dsp)] = .{ + .llvm_name = "dsp", + .description = "Mips DSP ASE", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dspr2)] = .{ + .llvm_name = "dspr2", + .description = "Mips DSP-R2 ASE", + .dependencies = featureSet(&[_]Feature{ + .dsp, + }), + }; + result[@enumToInt(Feature.dspr3)] = .{ + .llvm_name = "dspr3", + .description = "Mips DSP-R3 ASE", + .dependencies = featureSet(&[_]Feature{ + .dsp, + .dspr2, + }), + }; + result[@enumToInt(Feature.eva)] = .{ + .llvm_name = "eva", + .description = "Mips EVA ASE", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fp64)] = .{ + .llvm_name = "fp64", + .description = "Support 64-bit FP registers", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fpxx)] = .{ + .llvm_name = "fpxx", + .description = "Support for FPXX", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ginv)] = .{ + .llvm_name = "ginv", + .description = "Mips Global Invalidate ASE", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.gp64)] = .{ + .llvm_name = "gp64", + .description = "General Purpose Registers are 64-bit wide", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.long_calls)] = .{ + .llvm_name = "long-calls", + .description = "Disable use of the jal instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.micromips)] = .{ + .llvm_name = "micromips", + .description = "microMips mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mips1)] = .{ + .llvm_name = "mips1", + .description = "Mips I ISA Support [highly experimental]", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mips16)] = .{ + .llvm_name = "mips16", + .description = "Mips16 mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mips2)] = .{ + .llvm_name = "mips2", + .description = "Mips II ISA Support [highly experimental]", + .dependencies = featureSet(&[_]Feature{ + .mips1, + }), + }; + result[@enumToInt(Feature.mips3)] = .{ + .llvm_name = "mips3", + .description = "MIPS III ISA Support [highly experimental]", + .dependencies = featureSet(&[_]Feature{ + .fp64, + .gp64, + .mips2, + .mips3_32, + .mips3_32r2, + }), + }; + result[@enumToInt(Feature.mips32)] = .{ + .llvm_name = "mips32", + .description = "Mips32 ISA Support", + .dependencies = featureSet(&[_]Feature{ + .mips2, + .mips3_32, + .mips4_32, + }), + }; + result[@enumToInt(Feature.mips32r2)] = .{ + .llvm_name = "mips32r2", + .description = "Mips32r2 ISA Support", + .dependencies = featureSet(&[_]Feature{ + .mips32, + .mips3_32r2, + .mips4_32r2, + .mips5_32r2, + }), + }; + result[@enumToInt(Feature.mips32r3)] = .{ + .llvm_name = "mips32r3", + .description = "Mips32r3 ISA Support", + .dependencies = featureSet(&[_]Feature{ + .mips32r2, + }), + }; + result[@enumToInt(Feature.mips32r5)] = .{ + .llvm_name = "mips32r5", + .description = "Mips32r5 ISA Support", + .dependencies = featureSet(&[_]Feature{ + .mips32r3, + }), + }; + result[@enumToInt(Feature.mips32r6)] = .{ + .llvm_name = "mips32r6", + .description = "Mips32r6 ISA Support [experimental]", + .dependencies = featureSet(&[_]Feature{ + .abs2008, + .fp64, + .mips32r5, + .nan2008, + }), + }; + result[@enumToInt(Feature.mips3_32)] = .{ + .llvm_name = "mips3_32", + .description = "Subset of MIPS-III that is also in MIPS32 [highly experimental]", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mips3_32r2)] = .{ + .llvm_name = "mips3_32r2", + .description = "Subset of MIPS-III that is also in MIPS32r2 [highly experimental]", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mips4)] = .{ + .llvm_name = "mips4", + .description = "MIPS IV ISA Support", + .dependencies = featureSet(&[_]Feature{ + .mips3, + .mips4_32, + .mips4_32r2, + }), + }; + result[@enumToInt(Feature.mips4_32)] = .{ + .llvm_name = "mips4_32", + .description = "Subset of MIPS-IV that is also in MIPS32 [highly experimental]", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mips4_32r2)] = .{ + .llvm_name = "mips4_32r2", + .description = "Subset of MIPS-IV that is also in MIPS32r2 [highly experimental]", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mips5)] = .{ + .llvm_name = "mips5", + .description = "MIPS V ISA Support [highly experimental]", + .dependencies = featureSet(&[_]Feature{ + .mips4, + .mips5_32r2, + }), + }; + result[@enumToInt(Feature.mips5_32r2)] = .{ + .llvm_name = "mips5_32r2", + .description = "Subset of MIPS-V that is also in MIPS32r2 [highly experimental]", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mips64)] = .{ + .llvm_name = "mips64", + .description = "Mips64 ISA Support", + .dependencies = featureSet(&[_]Feature{ + .mips32, + .mips5, + }), + }; + result[@enumToInt(Feature.mips64r2)] = .{ + .llvm_name = "mips64r2", + .description = "Mips64r2 ISA Support", + .dependencies = featureSet(&[_]Feature{ + .mips32r2, + .mips64, + }), + }; + result[@enumToInt(Feature.mips64r3)] = .{ + .llvm_name = "mips64r3", + .description = "Mips64r3 ISA Support", + .dependencies = featureSet(&[_]Feature{ + .mips32r3, + .mips64r2, + }), + }; + result[@enumToInt(Feature.mips64r5)] = .{ + .llvm_name = "mips64r5", + .description = "Mips64r5 ISA Support", + .dependencies = featureSet(&[_]Feature{ + .mips32r5, + .mips64r3, + }), + }; + result[@enumToInt(Feature.mips64r6)] = .{ + .llvm_name = "mips64r6", + .description = "Mips64r6 ISA Support [experimental]", + .dependencies = featureSet(&[_]Feature{ + .abs2008, + .mips32r6, + .mips64r5, + .nan2008, + }), + }; + result[@enumToInt(Feature.msa)] = .{ + .llvm_name = "msa", + .description = "Mips MSA ASE", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mt)] = .{ + .llvm_name = "mt", + .description = "Mips MT ASE", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.nan2008)] = .{ + .llvm_name = "nan2008", + .description = "IEEE 754-2008 NaN encoding", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.noabicalls)] = .{ + .llvm_name = "noabicalls", + .description = "Disable SVR4-style position-independent code", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.nomadd4)] = .{ + .llvm_name = "nomadd4", + .description = "Disable 4-operand madd.fmt and related instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.nooddspreg)] = .{ + .llvm_name = "nooddspreg", + .description = "Disable odd numbered single-precision registers", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.p5600)] = .{ + .llvm_name = "p5600", + .description = "The P5600 Processor", + .dependencies = featureSet(&[_]Feature{ + .mips32r5, + }), + }; + result[@enumToInt(Feature.ptr64)] = .{ + .llvm_name = "ptr64", + .description = "Pointers are 64-bit wide", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.single_float)] = .{ + .llvm_name = "single-float", + .description = "Only supports single precision float", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.soft_float)] = .{ + .llvm_name = "soft-float", + .description = "Does not support floating point instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sym32)] = .{ + .llvm_name = "sym32", + .description = "Symbols are 32 bit on Mips64", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.use_indirect_jump_hazard)] = .{ + .llvm_name = "use-indirect-jump-hazard", + .description = "Use indirect jump guards to prevent certain speculation based attacks", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.use_tcc_in_div)] = .{ + .llvm_name = "use-tcc-in-div", + .description = "Force the assembler to use trapping", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vfpu)] = .{ + .llvm_name = "vfpu", + .description = "Enable vector FPU instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.virt)] = .{ + .llvm_name = "virt", + .description = "Mips Virtualization ASE", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const mips1 = Cpu{ + .name = "mips1", + .llvm_name = "mips1", + .features = featureSet(&[_]Feature{ + .mips1, + }), + }; + pub const mips2 = Cpu{ + .name = "mips2", + .llvm_name = "mips2", + .features = featureSet(&[_]Feature{ + .mips2, + }), + }; + pub const mips3 = Cpu{ + .name = "mips3", + .llvm_name = "mips3", + .features = featureSet(&[_]Feature{ + .mips3, + }), + }; + pub const mips32 = Cpu{ + .name = "mips32", + .llvm_name = "mips32", + .features = featureSet(&[_]Feature{ + .mips32, + }), + }; + pub const mips32r2 = Cpu{ + .name = "mips32r2", + .llvm_name = "mips32r2", + .features = featureSet(&[_]Feature{ + .mips32r2, + }), + }; + pub const mips32r3 = Cpu{ + .name = "mips32r3", + .llvm_name = "mips32r3", + .features = featureSet(&[_]Feature{ + .mips32r3, + }), + }; + pub const mips32r5 = Cpu{ + .name = "mips32r5", + .llvm_name = "mips32r5", + .features = featureSet(&[_]Feature{ + .mips32r5, + }), + }; + pub const mips32r6 = Cpu{ + .name = "mips32r6", + .llvm_name = "mips32r6", + .features = featureSet(&[_]Feature{ + .mips32r6, + }), + }; + pub const mips4 = Cpu{ + .name = "mips4", + .llvm_name = "mips4", + .features = featureSet(&[_]Feature{ + .mips4, + }), + }; + pub const mips5 = Cpu{ + .name = "mips5", + .llvm_name = "mips5", + .features = featureSet(&[_]Feature{ + .mips5, + }), + }; + pub const mips64 = Cpu{ + .name = "mips64", + .llvm_name = "mips64", + .features = featureSet(&[_]Feature{ + .mips64, + }), + }; + pub const mips64r2 = Cpu{ + .name = "mips64r2", + .llvm_name = "mips64r2", + .features = featureSet(&[_]Feature{ + .mips64r2, + }), + }; + pub const mips64r3 = Cpu{ + .name = "mips64r3", + .llvm_name = "mips64r3", + .features = featureSet(&[_]Feature{ + .mips64r3, + }), + }; + pub const mips64r5 = Cpu{ + .name = "mips64r5", + .llvm_name = "mips64r5", + .features = featureSet(&[_]Feature{ + .mips64r5, + }), + }; + pub const mips64r6 = Cpu{ + .name = "mips64r6", + .llvm_name = "mips64r6", + .features = featureSet(&[_]Feature{ + .mips64r6, + }), + }; + pub const octeon = Cpu{ + .name = "octeon", + .llvm_name = "octeon", + .features = featureSet(&[_]Feature{ + .cnmips, + .mips64r2, + }), + }; + pub const p5600 = Cpu{ + .name = "p5600", + .llvm_name = "p5600", + .features = featureSet(&[_]Feature{ + .p5600, + }), + }; +}; + +/// All mips CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.mips1, + &cpu.mips2, + &cpu.mips3, + &cpu.mips32, + &cpu.mips32r2, + &cpu.mips32r3, + &cpu.mips32r5, + &cpu.mips32r6, + &cpu.mips4, + &cpu.mips5, + &cpu.mips64, + &cpu.mips64r2, + &cpu.mips64r3, + &cpu.mips64r5, + &cpu.mips64r6, + &cpu.octeon, + &cpu.p5600, +}; diff --git a/lib/std/target/msp430.zig b/lib/std/target/msp430.zig new file mode 100644 index 0000000000..bc932f2295 --- /dev/null +++ b/lib/std/target/msp430.zig @@ -0,0 +1,72 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + ext, + hwmult16, + hwmult32, + hwmultf5, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.ext)] = .{ + .llvm_name = "ext", + .description = "Enable MSP430-X extensions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.hwmult16)] = .{ + .llvm_name = "hwmult16", + .description = "Enable 16-bit hardware multiplier", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.hwmult32)] = .{ + .llvm_name = "hwmult32", + .description = "Enable 32-bit hardware multiplier", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.hwmultf5)] = .{ + .llvm_name = "hwmultf5", + .description = "Enable F5 series hardware multiplier", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{}), + }; + pub const msp430 = Cpu{ + .name = "msp430", + .llvm_name = "msp430", + .features = featureSet(&[_]Feature{}), + }; + pub const msp430x = Cpu{ + .name = "msp430x", + .llvm_name = "msp430x", + .features = featureSet(&[_]Feature{ + .ext, + }), + }; +}; + +/// All msp430 CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.generic, + &cpu.msp430, + &cpu.msp430x, +}; diff --git a/lib/std/target/nvptx.zig b/lib/std/target/nvptx.zig new file mode 100644 index 0000000000..1800e320b4 --- /dev/null +++ b/lib/std/target/nvptx.zig @@ -0,0 +1,309 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + ptx32, + ptx40, + ptx41, + ptx42, + ptx43, + ptx50, + ptx60, + ptx61, + ptx63, + ptx64, + sm_20, + sm_21, + sm_30, + sm_32, + sm_35, + sm_37, + sm_50, + sm_52, + sm_53, + sm_60, + sm_61, + sm_62, + sm_70, + sm_72, + sm_75, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.ptx32)] = .{ + .llvm_name = "ptx32", + .description = "Use PTX version 3.2", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ptx40)] = .{ + .llvm_name = "ptx40", + .description = "Use PTX version 4.0", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ptx41)] = .{ + .llvm_name = "ptx41", + .description = "Use PTX version 4.1", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ptx42)] = .{ + .llvm_name = "ptx42", + .description = "Use PTX version 4.2", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ptx43)] = .{ + .llvm_name = "ptx43", + .description = "Use PTX version 4.3", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ptx50)] = .{ + .llvm_name = "ptx50", + .description = "Use PTX version 5.0", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ptx60)] = .{ + .llvm_name = "ptx60", + .description = "Use PTX version 6.0", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ptx61)] = .{ + .llvm_name = "ptx61", + .description = "Use PTX version 6.1", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ptx63)] = .{ + .llvm_name = "ptx63", + .description = "Use PTX version 6.3", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ptx64)] = .{ + .llvm_name = "ptx64", + .description = "Use PTX version 6.4", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_20)] = .{ + .llvm_name = "sm_20", + .description = "Target SM 2.0", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_21)] = .{ + .llvm_name = "sm_21", + .description = "Target SM 2.1", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_30)] = .{ + .llvm_name = "sm_30", + .description = "Target SM 3.0", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_32)] = .{ + .llvm_name = "sm_32", + .description = "Target SM 3.2", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_35)] = .{ + .llvm_name = "sm_35", + .description = "Target SM 3.5", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_37)] = .{ + .llvm_name = "sm_37", + .description = "Target SM 3.7", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_50)] = .{ + .llvm_name = "sm_50", + .description = "Target SM 5.0", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_52)] = .{ + .llvm_name = "sm_52", + .description = "Target SM 5.2", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_53)] = .{ + .llvm_name = "sm_53", + .description = "Target SM 5.3", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_60)] = .{ + .llvm_name = "sm_60", + .description = "Target SM 6.0", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_61)] = .{ + .llvm_name = "sm_61", + .description = "Target SM 6.1", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_62)] = .{ + .llvm_name = "sm_62", + .description = "Target SM 6.2", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_70)] = .{ + .llvm_name = "sm_70", + .description = "Target SM 7.0", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_72)] = .{ + .llvm_name = "sm_72", + .description = "Target SM 7.2", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sm_75)] = .{ + .llvm_name = "sm_75", + .description = "Target SM 7.5", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const sm_20 = Cpu{ + .name = "sm_20", + .llvm_name = "sm_20", + .features = featureSet(&[_]Feature{ + .sm_20, + }), + }; + pub const sm_21 = Cpu{ + .name = "sm_21", + .llvm_name = "sm_21", + .features = featureSet(&[_]Feature{ + .sm_21, + }), + }; + pub const sm_30 = Cpu{ + .name = "sm_30", + .llvm_name = "sm_30", + .features = featureSet(&[_]Feature{ + .sm_30, + }), + }; + pub const sm_32 = Cpu{ + .name = "sm_32", + .llvm_name = "sm_32", + .features = featureSet(&[_]Feature{ + .ptx40, + .sm_32, + }), + }; + pub const sm_35 = Cpu{ + .name = "sm_35", + .llvm_name = "sm_35", + .features = featureSet(&[_]Feature{ + .sm_35, + }), + }; + pub const sm_37 = Cpu{ + .name = "sm_37", + .llvm_name = "sm_37", + .features = featureSet(&[_]Feature{ + .ptx41, + .sm_37, + }), + }; + pub const sm_50 = Cpu{ + .name = "sm_50", + .llvm_name = "sm_50", + .features = featureSet(&[_]Feature{ + .ptx40, + .sm_50, + }), + }; + pub const sm_52 = Cpu{ + .name = "sm_52", + .llvm_name = "sm_52", + .features = featureSet(&[_]Feature{ + .ptx41, + .sm_52, + }), + }; + pub const sm_53 = Cpu{ + .name = "sm_53", + .llvm_name = "sm_53", + .features = featureSet(&[_]Feature{ + .ptx42, + .sm_53, + }), + }; + pub const sm_60 = Cpu{ + .name = "sm_60", + .llvm_name = "sm_60", + .features = featureSet(&[_]Feature{ + .ptx50, + .sm_60, + }), + }; + pub const sm_61 = Cpu{ + .name = "sm_61", + .llvm_name = "sm_61", + .features = featureSet(&[_]Feature{ + .ptx50, + .sm_61, + }), + }; + pub const sm_62 = Cpu{ + .name = "sm_62", + .llvm_name = "sm_62", + .features = featureSet(&[_]Feature{ + .ptx50, + .sm_62, + }), + }; + pub const sm_70 = Cpu{ + .name = "sm_70", + .llvm_name = "sm_70", + .features = featureSet(&[_]Feature{ + .ptx60, + .sm_70, + }), + }; + pub const sm_72 = Cpu{ + .name = "sm_72", + .llvm_name = "sm_72", + .features = featureSet(&[_]Feature{ + .ptx61, + .sm_72, + }), + }; + pub const sm_75 = Cpu{ + .name = "sm_75", + .llvm_name = "sm_75", + .features = featureSet(&[_]Feature{ + .ptx63, + .sm_75, + }), + }; +}; + +/// All nvptx CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.sm_20, + &cpu.sm_21, + &cpu.sm_30, + &cpu.sm_32, + &cpu.sm_35, + &cpu.sm_37, + &cpu.sm_50, + &cpu.sm_52, + &cpu.sm_53, + &cpu.sm_60, + &cpu.sm_61, + &cpu.sm_62, + &cpu.sm_70, + &cpu.sm_72, + &cpu.sm_75, +}; diff --git a/lib/std/target/powerpc.zig b/lib/std/target/powerpc.zig new file mode 100644 index 0000000000..41321f7b04 --- /dev/null +++ b/lib/std/target/powerpc.zig @@ -0,0 +1,938 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + @"64bit", + @"64bitregs", + altivec, + booke, + bpermd, + cmpb, + crbits, + crypto, + direct_move, + e500, + extdiv, + fcpsgn, + float128, + fpcvt, + fprnd, + fpu, + fre, + fres, + frsqrte, + frsqrtes, + fsqrt, + hard_float, + htm, + icbt, + invariant_function_descriptors, + isa_v30_instructions, + isel, + ldbrx, + lfiwax, + longcall, + mfocrf, + msync, + partword_atomics, + popcntd, + power8_altivec, + power8_vector, + power9_altivec, + power9_vector, + ppc_postra_sched, + ppc_prera_sched, + ppc4xx, + ppc6xx, + qpx, + recipprec, + secure_plt, + slow_popcntd, + spe, + stfiwx, + two_const_nr, + vectors_use_two_units, + vsx, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.@"64bit")] = .{ + .llvm_name = "64bit", + .description = "Enable 64-bit instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.@"64bitregs")] = .{ + .llvm_name = "64bitregs", + .description = "Enable 64-bit registers usage for ppc32 [beta]", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.altivec)] = .{ + .llvm_name = "altivec", + .description = "Enable Altivec instructions", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.booke)] = .{ + .llvm_name = "booke", + .description = "Enable Book E instructions", + .dependencies = featureSet(&[_]Feature{ + .icbt, + }), + }; + result[@enumToInt(Feature.bpermd)] = .{ + .llvm_name = "bpermd", + .description = "Enable the bpermd instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.cmpb)] = .{ + .llvm_name = "cmpb", + .description = "Enable the cmpb instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.crbits)] = .{ + .llvm_name = "crbits", + .description = "Use condition-register bits individually", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.crypto)] = .{ + .llvm_name = "crypto", + .description = "Enable POWER8 Crypto instructions", + .dependencies = featureSet(&[_]Feature{ + .power8_altivec, + }), + }; + result[@enumToInt(Feature.direct_move)] = .{ + .llvm_name = "direct-move", + .description = "Enable Power8 direct move instructions", + .dependencies = featureSet(&[_]Feature{ + .vsx, + }), + }; + result[@enumToInt(Feature.e500)] = .{ + .llvm_name = "e500", + .description = "Enable E500/E500mc instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.extdiv)] = .{ + .llvm_name = "extdiv", + .description = "Enable extended divide instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fcpsgn)] = .{ + .llvm_name = "fcpsgn", + .description = "Enable the fcpsgn instruction", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.float128)] = .{ + .llvm_name = "float128", + .description = "Enable the __float128 data type for IEEE-754R Binary128.", + .dependencies = featureSet(&[_]Feature{ + .vsx, + }), + }; + result[@enumToInt(Feature.fpcvt)] = .{ + .llvm_name = "fpcvt", + .description = "Enable fc[ft]* (unsigned and single-precision) and lfiwzx instructions", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.fprnd)] = .{ + .llvm_name = "fprnd", + .description = "Enable the fri[mnpz] instructions", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.fpu)] = .{ + .llvm_name = "fpu", + .description = "Enable classic FPU instructions", + .dependencies = featureSet(&[_]Feature{ + .hard_float, + }), + }; + result[@enumToInt(Feature.fre)] = .{ + .llvm_name = "fre", + .description = "Enable the fre instruction", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.fres)] = .{ + .llvm_name = "fres", + .description = "Enable the fres instruction", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.frsqrte)] = .{ + .llvm_name = "frsqrte", + .description = "Enable the frsqrte instruction", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.frsqrtes)] = .{ + .llvm_name = "frsqrtes", + .description = "Enable the frsqrtes instruction", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.fsqrt)] = .{ + .llvm_name = "fsqrt", + .description = "Enable the fsqrt instruction", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.hard_float)] = .{ + .llvm_name = "hard-float", + .description = "Enable floating-point instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.htm)] = .{ + .llvm_name = "htm", + .description = "Enable Hardware Transactional Memory instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.icbt)] = .{ + .llvm_name = "icbt", + .description = "Enable icbt instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.invariant_function_descriptors)] = .{ + .llvm_name = "invariant-function-descriptors", + .description = "Assume function descriptors are invariant", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.isa_v30_instructions)] = .{ + .llvm_name = "isa-v30-instructions", + .description = "Enable instructions added in ISA 3.0.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.isel)] = .{ + .llvm_name = "isel", + .description = "Enable the isel instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ldbrx)] = .{ + .llvm_name = "ldbrx", + .description = "Enable the ldbrx instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lfiwax)] = .{ + .llvm_name = "lfiwax", + .description = "Enable the lfiwax instruction", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.longcall)] = .{ + .llvm_name = "longcall", + .description = "Always use indirect calls", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mfocrf)] = .{ + .llvm_name = "mfocrf", + .description = "Enable the MFOCRF instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.msync)] = .{ + .llvm_name = "msync", + .description = "Has only the msync instruction instead of sync", + .dependencies = featureSet(&[_]Feature{ + .booke, + }), + }; + result[@enumToInt(Feature.partword_atomics)] = .{ + .llvm_name = "partword-atomics", + .description = "Enable l[bh]arx and st[bh]cx.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.popcntd)] = .{ + .llvm_name = "popcntd", + .description = "Enable the popcnt[dw] instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.power8_altivec)] = .{ + .llvm_name = "power8-altivec", + .description = "Enable POWER8 Altivec instructions", + .dependencies = featureSet(&[_]Feature{ + .altivec, + }), + }; + result[@enumToInt(Feature.power8_vector)] = .{ + .llvm_name = "power8-vector", + .description = "Enable POWER8 vector instructions", + .dependencies = featureSet(&[_]Feature{ + .power8_altivec, + .vsx, + }), + }; + result[@enumToInt(Feature.power9_altivec)] = .{ + .llvm_name = "power9-altivec", + .description = "Enable POWER9 Altivec instructions", + .dependencies = featureSet(&[_]Feature{ + .isa_v30_instructions, + .power8_altivec, + }), + }; + result[@enumToInt(Feature.power9_vector)] = .{ + .llvm_name = "power9-vector", + .description = "Enable POWER9 vector instructions", + .dependencies = featureSet(&[_]Feature{ + .isa_v30_instructions, + .power8_vector, + .power9_altivec, + }), + }; + result[@enumToInt(Feature.ppc_postra_sched)] = .{ + .llvm_name = "ppc-postra-sched", + .description = "Use PowerPC post-RA scheduling strategy", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ppc_prera_sched)] = .{ + .llvm_name = "ppc-prera-sched", + .description = "Use PowerPC pre-RA scheduling strategy", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ppc4xx)] = .{ + .llvm_name = "ppc4xx", + .description = "Enable PPC 4xx instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ppc6xx)] = .{ + .llvm_name = "ppc6xx", + .description = "Enable PPC 6xx instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.qpx)] = .{ + .llvm_name = "qpx", + .description = "Enable QPX instructions", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.recipprec)] = .{ + .llvm_name = "recipprec", + .description = "Assume higher precision reciprocal estimates", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.secure_plt)] = .{ + .llvm_name = "secure-plt", + .description = "Enable secure plt mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_popcntd)] = .{ + .llvm_name = "slow-popcntd", + .description = "Has slow popcnt[dw] instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.spe)] = .{ + .llvm_name = "spe", + .description = "Enable SPE instructions", + .dependencies = featureSet(&[_]Feature{ + .hard_float, + }), + }; + result[@enumToInt(Feature.stfiwx)] = .{ + .llvm_name = "stfiwx", + .description = "Enable the stfiwx instruction", + .dependencies = featureSet(&[_]Feature{ + .fpu, + }), + }; + result[@enumToInt(Feature.two_const_nr)] = .{ + .llvm_name = "two-const-nr", + .description = "Requires two constant Newton-Raphson computation", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vectors_use_two_units)] = .{ + .llvm_name = "vectors-use-two-units", + .description = "Vectors use two units", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vsx)] = .{ + .llvm_name = "vsx", + .description = "Enable VSX instructions", + .dependencies = featureSet(&[_]Feature{ + .altivec, + }), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const @"440" = Cpu{ + .name = "440", + .llvm_name = "440", + .features = featureSet(&[_]Feature{ + .booke, + .fres, + .frsqrte, + .icbt, + .isel, + .msync, + }), + }; + pub const @"450" = Cpu{ + .name = "450", + .llvm_name = "450", + .features = featureSet(&[_]Feature{ + .booke, + .fres, + .frsqrte, + .icbt, + .isel, + .msync, + }), + }; + pub const @"601" = Cpu{ + .name = "601", + .llvm_name = "601", + .features = featureSet(&[_]Feature{ + .fpu, + }), + }; + pub const @"602" = Cpu{ + .name = "602", + .llvm_name = "602", + .features = featureSet(&[_]Feature{ + .fpu, + }), + }; + pub const @"603" = Cpu{ + .name = "603", + .llvm_name = "603", + .features = featureSet(&[_]Feature{ + .fres, + .frsqrte, + }), + }; + pub const @"603e" = Cpu{ + .name = "603e", + .llvm_name = "603e", + .features = featureSet(&[_]Feature{ + .fres, + .frsqrte, + }), + }; + pub const @"603ev" = Cpu{ + .name = "603ev", + .llvm_name = "603ev", + .features = featureSet(&[_]Feature{ + .fres, + .frsqrte, + }), + }; + pub const @"604" = Cpu{ + .name = "604", + .llvm_name = "604", + .features = featureSet(&[_]Feature{ + .fres, + .frsqrte, + }), + }; + pub const @"604e" = Cpu{ + .name = "604e", + .llvm_name = "604e", + .features = featureSet(&[_]Feature{ + .fres, + .frsqrte, + }), + }; + pub const @"620" = Cpu{ + .name = "620", + .llvm_name = "620", + .features = featureSet(&[_]Feature{ + .fres, + .frsqrte, + }), + }; + pub const @"7400" = Cpu{ + .name = "7400", + .llvm_name = "7400", + .features = featureSet(&[_]Feature{ + .altivec, + .fres, + .frsqrte, + }), + }; + pub const @"7450" = Cpu{ + .name = "7450", + .llvm_name = "7450", + .features = featureSet(&[_]Feature{ + .altivec, + .fres, + .frsqrte, + }), + }; + pub const @"750" = Cpu{ + .name = "750", + .llvm_name = "750", + .features = featureSet(&[_]Feature{ + .fres, + .frsqrte, + }), + }; + pub const @"970" = Cpu{ + .name = "970", + .llvm_name = "970", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .fres, + .frsqrte, + .fsqrt, + .mfocrf, + .stfiwx, + }), + }; + pub const a2 = Cpu{ + .name = "a2", + .llvm_name = "a2", + .features = featureSet(&[_]Feature{ + .@"64bit", + .booke, + .cmpb, + .fcpsgn, + .fpcvt, + .fprnd, + .fre, + .fres, + .frsqrte, + .frsqrtes, + .fsqrt, + .icbt, + .isel, + .ldbrx, + .lfiwax, + .mfocrf, + .recipprec, + .slow_popcntd, + .stfiwx, + }), + }; + pub const a2q = Cpu{ + .name = "a2q", + .llvm_name = "a2q", + .features = featureSet(&[_]Feature{ + .@"64bit", + .booke, + .cmpb, + .fcpsgn, + .fpcvt, + .fprnd, + .fre, + .fres, + .frsqrte, + .frsqrtes, + .fsqrt, + .icbt, + .isel, + .ldbrx, + .lfiwax, + .mfocrf, + .qpx, + .recipprec, + .slow_popcntd, + .stfiwx, + }), + }; + pub const e500 = Cpu{ + .name = "e500", + .llvm_name = "e500", + .features = featureSet(&[_]Feature{ + .booke, + .icbt, + .isel, + }), + }; + pub const e500mc = Cpu{ + .name = "e500mc", + .llvm_name = "e500mc", + .features = featureSet(&[_]Feature{ + .booke, + .icbt, + .isel, + .stfiwx, + }), + }; + pub const e5500 = Cpu{ + .name = "e5500", + .llvm_name = "e5500", + .features = featureSet(&[_]Feature{ + .@"64bit", + .booke, + .icbt, + .isel, + .mfocrf, + .stfiwx, + }), + }; + pub const g3 = Cpu{ + .name = "g3", + .llvm_name = "g3", + .features = featureSet(&[_]Feature{ + .fres, + .frsqrte, + }), + }; + pub const g4 = Cpu{ + .name = "g4", + .llvm_name = "g4", + .features = featureSet(&[_]Feature{ + .altivec, + .fres, + .frsqrte, + }), + }; + pub const @"g4+" = Cpu{ + .name = "g4+", + .llvm_name = "g4+", + .features = featureSet(&[_]Feature{ + .altivec, + .fres, + .frsqrte, + }), + }; + pub const g5 = Cpu{ + .name = "g5", + .llvm_name = "g5", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .fres, + .frsqrte, + .fsqrt, + .mfocrf, + .stfiwx, + }), + }; + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{ + .hard_float, + }), + }; + pub const ppc = Cpu{ + .name = "ppc", + .llvm_name = "ppc", + .features = featureSet(&[_]Feature{ + .hard_float, + }), + }; + pub const ppc32 = Cpu{ + .name = "ppc32", + .llvm_name = "ppc32", + .features = featureSet(&[_]Feature{ + .hard_float, + }), + }; + pub const ppc64 = Cpu{ + .name = "ppc64", + .llvm_name = "ppc64", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .fres, + .frsqrte, + .fsqrt, + .mfocrf, + .stfiwx, + }), + }; + pub const ppc64le = Cpu{ + .name = "ppc64le", + .llvm_name = "ppc64le", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .bpermd, + .cmpb, + .crypto, + .direct_move, + .extdiv, + .fcpsgn, + .fpcvt, + .fprnd, + .fre, + .fres, + .frsqrte, + .frsqrtes, + .fsqrt, + .htm, + .icbt, + .isel, + .ldbrx, + .lfiwax, + .mfocrf, + .partword_atomics, + .popcntd, + .power8_altivec, + .power8_vector, + .recipprec, + .stfiwx, + .two_const_nr, + .vsx, + }), + }; + pub const pwr3 = Cpu{ + .name = "pwr3", + .llvm_name = "pwr3", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .fres, + .frsqrte, + .mfocrf, + .stfiwx, + }), + }; + pub const pwr4 = Cpu{ + .name = "pwr4", + .llvm_name = "pwr4", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .fres, + .frsqrte, + .fsqrt, + .mfocrf, + .stfiwx, + }), + }; + pub const pwr5 = Cpu{ + .name = "pwr5", + .llvm_name = "pwr5", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .fre, + .fres, + .frsqrte, + .frsqrtes, + .fsqrt, + .mfocrf, + .stfiwx, + }), + }; + pub const pwr5x = Cpu{ + .name = "pwr5x", + .llvm_name = "pwr5x", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .fprnd, + .fre, + .fres, + .frsqrte, + .frsqrtes, + .fsqrt, + .mfocrf, + .stfiwx, + }), + }; + pub const pwr6 = Cpu{ + .name = "pwr6", + .llvm_name = "pwr6", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .cmpb, + .fcpsgn, + .fprnd, + .fre, + .fres, + .frsqrte, + .frsqrtes, + .fsqrt, + .lfiwax, + .mfocrf, + .recipprec, + .stfiwx, + }), + }; + pub const pwr6x = Cpu{ + .name = "pwr6x", + .llvm_name = "pwr6x", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .cmpb, + .fcpsgn, + .fprnd, + .fre, + .fres, + .frsqrte, + .frsqrtes, + .fsqrt, + .lfiwax, + .mfocrf, + .recipprec, + .stfiwx, + }), + }; + pub const pwr7 = Cpu{ + .name = "pwr7", + .llvm_name = "pwr7", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .bpermd, + .cmpb, + .extdiv, + .fcpsgn, + .fpcvt, + .fprnd, + .fre, + .fres, + .frsqrte, + .frsqrtes, + .fsqrt, + .isel, + .ldbrx, + .lfiwax, + .mfocrf, + .popcntd, + .recipprec, + .stfiwx, + .two_const_nr, + .vsx, + }), + }; + pub const pwr8 = Cpu{ + .name = "pwr8", + .llvm_name = "pwr8", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .bpermd, + .cmpb, + .crypto, + .direct_move, + .extdiv, + .fcpsgn, + .fpcvt, + .fprnd, + .fre, + .fres, + .frsqrte, + .frsqrtes, + .fsqrt, + .htm, + .icbt, + .isel, + .ldbrx, + .lfiwax, + .mfocrf, + .partword_atomics, + .popcntd, + .power8_altivec, + .power8_vector, + .recipprec, + .stfiwx, + .two_const_nr, + .vsx, + }), + }; + pub const pwr9 = Cpu{ + .name = "pwr9", + .llvm_name = "pwr9", + .features = featureSet(&[_]Feature{ + .@"64bit", + .altivec, + .bpermd, + .cmpb, + .crypto, + .direct_move, + .extdiv, + .fcpsgn, + .fpcvt, + .fprnd, + .fre, + .fres, + .frsqrte, + .frsqrtes, + .fsqrt, + .htm, + .icbt, + .isa_v30_instructions, + .isel, + .ldbrx, + .lfiwax, + .mfocrf, + .partword_atomics, + .popcntd, + .power8_altivec, + .power8_vector, + .power9_altivec, + .power9_vector, + .ppc_postra_sched, + .ppc_prera_sched, + .recipprec, + .stfiwx, + .two_const_nr, + .vectors_use_two_units, + .vsx, + }), + }; +}; + +/// All powerpc CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.@"440", + &cpu.@"450", + &cpu.@"601", + &cpu.@"602", + &cpu.@"603", + &cpu.@"603e", + &cpu.@"603ev", + &cpu.@"604", + &cpu.@"604e", + &cpu.@"620", + &cpu.@"7400", + &cpu.@"7450", + &cpu.@"750", + &cpu.@"970", + &cpu.a2, + &cpu.a2q, + &cpu.e500, + &cpu.e500mc, + &cpu.e5500, + &cpu.g3, + &cpu.g4, + &cpu.@"g4+", + &cpu.g5, + &cpu.generic, + &cpu.ppc, + &cpu.ppc32, + &cpu.ppc64, + &cpu.ppc64le, + &cpu.pwr3, + &cpu.pwr4, + &cpu.pwr5, + &cpu.pwr5x, + &cpu.pwr6, + &cpu.pwr6x, + &cpu.pwr7, + &cpu.pwr8, + &cpu.pwr9, +}; diff --git a/lib/std/target/riscv.zig b/lib/std/target/riscv.zig new file mode 100644 index 0000000000..315329306e --- /dev/null +++ b/lib/std/target/riscv.zig @@ -0,0 +1,122 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + @"64bit", + a, + c, + d, + e, + f, + m, + relax, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.@"64bit")] = .{ + .llvm_name = "64bit", + .description = "Implements RV64", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.a)] = .{ + .llvm_name = "a", + .description = "'A' (Atomic Instructions)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.c)] = .{ + .llvm_name = "c", + .description = "'C' (Compressed Instructions)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.d)] = .{ + .llvm_name = "d", + .description = "'D' (Double-Precision Floating-Point)", + .dependencies = featureSet(&[_]Feature{ + .f, + }), + }; + result[@enumToInt(Feature.e)] = .{ + .llvm_name = "e", + .description = "Implements RV32E (provides 16 rather than 32 GPRs)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.f)] = .{ + .llvm_name = "f", + .description = "'F' (Single-Precision Floating-Point)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.m)] = .{ + .llvm_name = "m", + .description = "'M' (Integer Multiplication and Division)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.relax)] = .{ + .llvm_name = "relax", + .description = "Enable Linker relaxation.", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const baseline_rv32 = Cpu{ + .name = "baseline_rv32", + .llvm_name = "generic-rv32", + .features = featureSet(&[_]Feature{ + .a, + .c, + .d, + .f, + .m, + .relax, + }), + }; + + pub const baseline_rv64 = Cpu{ + .name = "baseline_rv64", + .llvm_name = "generic-rv64", + .features = featureSet(&[_]Feature{ + .@"64bit", + .a, + .c, + .d, + .f, + .m, + .relax, + }), + }; + + pub const generic_rv32 = Cpu{ + .name = "generic_rv32", + .llvm_name = "generic-rv32", + .features = featureSet(&[_]Feature{}), + }; + + pub const generic_rv64 = Cpu{ + .name = "generic_rv64", + .llvm_name = "generic-rv64", + .features = featureSet(&[_]Feature{ + .@"64bit", + }), + }; +}; + +/// All riscv CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.baseline_rv32, + &cpu.baseline_rv64, + &cpu.generic_rv32, + &cpu.generic_rv64, +}; diff --git a/lib/std/target/sparc.zig b/lib/std/target/sparc.zig new file mode 100644 index 0000000000..923cc0732c --- /dev/null +++ b/lib/std/target/sparc.zig @@ -0,0 +1,495 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + deprecated_v8, + detectroundchange, + fixallfdivsqrt, + hard_quad_float, + hasleoncasa, + hasumacsmac, + insertnopload, + leon, + leoncyclecounter, + leonpwrpsr, + no_fmuls, + no_fsmuld, + popc, + soft_float, + soft_mul_div, + v9, + vis, + vis2, + vis3, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.deprecated_v8)] = .{ + .llvm_name = "deprecated-v8", + .description = "Enable deprecated V8 instructions in V9 mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.detectroundchange)] = .{ + .llvm_name = "detectroundchange", + .description = "LEON3 erratum detection: Detects any rounding mode change request: use only the round-to-nearest rounding mode", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fixallfdivsqrt)] = .{ + .llvm_name = "fixallfdivsqrt", + .description = "LEON erratum fix: Fix FDIVS/FDIVD/FSQRTS/FSQRTD instructions with NOPs and floating-point store", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.hard_quad_float)] = .{ + .llvm_name = "hard-quad-float", + .description = "Enable quad-word floating point instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.hasleoncasa)] = .{ + .llvm_name = "hasleoncasa", + .description = "Enable CASA instruction for LEON3 and LEON4 processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.hasumacsmac)] = .{ + .llvm_name = "hasumacsmac", + .description = "Enable UMAC and SMAC for LEON3 and LEON4 processors", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.insertnopload)] = .{ + .llvm_name = "insertnopload", + .description = "LEON3 erratum fix: Insert a NOP instruction after every single-cycle load instruction when the next instruction is another load/store instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.leon)] = .{ + .llvm_name = "leon", + .description = "Enable LEON extensions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.leoncyclecounter)] = .{ + .llvm_name = "leoncyclecounter", + .description = "Use the Leon cycle counter register", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.leonpwrpsr)] = .{ + .llvm_name = "leonpwrpsr", + .description = "Enable the PWRPSR instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.no_fmuls)] = .{ + .llvm_name = "no-fmuls", + .description = "Disable the fmuls instruction.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.no_fsmuld)] = .{ + .llvm_name = "no-fsmuld", + .description = "Disable the fsmuld instruction.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.popc)] = .{ + .llvm_name = "popc", + .description = "Use the popc (population count) instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.soft_float)] = .{ + .llvm_name = "soft-float", + .description = "Use software emulation for floating point", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.soft_mul_div)] = .{ + .llvm_name = "soft-mul-div", + .description = "Use software emulation for integer multiply and divide", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v9)] = .{ + .llvm_name = "v9", + .description = "Enable SPARC-V9 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vis)] = .{ + .llvm_name = "vis", + .description = "Enable UltraSPARC Visual Instruction Set extensions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vis2)] = .{ + .llvm_name = "vis2", + .description = "Enable Visual Instruction Set extensions II", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vis3)] = .{ + .llvm_name = "vis3", + .description = "Enable Visual Instruction Set extensions III", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const at697e = Cpu{ + .name = "at697e", + .llvm_name = "at697e", + .features = featureSet(&[_]Feature{ + .insertnopload, + .leon, + }), + }; + pub const at697f = Cpu{ + .name = "at697f", + .llvm_name = "at697f", + .features = featureSet(&[_]Feature{ + .insertnopload, + .leon, + }), + }; + pub const f934 = Cpu{ + .name = "f934", + .llvm_name = "f934", + .features = featureSet(&[_]Feature{}), + }; + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{}), + }; + pub const gr712rc = Cpu{ + .name = "gr712rc", + .llvm_name = "gr712rc", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const gr740 = Cpu{ + .name = "gr740", + .llvm_name = "gr740", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .hasumacsmac, + .leon, + .leoncyclecounter, + .leonpwrpsr, + }), + }; + pub const hypersparc = Cpu{ + .name = "hypersparc", + .llvm_name = "hypersparc", + .features = featureSet(&[_]Feature{}), + }; + pub const leon2 = Cpu{ + .name = "leon2", + .llvm_name = "leon2", + .features = featureSet(&[_]Feature{ + .leon, + }), + }; + pub const leon3 = Cpu{ + .name = "leon3", + .llvm_name = "leon3", + .features = featureSet(&[_]Feature{ + .hasumacsmac, + .leon, + }), + }; + pub const leon4 = Cpu{ + .name = "leon4", + .llvm_name = "leon4", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .hasumacsmac, + .leon, + }), + }; + pub const ma2080 = Cpu{ + .name = "ma2080", + .llvm_name = "ma2080", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const ma2085 = Cpu{ + .name = "ma2085", + .llvm_name = "ma2085", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const ma2100 = Cpu{ + .name = "ma2100", + .llvm_name = "ma2100", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const ma2150 = Cpu{ + .name = "ma2150", + .llvm_name = "ma2150", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const ma2155 = Cpu{ + .name = "ma2155", + .llvm_name = "ma2155", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const ma2450 = Cpu{ + .name = "ma2450", + .llvm_name = "ma2450", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const ma2455 = Cpu{ + .name = "ma2455", + .llvm_name = "ma2455", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const ma2480 = Cpu{ + .name = "ma2480", + .llvm_name = "ma2480", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const ma2485 = Cpu{ + .name = "ma2485", + .llvm_name = "ma2485", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const ma2x5x = Cpu{ + .name = "ma2x5x", + .llvm_name = "ma2x5x", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const ma2x8x = Cpu{ + .name = "ma2x8x", + .llvm_name = "ma2x8x", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const myriad2 = Cpu{ + .name = "myriad2", + .llvm_name = "myriad2", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const myriad2_1 = Cpu{ + .name = "myriad2_1", + .llvm_name = "myriad2.1", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const myriad2_2 = Cpu{ + .name = "myriad2_2", + .llvm_name = "myriad2.2", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const myriad2_3 = Cpu{ + .name = "myriad2_3", + .llvm_name = "myriad2.3", + .features = featureSet(&[_]Feature{ + .hasleoncasa, + .leon, + }), + }; + pub const niagara = Cpu{ + .name = "niagara", + .llvm_name = "niagara", + .features = featureSet(&[_]Feature{ + .deprecated_v8, + .v9, + .vis, + .vis2, + }), + }; + pub const niagara2 = Cpu{ + .name = "niagara2", + .llvm_name = "niagara2", + .features = featureSet(&[_]Feature{ + .deprecated_v8, + .popc, + .v9, + .vis, + .vis2, + }), + }; + pub const niagara3 = Cpu{ + .name = "niagara3", + .llvm_name = "niagara3", + .features = featureSet(&[_]Feature{ + .deprecated_v8, + .popc, + .v9, + .vis, + .vis2, + }), + }; + pub const niagara4 = Cpu{ + .name = "niagara4", + .llvm_name = "niagara4", + .features = featureSet(&[_]Feature{ + .deprecated_v8, + .popc, + .v9, + .vis, + .vis2, + .vis3, + }), + }; + pub const sparclet = Cpu{ + .name = "sparclet", + .llvm_name = "sparclet", + .features = featureSet(&[_]Feature{}), + }; + pub const sparclite = Cpu{ + .name = "sparclite", + .llvm_name = "sparclite", + .features = featureSet(&[_]Feature{}), + }; + pub const sparclite86x = Cpu{ + .name = "sparclite86x", + .llvm_name = "sparclite86x", + .features = featureSet(&[_]Feature{}), + }; + pub const supersparc = Cpu{ + .name = "supersparc", + .llvm_name = "supersparc", + .features = featureSet(&[_]Feature{}), + }; + pub const tsc701 = Cpu{ + .name = "tsc701", + .llvm_name = "tsc701", + .features = featureSet(&[_]Feature{}), + }; + pub const ultrasparc = Cpu{ + .name = "ultrasparc", + .llvm_name = "ultrasparc", + .features = featureSet(&[_]Feature{ + .deprecated_v8, + .v9, + .vis, + }), + }; + pub const ultrasparc3 = Cpu{ + .name = "ultrasparc3", + .llvm_name = "ultrasparc3", + .features = featureSet(&[_]Feature{ + .deprecated_v8, + .v9, + .vis, + .vis2, + }), + }; + pub const ut699 = Cpu{ + .name = "ut699", + .llvm_name = "ut699", + .features = featureSet(&[_]Feature{ + .fixallfdivsqrt, + .insertnopload, + .leon, + .no_fmuls, + .no_fsmuld, + }), + }; + pub const v7 = Cpu{ + .name = "v7", + .llvm_name = "v7", + .features = featureSet(&[_]Feature{ + .no_fsmuld, + .soft_mul_div, + }), + }; + pub const v8 = Cpu{ + .name = "v8", + .llvm_name = "v8", + .features = featureSet(&[_]Feature{}), + }; + pub const v9 = Cpu{ + .name = "v9", + .llvm_name = "v9", + .features = featureSet(&[_]Feature{ + .v9, + }), + }; +}; + +/// All sparc CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.at697e, + &cpu.at697f, + &cpu.f934, + &cpu.generic, + &cpu.gr712rc, + &cpu.gr740, + &cpu.hypersparc, + &cpu.leon2, + &cpu.leon3, + &cpu.leon4, + &cpu.ma2080, + &cpu.ma2085, + &cpu.ma2100, + &cpu.ma2150, + &cpu.ma2155, + &cpu.ma2450, + &cpu.ma2455, + &cpu.ma2480, + &cpu.ma2485, + &cpu.ma2x5x, + &cpu.ma2x8x, + &cpu.myriad2, + &cpu.myriad2_1, + &cpu.myriad2_2, + &cpu.myriad2_3, + &cpu.niagara, + &cpu.niagara2, + &cpu.niagara3, + &cpu.niagara4, + &cpu.sparclet, + &cpu.sparclite, + &cpu.sparclite86x, + &cpu.supersparc, + &cpu.tsc701, + &cpu.ultrasparc, + &cpu.ultrasparc3, + &cpu.ut699, + &cpu.v7, + &cpu.v8, + &cpu.v9, +}; diff --git a/lib/std/target/systemz.zig b/lib/std/target/systemz.zig new file mode 100644 index 0000000000..c924af6e70 --- /dev/null +++ b/lib/std/target/systemz.zig @@ -0,0 +1,510 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + deflate_conversion, + dfp_packed_conversion, + dfp_zoned_conversion, + distinct_ops, + enhanced_dat_2, + enhanced_sort, + execution_hint, + fast_serialization, + fp_extension, + guarded_storage, + high_word, + insert_reference_bits_multiple, + interlocked_access1, + load_and_trap, + load_and_zero_rightmost_byte, + load_store_on_cond, + load_store_on_cond_2, + message_security_assist_extension3, + message_security_assist_extension4, + message_security_assist_extension5, + message_security_assist_extension7, + message_security_assist_extension8, + message_security_assist_extension9, + miscellaneous_extensions, + miscellaneous_extensions_2, + miscellaneous_extensions_3, + population_count, + processor_assist, + reset_reference_bits_multiple, + transactional_execution, + vector, + vector_enhancements_1, + vector_enhancements_2, + vector_packed_decimal, + vector_packed_decimal_enhancement, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.deflate_conversion)] = .{ + .llvm_name = "deflate-conversion", + .description = "Assume that the deflate-conversion facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dfp_packed_conversion)] = .{ + .llvm_name = "dfp-packed-conversion", + .description = "Assume that the DFP packed-conversion facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.dfp_zoned_conversion)] = .{ + .llvm_name = "dfp-zoned-conversion", + .description = "Assume that the DFP zoned-conversion facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.distinct_ops)] = .{ + .llvm_name = "distinct-ops", + .description = "Assume that the distinct-operands facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.enhanced_dat_2)] = .{ + .llvm_name = "enhanced-dat-2", + .description = "Assume that the enhanced-DAT facility 2 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.enhanced_sort)] = .{ + .llvm_name = "enhanced-sort", + .description = "Assume that the enhanced-sort facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.execution_hint)] = .{ + .llvm_name = "execution-hint", + .description = "Assume that the execution-hint facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_serialization)] = .{ + .llvm_name = "fast-serialization", + .description = "Assume that the fast-serialization facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fp_extension)] = .{ + .llvm_name = "fp-extension", + .description = "Assume that the floating-point extension facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.guarded_storage)] = .{ + .llvm_name = "guarded-storage", + .description = "Assume that the guarded-storage facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.high_word)] = .{ + .llvm_name = "high-word", + .description = "Assume that the high-word facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.insert_reference_bits_multiple)] = .{ + .llvm_name = "insert-reference-bits-multiple", + .description = "Assume that the insert-reference-bits-multiple facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.interlocked_access1)] = .{ + .llvm_name = "interlocked-access1", + .description = "Assume that interlocked-access facility 1 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.load_and_trap)] = .{ + .llvm_name = "load-and-trap", + .description = "Assume that the load-and-trap facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.load_and_zero_rightmost_byte)] = .{ + .llvm_name = "load-and-zero-rightmost-byte", + .description = "Assume that the load-and-zero-rightmost-byte facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.load_store_on_cond)] = .{ + .llvm_name = "load-store-on-cond", + .description = "Assume that the load/store-on-condition facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.load_store_on_cond_2)] = .{ + .llvm_name = "load-store-on-cond-2", + .description = "Assume that the load/store-on-condition facility 2 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.message_security_assist_extension3)] = .{ + .llvm_name = "message-security-assist-extension3", + .description = "Assume that the message-security-assist extension facility 3 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.message_security_assist_extension4)] = .{ + .llvm_name = "message-security-assist-extension4", + .description = "Assume that the message-security-assist extension facility 4 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.message_security_assist_extension5)] = .{ + .llvm_name = "message-security-assist-extension5", + .description = "Assume that the message-security-assist extension facility 5 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.message_security_assist_extension7)] = .{ + .llvm_name = "message-security-assist-extension7", + .description = "Assume that the message-security-assist extension facility 7 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.message_security_assist_extension8)] = .{ + .llvm_name = "message-security-assist-extension8", + .description = "Assume that the message-security-assist extension facility 8 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.message_security_assist_extension9)] = .{ + .llvm_name = "message-security-assist-extension9", + .description = "Assume that the message-security-assist extension facility 9 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.miscellaneous_extensions)] = .{ + .llvm_name = "miscellaneous-extensions", + .description = "Assume that the miscellaneous-extensions facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.miscellaneous_extensions_2)] = .{ + .llvm_name = "miscellaneous-extensions-2", + .description = "Assume that the miscellaneous-extensions facility 2 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.miscellaneous_extensions_3)] = .{ + .llvm_name = "miscellaneous-extensions-3", + .description = "Assume that the miscellaneous-extensions facility 3 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.population_count)] = .{ + .llvm_name = "population-count", + .description = "Assume that the population-count facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.processor_assist)] = .{ + .llvm_name = "processor-assist", + .description = "Assume that the processor-assist facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.reset_reference_bits_multiple)] = .{ + .llvm_name = "reset-reference-bits-multiple", + .description = "Assume that the reset-reference-bits-multiple facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.transactional_execution)] = .{ + .llvm_name = "transactional-execution", + .description = "Assume that the transactional-execution facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vector)] = .{ + .llvm_name = "vector", + .description = "Assume that the vectory facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vector_enhancements_1)] = .{ + .llvm_name = "vector-enhancements-1", + .description = "Assume that the vector enhancements facility 1 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vector_enhancements_2)] = .{ + .llvm_name = "vector-enhancements-2", + .description = "Assume that the vector enhancements facility 2 is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vector_packed_decimal)] = .{ + .llvm_name = "vector-packed-decimal", + .description = "Assume that the vector packed decimal facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vector_packed_decimal_enhancement)] = .{ + .llvm_name = "vector-packed-decimal-enhancement", + .description = "Assume that the vector packed decimal enhancement facility is installed", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const arch10 = Cpu{ + .name = "arch10", + .llvm_name = "arch10", + .features = featureSet(&[_]Feature{ + .dfp_zoned_conversion, + .distinct_ops, + .enhanced_dat_2, + .execution_hint, + .fast_serialization, + .fp_extension, + .high_word, + .interlocked_access1, + .load_and_trap, + .load_store_on_cond, + .message_security_assist_extension3, + .message_security_assist_extension4, + .miscellaneous_extensions, + .population_count, + .processor_assist, + .reset_reference_bits_multiple, + .transactional_execution, + }), + }; + pub const arch11 = Cpu{ + .name = "arch11", + .llvm_name = "arch11", + .features = featureSet(&[_]Feature{ + .dfp_packed_conversion, + .dfp_zoned_conversion, + .distinct_ops, + .enhanced_dat_2, + .execution_hint, + .fast_serialization, + .fp_extension, + .high_word, + .interlocked_access1, + .load_and_trap, + .load_and_zero_rightmost_byte, + .load_store_on_cond, + .load_store_on_cond_2, + .message_security_assist_extension3, + .message_security_assist_extension4, + .message_security_assist_extension5, + .miscellaneous_extensions, + .population_count, + .processor_assist, + .reset_reference_bits_multiple, + .transactional_execution, + .vector, + }), + }; + pub const arch12 = Cpu{ + .name = "arch12", + .llvm_name = "arch12", + .features = featureSet(&[_]Feature{ + .dfp_packed_conversion, + .dfp_zoned_conversion, + .distinct_ops, + .enhanced_dat_2, + .execution_hint, + .fast_serialization, + .fp_extension, + .guarded_storage, + .high_word, + .insert_reference_bits_multiple, + .interlocked_access1, + .load_and_trap, + .load_and_zero_rightmost_byte, + .load_store_on_cond, + .load_store_on_cond_2, + .message_security_assist_extension3, + .message_security_assist_extension4, + .message_security_assist_extension5, + .message_security_assist_extension7, + .message_security_assist_extension8, + .miscellaneous_extensions, + .miscellaneous_extensions_2, + .population_count, + .processor_assist, + .reset_reference_bits_multiple, + .transactional_execution, + .vector, + .vector_enhancements_1, + .vector_packed_decimal, + }), + }; + pub const arch13 = Cpu{ + .name = "arch13", + .llvm_name = "arch13", + .features = featureSet(&[_]Feature{ + .deflate_conversion, + .dfp_packed_conversion, + .dfp_zoned_conversion, + .distinct_ops, + .enhanced_dat_2, + .enhanced_sort, + .execution_hint, + .fast_serialization, + .fp_extension, + .guarded_storage, + .high_word, + .insert_reference_bits_multiple, + .interlocked_access1, + .load_and_trap, + .load_and_zero_rightmost_byte, + .load_store_on_cond, + .load_store_on_cond_2, + .message_security_assist_extension3, + .message_security_assist_extension4, + .message_security_assist_extension5, + .message_security_assist_extension7, + .message_security_assist_extension8, + .message_security_assist_extension9, + .miscellaneous_extensions, + .miscellaneous_extensions_2, + .miscellaneous_extensions_3, + .population_count, + .processor_assist, + .reset_reference_bits_multiple, + .transactional_execution, + .vector, + .vector_enhancements_1, + .vector_enhancements_2, + .vector_packed_decimal, + .vector_packed_decimal_enhancement, + }), + }; + pub const arch8 = Cpu{ + .name = "arch8", + .llvm_name = "arch8", + .features = featureSet(&[_]Feature{}), + }; + pub const arch9 = Cpu{ + .name = "arch9", + .llvm_name = "arch9", + .features = featureSet(&[_]Feature{ + .distinct_ops, + .fast_serialization, + .fp_extension, + .high_word, + .interlocked_access1, + .load_store_on_cond, + .message_security_assist_extension3, + .message_security_assist_extension4, + .population_count, + .reset_reference_bits_multiple, + }), + }; + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{}), + }; + pub const z10 = Cpu{ + .name = "z10", + .llvm_name = "z10", + .features = featureSet(&[_]Feature{}), + }; + pub const z13 = Cpu{ + .name = "z13", + .llvm_name = "z13", + .features = featureSet(&[_]Feature{ + .dfp_packed_conversion, + .dfp_zoned_conversion, + .distinct_ops, + .enhanced_dat_2, + .execution_hint, + .fast_serialization, + .fp_extension, + .high_word, + .interlocked_access1, + .load_and_trap, + .load_and_zero_rightmost_byte, + .load_store_on_cond, + .load_store_on_cond_2, + .message_security_assist_extension3, + .message_security_assist_extension4, + .message_security_assist_extension5, + .miscellaneous_extensions, + .population_count, + .processor_assist, + .reset_reference_bits_multiple, + .transactional_execution, + .vector, + }), + }; + pub const z14 = Cpu{ + .name = "z14", + .llvm_name = "z14", + .features = featureSet(&[_]Feature{ + .dfp_packed_conversion, + .dfp_zoned_conversion, + .distinct_ops, + .enhanced_dat_2, + .execution_hint, + .fast_serialization, + .fp_extension, + .guarded_storage, + .high_word, + .insert_reference_bits_multiple, + .interlocked_access1, + .load_and_trap, + .load_and_zero_rightmost_byte, + .load_store_on_cond, + .load_store_on_cond_2, + .message_security_assist_extension3, + .message_security_assist_extension4, + .message_security_assist_extension5, + .message_security_assist_extension7, + .message_security_assist_extension8, + .miscellaneous_extensions, + .miscellaneous_extensions_2, + .population_count, + .processor_assist, + .reset_reference_bits_multiple, + .transactional_execution, + .vector, + .vector_enhancements_1, + .vector_packed_decimal, + }), + }; + pub const z196 = Cpu{ + .name = "z196", + .llvm_name = "z196", + .features = featureSet(&[_]Feature{ + .distinct_ops, + .fast_serialization, + .fp_extension, + .high_word, + .interlocked_access1, + .load_store_on_cond, + .message_security_assist_extension3, + .message_security_assist_extension4, + .population_count, + .reset_reference_bits_multiple, + }), + }; + pub const zEC12 = Cpu{ + .name = "zEC12", + .llvm_name = "zEC12", + .features = featureSet(&[_]Feature{ + .dfp_zoned_conversion, + .distinct_ops, + .enhanced_dat_2, + .execution_hint, + .fast_serialization, + .fp_extension, + .high_word, + .interlocked_access1, + .load_and_trap, + .load_store_on_cond, + .message_security_assist_extension3, + .message_security_assist_extension4, + .miscellaneous_extensions, + .population_count, + .processor_assist, + .reset_reference_bits_multiple, + .transactional_execution, + }), + }; +}; + +/// All systemz CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.arch10, + &cpu.arch11, + &cpu.arch12, + &cpu.arch13, + &cpu.arch8, + &cpu.arch9, + &cpu.generic, + &cpu.z10, + &cpu.z13, + &cpu.z14, + &cpu.z196, + &cpu.zEC12, +}; diff --git a/lib/std/target/wasm.zig b/lib/std/target/wasm.zig new file mode 100644 index 0000000000..6d79bbb282 --- /dev/null +++ b/lib/std/target/wasm.zig @@ -0,0 +1,114 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + atomics, + bulk_memory, + exception_handling, + multivalue, + mutable_globals, + nontrapping_fptoint, + sign_ext, + simd128, + tail_call, + unimplemented_simd128, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.atomics)] = .{ + .llvm_name = "atomics", + .description = "Enable Atomics", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.bulk_memory)] = .{ + .llvm_name = "bulk-memory", + .description = "Enable bulk memory operations", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.exception_handling)] = .{ + .llvm_name = "exception-handling", + .description = "Enable Wasm exception handling", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.multivalue)] = .{ + .llvm_name = "multivalue", + .description = "Enable multivalue blocks, instructions, and functions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mutable_globals)] = .{ + .llvm_name = "mutable-globals", + .description = "Enable mutable globals", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.nontrapping_fptoint)] = .{ + .llvm_name = "nontrapping-fptoint", + .description = "Enable non-trapping float-to-int conversion operators", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sign_ext)] = .{ + .llvm_name = "sign-ext", + .description = "Enable sign extension operators", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.simd128)] = .{ + .llvm_name = "simd128", + .description = "Enable 128-bit SIMD", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.tail_call)] = .{ + .llvm_name = "tail-call", + .description = "Enable tail call instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.unimplemented_simd128)] = .{ + .llvm_name = "unimplemented-simd128", + .description = "Enable 128-bit SIMD not yet implemented in engines", + .dependencies = featureSet(&[_]Feature{ + .simd128, + }), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const bleeding_edge = Cpu{ + .name = "bleeding_edge", + .llvm_name = "bleeding-edge", + .features = featureSet(&[_]Feature{ + .atomics, + .mutable_globals, + .nontrapping_fptoint, + .sign_ext, + .simd128, + }), + }; + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{}), + }; + pub const mvp = Cpu{ + .name = "mvp", + .llvm_name = "mvp", + .features = featureSet(&[_]Feature{}), + }; +}; + +/// All wasm CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.bleeding_edge, + &cpu.generic, + &cpu.mvp, +}; diff --git a/lib/std/target/x86.zig b/lib/std/target/x86.zig new file mode 100644 index 0000000000..3c2e306e79 --- /dev/null +++ b/lib/std/target/x86.zig @@ -0,0 +1,2859 @@ +const std = @import("../std.zig"); +const Cpu = std.Target.Cpu; + +pub const Feature = enum { + @"3dnow", + @"3dnowa", + @"64bit", + adx, + aes, + avx, + avx2, + avx512bf16, + avx512bitalg, + avx512bw, + avx512cd, + avx512dq, + avx512er, + avx512f, + avx512ifma, + avx512pf, + avx512vbmi, + avx512vbmi2, + avx512vl, + avx512vnni, + avx512vp2intersect, + avx512vpopcntdq, + bmi, + bmi2, + branchfusion, + cldemote, + clflushopt, + clwb, + clzero, + cmov, + cx16, + cx8, + enqcmd, + ermsb, + f16c, + false_deps_lzcnt_tzcnt, + false_deps_popcnt, + fast_11bytenop, + fast_15bytenop, + fast_bextr, + fast_gather, + fast_hops, + fast_lzcnt, + fast_partial_ymm_or_zmm_write, + fast_scalar_fsqrt, + fast_scalar_shift_masks, + fast_shld_rotate, + fast_variable_shuffle, + fast_vector_fsqrt, + fast_vector_shift_masks, + fma, + fma4, + fsgsbase, + fxsr, + gfni, + idivl_to_divb, + idivq_to_divl, + invpcid, + lea_sp, + lea_uses_ag, + lwp, + lzcnt, + macrofusion, + merge_to_threeway_branch, + mmx, + movbe, + movdir64b, + movdiri, + mpx, + mwaitx, + nopl, + pad_short_functions, + pclmul, + pconfig, + pku, + popcnt, + prefer_256_bit, + prefetchwt1, + prfchw, + ptwrite, + rdpid, + rdrnd, + rdseed, + retpoline, + retpoline_external_thunk, + retpoline_indirect_branches, + retpoline_indirect_calls, + rtm, + sahf, + sgx, + sha, + shstk, + slow_3ops_lea, + slow_incdec, + slow_lea, + slow_pmaddwd, + slow_pmulld, + slow_shld, + slow_two_mem_ops, + slow_unaligned_mem_16, + slow_unaligned_mem_32, + soft_float, + sse, + sse_unaligned_mem, + sse2, + sse3, + sse4_1, + sse4_2, + sse4a, + ssse3, + tbm, + vaes, + vpclmulqdq, + waitpkg, + wbnoinvd, + x87, + xop, + xsave, + xsavec, + xsaveopt, + xsaves, +}; + +pub usingnamespace Cpu.Feature.feature_set_fns(Feature); + +pub const all_features = blk: { + const len = @typeInfo(Feature).Enum.fields.len; + std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); + var result: [len]Cpu.Feature = undefined; + result[@enumToInt(Feature.@"3dnow")] = .{ + .llvm_name = "3dnow", + .description = "Enable 3DNow! instructions", + .dependencies = featureSet(&[_]Feature{ + .mmx, + }), + }; + result[@enumToInt(Feature.@"3dnowa")] = .{ + .llvm_name = "3dnowa", + .description = "Enable 3DNow! Athlon instructions", + .dependencies = featureSet(&[_]Feature{ + .@"3dnow", + }), + }; + result[@enumToInt(Feature.@"64bit")] = .{ + .llvm_name = "64bit", + .description = "Support 64-bit instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.adx)] = .{ + .llvm_name = "adx", + .description = "Support ADX instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.aes)] = .{ + .llvm_name = "aes", + .description = "Enable AES instructions", + .dependencies = featureSet(&[_]Feature{ + .sse2, + }), + }; + result[@enumToInt(Feature.avx)] = .{ + .llvm_name = "avx", + .description = "Enable AVX instructions", + .dependencies = featureSet(&[_]Feature{ + .sse4_2, + }), + }; + result[@enumToInt(Feature.avx2)] = .{ + .llvm_name = "avx2", + .description = "Enable AVX2 instructions", + .dependencies = featureSet(&[_]Feature{ + .avx, + }), + }; + result[@enumToInt(Feature.avx512bf16)] = .{ + .llvm_name = "avx512bf16", + .description = "Support bfloat16 floating point", + .dependencies = featureSet(&[_]Feature{ + .avx512bw, + }), + }; + result[@enumToInt(Feature.avx512bitalg)] = .{ + .llvm_name = "avx512bitalg", + .description = "Enable AVX-512 Bit Algorithms", + .dependencies = featureSet(&[_]Feature{ + .avx512bw, + }), + }; + result[@enumToInt(Feature.avx512bw)] = .{ + .llvm_name = "avx512bw", + .description = "Enable AVX-512 Byte and Word Instructions", + .dependencies = featureSet(&[_]Feature{ + .avx512f, + }), + }; + result[@enumToInt(Feature.avx512cd)] = .{ + .llvm_name = "avx512cd", + .description = "Enable AVX-512 Conflict Detection Instructions", + .dependencies = featureSet(&[_]Feature{ + .avx512f, + }), + }; + result[@enumToInt(Feature.avx512dq)] = .{ + .llvm_name = "avx512dq", + .description = "Enable AVX-512 Doubleword and Quadword Instructions", + .dependencies = featureSet(&[_]Feature{ + .avx512f, + }), + }; + result[@enumToInt(Feature.avx512er)] = .{ + .llvm_name = "avx512er", + .description = "Enable AVX-512 Exponential and Reciprocal Instructions", + .dependencies = featureSet(&[_]Feature{ + .avx512f, + }), + }; + result[@enumToInt(Feature.avx512f)] = .{ + .llvm_name = "avx512f", + .description = "Enable AVX-512 instructions", + .dependencies = featureSet(&[_]Feature{ + .avx2, + .f16c, + .fma, + }), + }; + result[@enumToInt(Feature.avx512ifma)] = .{ + .llvm_name = "avx512ifma", + .description = "Enable AVX-512 Integer Fused Multiple-Add", + .dependencies = featureSet(&[_]Feature{ + .avx512f, + }), + }; + result[@enumToInt(Feature.avx512pf)] = .{ + .llvm_name = "avx512pf", + .description = "Enable AVX-512 PreFetch Instructions", + .dependencies = featureSet(&[_]Feature{ + .avx512f, + }), + }; + result[@enumToInt(Feature.avx512vbmi)] = .{ + .llvm_name = "avx512vbmi", + .description = "Enable AVX-512 Vector Byte Manipulation Instructions", + .dependencies = featureSet(&[_]Feature{ + .avx512bw, + }), + }; + result[@enumToInt(Feature.avx512vbmi2)] = .{ + .llvm_name = "avx512vbmi2", + .description = "Enable AVX-512 further Vector Byte Manipulation Instructions", + .dependencies = featureSet(&[_]Feature{ + .avx512bw, + }), + }; + result[@enumToInt(Feature.avx512vl)] = .{ + .llvm_name = "avx512vl", + .description = "Enable AVX-512 Vector Length eXtensions", + .dependencies = featureSet(&[_]Feature{ + .avx512f, + }), + }; + result[@enumToInt(Feature.avx512vnni)] = .{ + .llvm_name = "avx512vnni", + .description = "Enable AVX-512 Vector Neural Network Instructions", + .dependencies = featureSet(&[_]Feature{ + .avx512f, + }), + }; + result[@enumToInt(Feature.avx512vp2intersect)] = .{ + .llvm_name = "avx512vp2intersect", + .description = "Enable AVX-512 vp2intersect", + .dependencies = featureSet(&[_]Feature{ + .avx512f, + }), + }; + result[@enumToInt(Feature.avx512vpopcntdq)] = .{ + .llvm_name = "avx512vpopcntdq", + .description = "Enable AVX-512 Population Count Instructions", + .dependencies = featureSet(&[_]Feature{ + .avx512f, + }), + }; + result[@enumToInt(Feature.bmi)] = .{ + .llvm_name = "bmi", + .description = "Support BMI instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.bmi2)] = .{ + .llvm_name = "bmi2", + .description = "Support BMI2 instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.branchfusion)] = .{ + .llvm_name = "branchfusion", + .description = "CMP/TEST can be fused with conditional branches", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.cldemote)] = .{ + .llvm_name = "cldemote", + .description = "Enable Cache Demote", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.clflushopt)] = .{ + .llvm_name = "clflushopt", + .description = "Flush A Cache Line Optimized", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.clwb)] = .{ + .llvm_name = "clwb", + .description = "Cache Line Write Back", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.clzero)] = .{ + .llvm_name = "clzero", + .description = "Enable Cache Line Zero", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.cmov)] = .{ + .llvm_name = "cmov", + .description = "Enable conditional move instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.cx16)] = .{ + .llvm_name = "cx16", + .description = "64-bit with cmpxchg16b", + .dependencies = featureSet(&[_]Feature{ + .cx8, + }), + }; + result[@enumToInt(Feature.cx8)] = .{ + .llvm_name = "cx8", + .description = "Support CMPXCHG8B instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.enqcmd)] = .{ + .llvm_name = "enqcmd", + .description = "Has ENQCMD instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ermsb)] = .{ + .llvm_name = "ermsb", + .description = "REP MOVS/STOS are fast", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.f16c)] = .{ + .llvm_name = "f16c", + .description = "Support 16-bit floating point conversion instructions", + .dependencies = featureSet(&[_]Feature{ + .avx, + }), + }; + result[@enumToInt(Feature.false_deps_lzcnt_tzcnt)] = .{ + .llvm_name = "false-deps-lzcnt-tzcnt", + .description = "LZCNT/TZCNT have a false dependency on dest register", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.false_deps_popcnt)] = .{ + .llvm_name = "false-deps-popcnt", + .description = "POPCNT has a false dependency on dest register", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_11bytenop)] = .{ + .llvm_name = "fast-11bytenop", + .description = "Target can quickly decode up to 11 byte NOPs", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_15bytenop)] = .{ + .llvm_name = "fast-15bytenop", + .description = "Target can quickly decode up to 15 byte NOPs", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_bextr)] = .{ + .llvm_name = "fast-bextr", + .description = "Indicates that the BEXTR instruction is implemented as a single uop with good throughput", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_gather)] = .{ + .llvm_name = "fast-gather", + .description = "Indicates if gather is reasonably fast", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_hops)] = .{ + .llvm_name = "fast-hops", + .description = "Prefer horizontal vector math instructions (haddp, phsub, etc.) over normal vector instructions with shuffles", + .dependencies = featureSet(&[_]Feature{ + .sse3, + }), + }; + result[@enumToInt(Feature.fast_lzcnt)] = .{ + .llvm_name = "fast-lzcnt", + .description = "LZCNT instructions are as fast as most simple integer ops", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_partial_ymm_or_zmm_write)] = .{ + .llvm_name = "fast-partial-ymm-or-zmm-write", + .description = "Partial writes to YMM/ZMM registers are fast", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_scalar_fsqrt)] = .{ + .llvm_name = "fast-scalar-fsqrt", + .description = "Scalar SQRT is fast (disable Newton-Raphson)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_scalar_shift_masks)] = .{ + .llvm_name = "fast-scalar-shift-masks", + .description = "Prefer a left/right scalar logical shift pair over a shift+and pair", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_shld_rotate)] = .{ + .llvm_name = "fast-shld-rotate", + .description = "SHLD can be used as a faster rotate", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_variable_shuffle)] = .{ + .llvm_name = "fast-variable-shuffle", + .description = "Shuffles with variable masks are fast", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_vector_fsqrt)] = .{ + .llvm_name = "fast-vector-fsqrt", + .description = "Vector SQRT is fast (disable Newton-Raphson)", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fast_vector_shift_masks)] = .{ + .llvm_name = "fast-vector-shift-masks", + .description = "Prefer a left/right vector logical shift pair over a shift+and pair", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fma)] = .{ + .llvm_name = "fma", + .description = "Enable three-operand fused multiple-add", + .dependencies = featureSet(&[_]Feature{ + .avx, + }), + }; + result[@enumToInt(Feature.fma4)] = .{ + .llvm_name = "fma4", + .description = "Enable four-operand fused multiple-add", + .dependencies = featureSet(&[_]Feature{ + .avx, + .sse4a, + }), + }; + result[@enumToInt(Feature.fsgsbase)] = .{ + .llvm_name = "fsgsbase", + .description = "Support FS/GS Base instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fxsr)] = .{ + .llvm_name = "fxsr", + .description = "Support fxsave/fxrestore instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.gfni)] = .{ + .llvm_name = "gfni", + .description = "Enable Galois Field Arithmetic Instructions", + .dependencies = featureSet(&[_]Feature{ + .sse2, + }), + }; + result[@enumToInt(Feature.idivl_to_divb)] = .{ + .llvm_name = "idivl-to-divb", + .description = "Use 8-bit divide for positive values less than 256", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.idivq_to_divl)] = .{ + .llvm_name = "idivq-to-divl", + .description = "Use 32-bit divide for positive values less than 2^32", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.invpcid)] = .{ + .llvm_name = "invpcid", + .description = "Invalidate Process-Context Identifier", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lea_sp)] = .{ + .llvm_name = "lea-sp", + .description = "Use LEA for adjusting the stack pointer", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lea_uses_ag)] = .{ + .llvm_name = "lea-uses-ag", + .description = "LEA instruction needs inputs at AG stage", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lwp)] = .{ + .llvm_name = "lwp", + .description = "Enable LWP instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.lzcnt)] = .{ + .llvm_name = "lzcnt", + .description = "Support LZCNT instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.macrofusion)] = .{ + .llvm_name = "macrofusion", + .description = "Various instructions can be fused with conditional branches", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.merge_to_threeway_branch)] = .{ + .llvm_name = "merge-to-threeway-branch", + .description = "Merge branches to a three-way conditional branch", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mmx)] = .{ + .llvm_name = "mmx", + .description = "Enable MMX instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.movbe)] = .{ + .llvm_name = "movbe", + .description = "Support MOVBE instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.movdir64b)] = .{ + .llvm_name = "movdir64b", + .description = "Support movdir64b instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.movdiri)] = .{ + .llvm_name = "movdiri", + .description = "Support movdiri instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mpx)] = .{ + .llvm_name = "mpx", + .description = "Support MPX instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.mwaitx)] = .{ + .llvm_name = "mwaitx", + .description = "Enable MONITORX/MWAITX timer functionality", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.nopl)] = .{ + .llvm_name = "nopl", + .description = "Enable NOPL instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.pad_short_functions)] = .{ + .llvm_name = "pad-short-functions", + .description = "Pad short functions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.pclmul)] = .{ + .llvm_name = "pclmul", + .description = "Enable packed carry-less multiplication instructions", + .dependencies = featureSet(&[_]Feature{ + .sse2, + }), + }; + result[@enumToInt(Feature.pconfig)] = .{ + .llvm_name = "pconfig", + .description = "platform configuration instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.pku)] = .{ + .llvm_name = "pku", + .description = "Enable protection keys", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.popcnt)] = .{ + .llvm_name = "popcnt", + .description = "Support POPCNT instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.prefer_256_bit)] = .{ + .llvm_name = "prefer-256-bit", + .description = "Prefer 256-bit AVX instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.prefetchwt1)] = .{ + .llvm_name = "prefetchwt1", + .description = "Prefetch with Intent to Write and T1 Hint", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.prfchw)] = .{ + .llvm_name = "prfchw", + .description = "Support PRFCHW instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.ptwrite)] = .{ + .llvm_name = "ptwrite", + .description = "Support ptwrite instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.rdpid)] = .{ + .llvm_name = "rdpid", + .description = "Support RDPID instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.rdrnd)] = .{ + .llvm_name = "rdrnd", + .description = "Support RDRAND instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.rdseed)] = .{ + .llvm_name = "rdseed", + .description = "Support RDSEED instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.retpoline)] = .{ + .llvm_name = "retpoline", + .description = "Remove speculation of indirect branches from the generated code, either by avoiding them entirely or lowering them with a speculation blocking construct", + .dependencies = featureSet(&[_]Feature{ + .retpoline_indirect_branches, + .retpoline_indirect_calls, + }), + }; + result[@enumToInt(Feature.retpoline_external_thunk)] = .{ + .llvm_name = "retpoline-external-thunk", + .description = "When lowering an indirect call or branch using a `retpoline`, rely on the specified user provided thunk rather than emitting one ourselves. Only has effect when combined with some other retpoline feature", + .dependencies = featureSet(&[_]Feature{ + .retpoline_indirect_calls, + }), + }; + result[@enumToInt(Feature.retpoline_indirect_branches)] = .{ + .llvm_name = "retpoline-indirect-branches", + .description = "Remove speculation of indirect branches from the generated code", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.retpoline_indirect_calls)] = .{ + .llvm_name = "retpoline-indirect-calls", + .description = "Remove speculation of indirect calls from the generated code", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.rtm)] = .{ + .llvm_name = "rtm", + .description = "Support RTM instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sahf)] = .{ + .llvm_name = "sahf", + .description = "Support LAHF and SAHF instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sgx)] = .{ + .llvm_name = "sgx", + .description = "Enable Software Guard Extensions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sha)] = .{ + .llvm_name = "sha", + .description = "Enable SHA instructions", + .dependencies = featureSet(&[_]Feature{ + .sse2, + }), + }; + result[@enumToInt(Feature.shstk)] = .{ + .llvm_name = "shstk", + .description = "Support CET Shadow-Stack instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_3ops_lea)] = .{ + .llvm_name = "slow-3ops-lea", + .description = "LEA instruction with 3 ops or certain registers is slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_incdec)] = .{ + .llvm_name = "slow-incdec", + .description = "INC and DEC instructions are slower than ADD and SUB", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_lea)] = .{ + .llvm_name = "slow-lea", + .description = "LEA instruction with certain arguments is slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_pmaddwd)] = .{ + .llvm_name = "slow-pmaddwd", + .description = "PMADDWD is slower than PMULLD", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_pmulld)] = .{ + .llvm_name = "slow-pmulld", + .description = "PMULLD instruction is slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_shld)] = .{ + .llvm_name = "slow-shld", + .description = "SHLD instruction is slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_two_mem_ops)] = .{ + .llvm_name = "slow-two-mem-ops", + .description = "Two memory operand instructions are slow", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_unaligned_mem_16)] = .{ + .llvm_name = "slow-unaligned-mem-16", + .description = "Slow unaligned 16-byte memory access", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.slow_unaligned_mem_32)] = .{ + .llvm_name = "slow-unaligned-mem-32", + .description = "Slow unaligned 32-byte memory access", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.soft_float)] = .{ + .llvm_name = "soft-float", + .description = "Use software floating point features", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sse)] = .{ + .llvm_name = "sse", + .description = "Enable SSE instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sse_unaligned_mem)] = .{ + .llvm_name = "sse-unaligned-mem", + .description = "Allow unaligned memory operands with SSE instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.sse2)] = .{ + .llvm_name = "sse2", + .description = "Enable SSE2 instructions", + .dependencies = featureSet(&[_]Feature{ + .sse, + }), + }; + result[@enumToInt(Feature.sse3)] = .{ + .llvm_name = "sse3", + .description = "Enable SSE3 instructions", + .dependencies = featureSet(&[_]Feature{ + .sse2, + }), + }; + result[@enumToInt(Feature.sse4_1)] = .{ + .llvm_name = "sse4.1", + .description = "Enable SSE 4.1 instructions", + .dependencies = featureSet(&[_]Feature{ + .ssse3, + }), + }; + result[@enumToInt(Feature.sse4_2)] = .{ + .llvm_name = "sse4.2", + .description = "Enable SSE 4.2 instructions", + .dependencies = featureSet(&[_]Feature{ + .sse4_1, + }), + }; + result[@enumToInt(Feature.sse4a)] = .{ + .llvm_name = "sse4a", + .description = "Support SSE 4a instructions", + .dependencies = featureSet(&[_]Feature{ + .sse3, + }), + }; + result[@enumToInt(Feature.ssse3)] = .{ + .llvm_name = "ssse3", + .description = "Enable SSSE3 instructions", + .dependencies = featureSet(&[_]Feature{ + .sse3, + }), + }; + result[@enumToInt(Feature.tbm)] = .{ + .llvm_name = "tbm", + .description = "Enable TBM instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.vaes)] = .{ + .llvm_name = "vaes", + .description = "Promote selected AES instructions to AVX512/AVX registers", + .dependencies = featureSet(&[_]Feature{ + .aes, + .avx, + }), + }; + result[@enumToInt(Feature.vpclmulqdq)] = .{ + .llvm_name = "vpclmulqdq", + .description = "Enable vpclmulqdq instructions", + .dependencies = featureSet(&[_]Feature{ + .avx, + .pclmul, + }), + }; + result[@enumToInt(Feature.waitpkg)] = .{ + .llvm_name = "waitpkg", + .description = "Wait and pause enhancements", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.wbnoinvd)] = .{ + .llvm_name = "wbnoinvd", + .description = "Write Back No Invalidate", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.x87)] = .{ + .llvm_name = "x87", + .description = "Enable X87 float instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.xop)] = .{ + .llvm_name = "xop", + .description = "Enable XOP instructions", + .dependencies = featureSet(&[_]Feature{ + .fma4, + }), + }; + result[@enumToInt(Feature.xsave)] = .{ + .llvm_name = "xsave", + .description = "Support xsave instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.xsavec)] = .{ + .llvm_name = "xsavec", + .description = "Support xsavec instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.xsaveopt)] = .{ + .llvm_name = "xsaveopt", + .description = "Support xsaveopt instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.xsaves)] = .{ + .llvm_name = "xsaves", + .description = "Support xsaves instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + const ti = @typeInfo(Feature); + for (result) |*elem, i| { + elem.index = i; + elem.name = ti.Enum.fields[i].name; + } + break :blk result; +}; + +pub const cpu = struct { + pub const amdfam10 = Cpu{ + .name = "amdfam10", + .llvm_name = "amdfam10", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .@"64bit", + .cmov, + .cx16, + .cx8, + .fast_scalar_shift_masks, + .fxsr, + .lzcnt, + .nopl, + .popcnt, + .sahf, + .slow_shld, + .sse4a, + .x87, + }), + }; + pub const athlon = Cpu{ + .name = "athlon", + .llvm_name = "athlon", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .cmov, + .cx8, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const athlon_4 = Cpu{ + .name = "athlon_4", + .llvm_name = "athlon-4", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .cmov, + .cx8, + .fxsr, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .sse, + .x87, + }), + }; + pub const athlon_fx = Cpu{ + .name = "athlon_fx", + .llvm_name = "athlon-fx", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .@"64bit", + .cmov, + .cx8, + .fast_scalar_shift_masks, + .fxsr, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .sse2, + .x87, + }), + }; + pub const athlon_mp = Cpu{ + .name = "athlon_mp", + .llvm_name = "athlon-mp", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .cmov, + .cx8, + .fxsr, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .sse, + .x87, + }), + }; + pub const athlon_tbird = Cpu{ + .name = "athlon_tbird", + .llvm_name = "athlon-tbird", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .cmov, + .cx8, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const athlon_xp = Cpu{ + .name = "athlon_xp", + .llvm_name = "athlon-xp", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .cmov, + .cx8, + .fxsr, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .sse, + .x87, + }), + }; + pub const athlon64 = Cpu{ + .name = "athlon64", + .llvm_name = "athlon64", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .@"64bit", + .cmov, + .cx8, + .fast_scalar_shift_masks, + .fxsr, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .sse2, + .x87, + }), + }; + pub const athlon64_sse3 = Cpu{ + .name = "athlon64_sse3", + .llvm_name = "athlon64-sse3", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .@"64bit", + .cmov, + .cx16, + .cx8, + .fast_scalar_shift_masks, + .fxsr, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .sse3, + .x87, + }), + }; + pub const atom = Cpu{ + .name = "atom", + .llvm_name = "atom", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .fxsr, + .idivl_to_divb, + .idivq_to_divl, + .lea_sp, + .lea_uses_ag, + .mmx, + .movbe, + .nopl, + .pad_short_functions, + .sahf, + .slow_two_mem_ops, + .slow_unaligned_mem_16, + .ssse3, + .x87, + }), + }; + pub const barcelona = Cpu{ + .name = "barcelona", + .llvm_name = "barcelona", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .@"64bit", + .cmov, + .cx16, + .cx8, + .fast_scalar_shift_masks, + .fxsr, + .lzcnt, + .nopl, + .popcnt, + .sahf, + .slow_shld, + .sse4a, + .x87, + }), + }; + pub const bdver1 = Cpu{ + .name = "bdver1", + .llvm_name = "bdver1", + .features = featureSet(&[_]Feature{ + .@"64bit", + .aes, + .branchfusion, + .cmov, + .cx16, + .cx8, + .fast_11bytenop, + .fast_scalar_shift_masks, + .fxsr, + .lwp, + .lzcnt, + .mmx, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .sahf, + .slow_shld, + .x87, + .xop, + .xsave, + }), + }; + pub const bdver2 = Cpu{ + .name = "bdver2", + .llvm_name = "bdver2", + .features = featureSet(&[_]Feature{ + .@"64bit", + .aes, + .bmi, + .branchfusion, + .cmov, + .cx16, + .cx8, + .f16c, + .fast_11bytenop, + .fast_bextr, + .fast_scalar_shift_masks, + .fma, + .fxsr, + .lwp, + .lzcnt, + .mmx, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .sahf, + .slow_shld, + .tbm, + .x87, + .xop, + .xsave, + }), + }; + pub const bdver3 = Cpu{ + .name = "bdver3", + .llvm_name = "bdver3", + .features = featureSet(&[_]Feature{ + .@"64bit", + .aes, + .bmi, + .branchfusion, + .cmov, + .cx16, + .cx8, + .f16c, + .fast_11bytenop, + .fast_bextr, + .fast_scalar_shift_masks, + .fma, + .fsgsbase, + .fxsr, + .lwp, + .lzcnt, + .mmx, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .sahf, + .slow_shld, + .tbm, + .x87, + .xop, + .xsave, + .xsaveopt, + }), + }; + pub const bdver4 = Cpu{ + .name = "bdver4", + .llvm_name = "bdver4", + .features = featureSet(&[_]Feature{ + .@"64bit", + .aes, + .avx2, + .bmi, + .bmi2, + .branchfusion, + .cmov, + .cx16, + .cx8, + .f16c, + .fast_11bytenop, + .fast_bextr, + .fast_scalar_shift_masks, + .fma, + .fsgsbase, + .fxsr, + .lwp, + .lzcnt, + .mmx, + .mwaitx, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .sahf, + .slow_shld, + .tbm, + .x87, + .xop, + .xsave, + .xsaveopt, + }), + }; + pub const bonnell = Cpu{ + .name = "bonnell", + .llvm_name = "bonnell", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .fxsr, + .idivl_to_divb, + .idivq_to_divl, + .lea_sp, + .lea_uses_ag, + .mmx, + .movbe, + .nopl, + .pad_short_functions, + .sahf, + .slow_two_mem_ops, + .slow_unaligned_mem_16, + .ssse3, + .x87, + }), + }; + pub const broadwell = Cpu{ + .name = "broadwell", + .llvm_name = "broadwell", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .avx, + .avx2, + .bmi, + .bmi2, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .false_deps_lzcnt_tzcnt, + .false_deps_popcnt, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .slow_3ops_lea, + .sse4_2, + .x87, + .xsave, + .xsaveopt, + }), + }; + pub const btver1 = Cpu{ + .name = "btver1", + .llvm_name = "btver1", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .fast_15bytenop, + .fast_scalar_shift_masks, + .fast_vector_shift_masks, + .fxsr, + .lzcnt, + .mmx, + .nopl, + .popcnt, + .prfchw, + .sahf, + .slow_shld, + .sse4a, + .ssse3, + .x87, + }), + }; + pub const btver2 = Cpu{ + .name = "btver2", + .llvm_name = "btver2", + .features = featureSet(&[_]Feature{ + .@"64bit", + .aes, + .avx, + .bmi, + .cmov, + .cx16, + .cx8, + .f16c, + .fast_15bytenop, + .fast_bextr, + .fast_hops, + .fast_lzcnt, + .fast_partial_ymm_or_zmm_write, + .fast_scalar_shift_masks, + .fast_vector_shift_masks, + .fxsr, + .lzcnt, + .mmx, + .movbe, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .sahf, + .slow_shld, + .sse4a, + .ssse3, + .x87, + .xsave, + .xsaveopt, + }), + }; + pub const c3 = Cpu{ + .name = "c3", + .llvm_name = "c3", + .features = featureSet(&[_]Feature{ + .@"3dnow", + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const c3_2 = Cpu{ + .name = "c3_2", + .llvm_name = "c3-2", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .fxsr, + .mmx, + .slow_unaligned_mem_16, + .sse, + .x87, + }), + }; + pub const cannonlake = Cpu{ + .name = "cannonlake", + .llvm_name = "cannonlake", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx, + .avx2, + .avx512bw, + .avx512cd, + .avx512dq, + .avx512f, + .avx512ifma, + .avx512vbmi, + .avx512vl, + .bmi, + .bmi2, + .clflushopt, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .fast_gather, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fast_vector_fsqrt, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .mpx, + .nopl, + .pclmul, + .pku, + .popcnt, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .sgx, + .sha, + .slow_3ops_lea, + .sse4_2, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const cascadelake = Cpu{ + .name = "cascadelake", + .llvm_name = "cascadelake", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx, + .avx2, + .avx512bw, + .avx512cd, + .avx512dq, + .avx512f, + .avx512vl, + .avx512vnni, + .bmi, + .bmi2, + .clflushopt, + .clwb, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .false_deps_popcnt, + .fast_gather, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fast_vector_fsqrt, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .mpx, + .nopl, + .pclmul, + .pku, + .popcnt, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .slow_3ops_lea, + .sse4_2, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const cooperlake = Cpu{ + .name = "cooperlake", + .llvm_name = "cooperlake", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx, + .avx2, + .avx512bf16, + .avx512bw, + .avx512cd, + .avx512dq, + .avx512f, + .avx512vl, + .avx512vnni, + .bmi, + .bmi2, + .clflushopt, + .clwb, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .false_deps_popcnt, + .fast_gather, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fast_vector_fsqrt, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .mpx, + .nopl, + .pclmul, + .pku, + .popcnt, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .slow_3ops_lea, + .sse4_2, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const core_avx_i = Cpu{ + .name = "core_avx_i", + .llvm_name = "core-avx-i", + .features = featureSet(&[_]Feature{ + .@"64bit", + .avx, + .cmov, + .cx16, + .cx8, + .f16c, + .false_deps_popcnt, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .nopl, + .pclmul, + .popcnt, + .rdrnd, + .sahf, + .slow_3ops_lea, + .slow_unaligned_mem_32, + .sse4_2, + .x87, + .xsave, + .xsaveopt, + }), + }; + pub const core_avx2 = Cpu{ + .name = "core_avx2", + .llvm_name = "core-avx2", + .features = featureSet(&[_]Feature{ + .@"64bit", + .avx, + .avx2, + .bmi, + .bmi2, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .false_deps_lzcnt_tzcnt, + .false_deps_popcnt, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .nopl, + .pclmul, + .popcnt, + .rdrnd, + .sahf, + .slow_3ops_lea, + .sse4_2, + .x87, + .xsave, + .xsaveopt, + }), + }; + pub const core2 = Cpu{ + .name = "core2", + .llvm_name = "core2", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .fxsr, + .macrofusion, + .mmx, + .nopl, + .sahf, + .slow_unaligned_mem_16, + .ssse3, + .x87, + }), + }; + pub const corei7 = Cpu{ + .name = "corei7", + .llvm_name = "corei7", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .fxsr, + .macrofusion, + .mmx, + .nopl, + .popcnt, + .sahf, + .sse4_2, + .x87, + }), + }; + pub const corei7_avx = Cpu{ + .name = "corei7_avx", + .llvm_name = "corei7-avx", + .features = featureSet(&[_]Feature{ + .@"64bit", + .avx, + .cmov, + .cx16, + .cx8, + .false_deps_popcnt, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fxsr, + .idivq_to_divl, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .nopl, + .pclmul, + .popcnt, + .sahf, + .slow_3ops_lea, + .slow_unaligned_mem_32, + .sse4_2, + .x87, + .xsave, + .xsaveopt, + }), + }; + pub const generic = Cpu{ + .name = "generic", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{ + .cx8, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const geode = Cpu{ + .name = "geode", + .llvm_name = "geode", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .cx8, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const goldmont = Cpu{ + .name = "goldmont", + .llvm_name = "goldmont", + .features = featureSet(&[_]Feature{ + .@"64bit", + .aes, + .clflushopt, + .cmov, + .cx16, + .cx8, + .false_deps_popcnt, + .fsgsbase, + .fxsr, + .mmx, + .movbe, + .mpx, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .sha, + .slow_incdec, + .slow_lea, + .slow_two_mem_ops, + .sse4_2, + .ssse3, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const goldmont_plus = Cpu{ + .name = "goldmont_plus", + .llvm_name = "goldmont-plus", + .features = featureSet(&[_]Feature{ + .@"64bit", + .aes, + .clflushopt, + .cmov, + .cx16, + .cx8, + .fsgsbase, + .fxsr, + .mmx, + .movbe, + .mpx, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .ptwrite, + .rdpid, + .rdrnd, + .rdseed, + .sahf, + .sgx, + .sha, + .slow_incdec, + .slow_lea, + .slow_two_mem_ops, + .sse4_2, + .ssse3, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const haswell = Cpu{ + .name = "haswell", + .llvm_name = "haswell", + .features = featureSet(&[_]Feature{ + .@"64bit", + .avx, + .avx2, + .bmi, + .bmi2, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .false_deps_lzcnt_tzcnt, + .false_deps_popcnt, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .nopl, + .pclmul, + .popcnt, + .rdrnd, + .sahf, + .slow_3ops_lea, + .sse4_2, + .x87, + .xsave, + .xsaveopt, + }), + }; + pub const _i386 = Cpu{ + .name = "_i386", + .llvm_name = "i386", + .features = featureSet(&[_]Feature{ + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const _i486 = Cpu{ + .name = "_i486", + .llvm_name = "i486", + .features = featureSet(&[_]Feature{ + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const _i586 = Cpu{ + .name = "_i586", + .llvm_name = "i586", + .features = featureSet(&[_]Feature{ + .cx8, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const _i686 = Cpu{ + .name = "_i686", + .llvm_name = "i686", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const icelake_client = Cpu{ + .name = "icelake_client", + .llvm_name = "icelake-client", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx, + .avx2, + .avx512bitalg, + .avx512bw, + .avx512cd, + .avx512dq, + .avx512f, + .avx512ifma, + .avx512vbmi, + .avx512vbmi2, + .avx512vl, + .avx512vnni, + .avx512vpopcntdq, + .bmi, + .bmi2, + .clflushopt, + .clwb, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .fast_gather, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fast_vector_fsqrt, + .fma, + .fsgsbase, + .fxsr, + .gfni, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .mpx, + .nopl, + .pclmul, + .pku, + .popcnt, + .prfchw, + .rdpid, + .rdrnd, + .rdseed, + .sahf, + .sgx, + .sha, + .slow_3ops_lea, + .sse4_2, + .vaes, + .vpclmulqdq, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const icelake_server = Cpu{ + .name = "icelake_server", + .llvm_name = "icelake-server", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx, + .avx2, + .avx512bitalg, + .avx512bw, + .avx512cd, + .avx512dq, + .avx512f, + .avx512ifma, + .avx512vbmi, + .avx512vbmi2, + .avx512vl, + .avx512vnni, + .avx512vpopcntdq, + .bmi, + .bmi2, + .clflushopt, + .clwb, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .fast_gather, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fast_vector_fsqrt, + .fma, + .fsgsbase, + .fxsr, + .gfni, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .mpx, + .nopl, + .pclmul, + .pconfig, + .pku, + .popcnt, + .prfchw, + .rdpid, + .rdrnd, + .rdseed, + .sahf, + .sgx, + .sha, + .slow_3ops_lea, + .sse4_2, + .vaes, + .vpclmulqdq, + .wbnoinvd, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const ivybridge = Cpu{ + .name = "ivybridge", + .llvm_name = "ivybridge", + .features = featureSet(&[_]Feature{ + .@"64bit", + .avx, + .cmov, + .cx16, + .cx8, + .f16c, + .false_deps_popcnt, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .nopl, + .pclmul, + .popcnt, + .rdrnd, + .sahf, + .slow_3ops_lea, + .slow_unaligned_mem_32, + .sse4_2, + .x87, + .xsave, + .xsaveopt, + }), + }; + pub const k6 = Cpu{ + .name = "k6", + .llvm_name = "k6", + .features = featureSet(&[_]Feature{ + .cx8, + .mmx, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const k6_2 = Cpu{ + .name = "k6_2", + .llvm_name = "k6-2", + .features = featureSet(&[_]Feature{ + .@"3dnow", + .cx8, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const k6_3 = Cpu{ + .name = "k6_3", + .llvm_name = "k6-3", + .features = featureSet(&[_]Feature{ + .@"3dnow", + .cx8, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const k8 = Cpu{ + .name = "k8", + .llvm_name = "k8", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .@"64bit", + .cmov, + .cx8, + .fast_scalar_shift_masks, + .fxsr, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .sse2, + .x87, + }), + }; + pub const k8_sse3 = Cpu{ + .name = "k8_sse3", + .llvm_name = "k8-sse3", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .@"64bit", + .cmov, + .cx16, + .cx8, + .fast_scalar_shift_masks, + .fxsr, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .sse3, + .x87, + }), + }; + pub const knl = Cpu{ + .name = "knl", + .llvm_name = "knl", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx512cd, + .avx512er, + .avx512f, + .avx512pf, + .bmi, + .bmi2, + .cmov, + .cx16, + .cx8, + .f16c, + .fast_gather, + .fast_partial_ymm_or_zmm_write, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .lzcnt, + .mmx, + .movbe, + .nopl, + .pclmul, + .popcnt, + .prefetchwt1, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .slow_3ops_lea, + .slow_incdec, + .slow_pmaddwd, + .slow_two_mem_ops, + .x87, + .xsave, + .xsaveopt, + }), + }; + pub const knm = Cpu{ + .name = "knm", + .llvm_name = "knm", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx512cd, + .avx512er, + .avx512f, + .avx512pf, + .avx512vpopcntdq, + .bmi, + .bmi2, + .cmov, + .cx16, + .cx8, + .f16c, + .fast_gather, + .fast_partial_ymm_or_zmm_write, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .lzcnt, + .mmx, + .movbe, + .nopl, + .pclmul, + .popcnt, + .prefetchwt1, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .slow_3ops_lea, + .slow_incdec, + .slow_pmaddwd, + .slow_two_mem_ops, + .x87, + .xsave, + .xsaveopt, + }), + }; + pub const lakemont = Cpu{ + .name = "lakemont", + .llvm_name = "lakemont", + .features = featureSet(&[_]Feature{}), + }; + pub const nehalem = Cpu{ + .name = "nehalem", + .llvm_name = "nehalem", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .fxsr, + .macrofusion, + .mmx, + .nopl, + .popcnt, + .sahf, + .sse4_2, + .x87, + }), + }; + pub const nocona = Cpu{ + .name = "nocona", + .llvm_name = "nocona", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .fxsr, + .mmx, + .nopl, + .slow_unaligned_mem_16, + .sse3, + .x87, + }), + }; + pub const opteron = Cpu{ + .name = "opteron", + .llvm_name = "opteron", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .@"64bit", + .cmov, + .cx8, + .fast_scalar_shift_masks, + .fxsr, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .sse2, + .x87, + }), + }; + pub const opteron_sse3 = Cpu{ + .name = "opteron_sse3", + .llvm_name = "opteron-sse3", + .features = featureSet(&[_]Feature{ + .@"3dnowa", + .@"64bit", + .cmov, + .cx16, + .cx8, + .fast_scalar_shift_masks, + .fxsr, + .nopl, + .slow_shld, + .slow_unaligned_mem_16, + .sse3, + .x87, + }), + }; + pub const penryn = Cpu{ + .name = "penryn", + .llvm_name = "penryn", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .fxsr, + .macrofusion, + .mmx, + .nopl, + .sahf, + .slow_unaligned_mem_16, + .sse4_1, + .x87, + }), + }; + pub const pentium = Cpu{ + .name = "pentium", + .llvm_name = "pentium", + .features = featureSet(&[_]Feature{ + .cx8, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const pentium_m = Cpu{ + .name = "pentium_m", + .llvm_name = "pentium-m", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .fxsr, + .mmx, + .nopl, + .slow_unaligned_mem_16, + .sse2, + .x87, + }), + }; + pub const pentium_mmx = Cpu{ + .name = "pentium_mmx", + .llvm_name = "pentium-mmx", + .features = featureSet(&[_]Feature{ + .cx8, + .mmx, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const pentium2 = Cpu{ + .name = "pentium2", + .llvm_name = "pentium2", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .fxsr, + .mmx, + .nopl, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const pentium3 = Cpu{ + .name = "pentium3", + .llvm_name = "pentium3", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .fxsr, + .mmx, + .nopl, + .slow_unaligned_mem_16, + .sse, + .x87, + }), + }; + pub const pentium3m = Cpu{ + .name = "pentium3m", + .llvm_name = "pentium3m", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .fxsr, + .mmx, + .nopl, + .slow_unaligned_mem_16, + .sse, + .x87, + }), + }; + pub const pentium4 = Cpu{ + .name = "pentium4", + .llvm_name = "pentium4", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .fxsr, + .mmx, + .nopl, + .slow_unaligned_mem_16, + .sse2, + .x87, + }), + }; + pub const pentium4m = Cpu{ + .name = "pentium4m", + .llvm_name = "pentium4m", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .fxsr, + .mmx, + .nopl, + .slow_unaligned_mem_16, + .sse2, + .x87, + }), + }; + pub const pentiumpro = Cpu{ + .name = "pentiumpro", + .llvm_name = "pentiumpro", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .nopl, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const prescott = Cpu{ + .name = "prescott", + .llvm_name = "prescott", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .fxsr, + .mmx, + .nopl, + .slow_unaligned_mem_16, + .sse3, + .x87, + }), + }; + pub const sandybridge = Cpu{ + .name = "sandybridge", + .llvm_name = "sandybridge", + .features = featureSet(&[_]Feature{ + .@"64bit", + .avx, + .cmov, + .cx16, + .cx8, + .false_deps_popcnt, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fxsr, + .idivq_to_divl, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .nopl, + .pclmul, + .popcnt, + .sahf, + .slow_3ops_lea, + .slow_unaligned_mem_32, + .sse4_2, + .x87, + .xsave, + .xsaveopt, + }), + }; + pub const silvermont = Cpu{ + .name = "silvermont", + .llvm_name = "silvermont", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .false_deps_popcnt, + .fxsr, + .idivq_to_divl, + .mmx, + .movbe, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .rdrnd, + .sahf, + .slow_incdec, + .slow_lea, + .slow_pmulld, + .slow_two_mem_ops, + .sse4_2, + .ssse3, + .x87, + }), + }; + pub const skx = Cpu{ + .name = "skx", + .llvm_name = "skx", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx, + .avx2, + .avx512bw, + .avx512cd, + .avx512dq, + .avx512f, + .avx512vl, + .bmi, + .bmi2, + .clflushopt, + .clwb, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .false_deps_popcnt, + .fast_gather, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fast_vector_fsqrt, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .mpx, + .nopl, + .pclmul, + .pku, + .popcnt, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .slow_3ops_lea, + .sse4_2, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const skylake = Cpu{ + .name = "skylake", + .llvm_name = "skylake", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx, + .avx2, + .bmi, + .bmi2, + .clflushopt, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .false_deps_popcnt, + .fast_gather, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fast_vector_fsqrt, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .mpx, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .sgx, + .slow_3ops_lea, + .sse4_2, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const skylake_avx512 = Cpu{ + .name = "skylake_avx512", + .llvm_name = "skylake-avx512", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx, + .avx2, + .avx512bw, + .avx512cd, + .avx512dq, + .avx512f, + .avx512vl, + .bmi, + .bmi2, + .clflushopt, + .clwb, + .cmov, + .cx16, + .cx8, + .ermsb, + .f16c, + .false_deps_popcnt, + .fast_gather, + .fast_scalar_fsqrt, + .fast_shld_rotate, + .fast_variable_shuffle, + .fast_vector_fsqrt, + .fma, + .fsgsbase, + .fxsr, + .idivq_to_divl, + .invpcid, + .lzcnt, + .macrofusion, + .merge_to_threeway_branch, + .mmx, + .movbe, + .mpx, + .nopl, + .pclmul, + .pku, + .popcnt, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .slow_3ops_lea, + .sse4_2, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const slm = Cpu{ + .name = "slm", + .llvm_name = "slm", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .false_deps_popcnt, + .fxsr, + .idivq_to_divl, + .mmx, + .movbe, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .rdrnd, + .sahf, + .slow_incdec, + .slow_lea, + .slow_pmulld, + .slow_two_mem_ops, + .sse4_2, + .ssse3, + .x87, + }), + }; + pub const tremont = Cpu{ + .name = "tremont", + .llvm_name = "tremont", + .features = featureSet(&[_]Feature{ + .@"64bit", + .aes, + .cldemote, + .clflushopt, + .cmov, + .cx16, + .cx8, + .fsgsbase, + .fxsr, + .gfni, + .mmx, + .movbe, + .movdir64b, + .movdiri, + .mpx, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .ptwrite, + .rdpid, + .rdrnd, + .rdseed, + .sahf, + .sgx, + .sha, + .slow_incdec, + .slow_lea, + .slow_two_mem_ops, + .sse4_2, + .ssse3, + .waitpkg, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const westmere = Cpu{ + .name = "westmere", + .llvm_name = "westmere", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx16, + .cx8, + .fxsr, + .macrofusion, + .mmx, + .nopl, + .pclmul, + .popcnt, + .sahf, + .sse4_2, + .x87, + }), + }; + pub const winchip_c6 = Cpu{ + .name = "winchip_c6", + .llvm_name = "winchip-c6", + .features = featureSet(&[_]Feature{ + .mmx, + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const winchip2 = Cpu{ + .name = "winchip2", + .llvm_name = "winchip2", + .features = featureSet(&[_]Feature{ + .@"3dnow", + .slow_unaligned_mem_16, + .x87, + }), + }; + pub const x86_64 = Cpu{ + .name = "x86_64", + .llvm_name = "x86-64", + .features = featureSet(&[_]Feature{ + .@"64bit", + .cmov, + .cx8, + .fxsr, + .macrofusion, + .mmx, + .nopl, + .slow_3ops_lea, + .slow_incdec, + .sse2, + .x87, + }), + }; + pub const yonah = Cpu{ + .name = "yonah", + .llvm_name = "yonah", + .features = featureSet(&[_]Feature{ + .cmov, + .cx8, + .fxsr, + .mmx, + .nopl, + .slow_unaligned_mem_16, + .sse3, + .x87, + }), + }; + pub const znver1 = Cpu{ + .name = "znver1", + .llvm_name = "znver1", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx2, + .bmi, + .bmi2, + .branchfusion, + .clflushopt, + .clzero, + .cmov, + .cx16, + .f16c, + .fast_15bytenop, + .fast_bextr, + .fast_lzcnt, + .fast_scalar_shift_masks, + .fma, + .fsgsbase, + .fxsr, + .lzcnt, + .mmx, + .movbe, + .mwaitx, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .rdrnd, + .rdseed, + .sahf, + .sha, + .slow_shld, + .sse4a, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; + pub const znver2 = Cpu{ + .name = "znver2", + .llvm_name = "znver2", + .features = featureSet(&[_]Feature{ + .@"64bit", + .adx, + .aes, + .avx2, + .bmi, + .bmi2, + .branchfusion, + .clflushopt, + .clwb, + .clzero, + .cmov, + .cx16, + .f16c, + .fast_15bytenop, + .fast_bextr, + .fast_lzcnt, + .fast_scalar_shift_masks, + .fma, + .fsgsbase, + .fxsr, + .lzcnt, + .mmx, + .movbe, + .mwaitx, + .nopl, + .pclmul, + .popcnt, + .prfchw, + .rdpid, + .rdrnd, + .rdseed, + .sahf, + .sha, + .slow_shld, + .sse4a, + .wbnoinvd, + .x87, + .xsave, + .xsavec, + .xsaveopt, + .xsaves, + }), + }; +}; + +/// All x86 CPUs, sorted alphabetically by name. +/// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 +/// compiler has inefficient memory and CPU usage, affecting build times. +pub const all_cpus = &[_]*const Cpu{ + &cpu.amdfam10, + &cpu.athlon, + &cpu.athlon_4, + &cpu.athlon_fx, + &cpu.athlon_mp, + &cpu.athlon_tbird, + &cpu.athlon_xp, + &cpu.athlon64, + &cpu.athlon64_sse3, + &cpu.atom, + &cpu.barcelona, + &cpu.bdver1, + &cpu.bdver2, + &cpu.bdver3, + &cpu.bdver4, + &cpu.bonnell, + &cpu.broadwell, + &cpu.btver1, + &cpu.btver2, + &cpu.c3, + &cpu.c3_2, + &cpu.cannonlake, + &cpu.cascadelake, + &cpu.cooperlake, + &cpu.core_avx_i, + &cpu.core_avx2, + &cpu.core2, + &cpu.corei7, + &cpu.corei7_avx, + &cpu.generic, + &cpu.geode, + &cpu.goldmont, + &cpu.goldmont_plus, + &cpu.haswell, + &cpu._i386, + &cpu._i486, + &cpu._i586, + &cpu._i686, + &cpu.icelake_client, + &cpu.icelake_server, + &cpu.ivybridge, + &cpu.k6, + &cpu.k6_2, + &cpu.k6_3, + &cpu.k8, + &cpu.k8_sse3, + &cpu.knl, + &cpu.knm, + &cpu.lakemont, + &cpu.nehalem, + &cpu.nocona, + &cpu.opteron, + &cpu.opteron_sse3, + &cpu.penryn, + &cpu.pentium, + &cpu.pentium_m, + &cpu.pentium_mmx, + &cpu.pentium2, + &cpu.pentium3, + &cpu.pentium3m, + &cpu.pentium4, + &cpu.pentium4m, + &cpu.pentiumpro, + &cpu.prescott, + &cpu.sandybridge, + &cpu.silvermont, + &cpu.skx, + &cpu.skylake, + &cpu.skylake_avx512, + &cpu.slm, + &cpu.tremont, + &cpu.westmere, + &cpu.winchip_c6, + &cpu.winchip2, + &cpu.x86_64, + &cpu.yonah, + &cpu.znver1, + &cpu.znver2, +}; |
