╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ update_cpu_features.zig ──────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1879 .extra_deps = &.{"3dnowa"}, 1880 }, 1881 .{ 1882 .llvm_name = "raptorlake", 1883 .extra_deps = &.{ "smap", "smep" }, 1884 }, 1885 .{ 1886 .llvm_name = "rocketlake", 1887 .extra_deps = &.{ "smap", "smep" }, 1888 }, 1889 .{ 1890 .llvm_name = "sapphirerapids", 1891 .extra_deps = &.{ "smap", "smep" }, 1892 }, 1893 .{ 1894 .llvm_name = "silvermont", 1895 .extra_deps = &.{"smep"}, 1896 }, 1897 .{ 1898 .llvm_name = "skx", 1899 .extra_deps = &.{ "smap", "smep" }, 1900 }, 1901 .{ 1902 .llvm_name = "skylake", 1903 .extra_deps = &.{ "smap", "smep" }, 1904 }, 1905 .{ 1906 .llvm_name = "skylake_avx512", 1907 .extra_deps = &.{ "smap", "smep" }, 1908 }, 1909 .{ 1910 .llvm_name = "tigerlake", 1911 .extra_deps = &.{ "smap", "smep" }, 1912 }, 1913 .{ 1914 .llvm_name = "winchip2", 1915 .extra_deps = &.{"3dnow"}, 1916 }, 1917 .{ 1918 .llvm_name = "sse4.2", 1919 .extra_deps = &.{"crc32"}, 1920 }, 1921 .{ 1922 .llvm_name = "znver1", 1923 .extra_deps = &.{ "smap", "smep" }, 1924 }, 1925 .{ 1926 .llvm_name = "znver2", 1927 .extra_deps = &.{ "smap", "smep" }, 1928 }, 1929 .{ 1930 .llvm_name = "znver3", 1931 .extra_deps = &.{ "smap", "smep" }, 1932 }, 1933 .{ 1934 .llvm_name = "znver4", 1935 .extra_deps = &.{ "smap", "smep" }, 1936 }, 1937 .{ 1938 .llvm_name = "znver5", 1939 .extra_deps = &.{ "smap", "smep" }, 1940 }, 1941 }, 1942 .extra_features = &.{ 1943 // Features removed from LLVM 1944 .{ 1945 .zig_name = "3dnow", 1946 .desc = "Enable 3DNow! instructions", 1947 .deps = &.{"mmx"}, 1948 }, 1949 .{ 1950 .zig_name = "3dnowa", 1951 .desc = "Enable 3DNow! Athlon instructions", 1952 .deps = &.{"3dnow"}, 1953 }, 1954 .{ 1955 .zig_name = "avx512er", 1956 .desc = "Enable AVX-512 Exponential and Reciprocal Instructions", 1957 .deps = &.{"avx512f"}, 1958 }, 1959 .{ 1960 .zig_name = "avx512pf", 1961 .desc = "Enable AVX-512 PreFetch Instructions", 1962 .deps = &.{"avx512f"}, 1963 }, 1964 .{ 1965 .zig_name = "prefetchwt1", 1966 .desc = "Prefetch with Intent to Write and T1 Hint", 1967 .deps = &.{}, 1968 }, 1969 // Custom Zig features 1970 .{ 1971 .zig_name = "bsf_bsr_0_clobbers_result", 1972 .desc = "BSF/BSR may clobber the lower 32-bits of the result register when the source is zero", 1973 .deps = &.{}, 1974 }, 1975 .{ 1976 .zig_name = "smap", 1977 .desc = "Enable Supervisor Mode Access Prevention", 1978 .deps = &.{}, 1979 }, 1980 .{ 1981 .zig_name = "smep", 1982 .desc = "Enable Supervisor Mode Execution Prevention", 1983 .deps = &.{}, 1984 }, 1985 }, 1986 .extra_cpus = &.{ 1987 .{ 1988 .llvm_name = null, 1989 .zig_name = "i86", 1990 .features = &.{"16bit_mode"}, 1991 }, 1992 }, 1993 .omit_cpus = &.{ 1994 // LLVM defines a bunch of dumb aliases with foreach loops in X86.td. 1995 "pentium_mmx", 1996 "pentium_pro", 1997 "pentium_ii", 1998 "pentium_3m", 1999 "pentium_iii_no_xmm_regs", 2000 "pentium_iii", 2001 "pentium_m", 2002 "pentium4m", 2003 "pentium_4", 2004 "pentium_4_sse3", 2005 "core_2_duo_ssse3", 2006 "core_2_duo_sse4_1", 2007 "atom_sse4_2", 2008 "goldmont_plus", 2009 "core_i7_sse4_2", 2010 "core_aes_pclmulqdq", 2011 "corei7-avx", 2012 "core_2nd_gen_avx", 2013 "core-avx-i", 2014 "core_3rd_gen_avx", 2015 "core-avx2", 2016 "core_4th_gen_avx", 2017 "core_4th_gen_avx_tsx", 2018 "core_5th_gen_avx", 2019 "core_5th_gen_avx_tsx", 2020 "mic_avx512", 2021 "skylake_avx512", 2022 "icelake_client", 2023 "icelake_server", 2024 "graniterapids_d", 2025 "arrowlake_s", 2026 }, 2027 }, 2028 .{ 2029 .zig_name = "xcore", 2030 .llvm = .{ 2031 .name = "XCore", 2032 .td_name = "XCore", 2033 }, 2034 }, 2035 .{ 2036 .zig_name = "xtensa", 2037 .llvm = .{ 2038 .name = "Xtensa", 2039 .td_name = "Xtensa", 2040 }, 2041 }, 2042 }; 2043 2044 pub fn main(init: std.process.Init) !void { 2045 const arena = init.arena.allocator(); 2046 const io = init.io; 2047 2048 var args = try init.minimal.args.iterateAllocator(arena); 2049 const args0 = args.next().?; 2050 2051 const llvm_tblgen_exe = args.next() orelse 2052 usageAndExit(args0, 1); 2053 2054 if (std.mem.eql(u8, llvm_tblgen_exe, "--help")) { 2055 usageAndExit(args0, 0); 2056 } 2057 if (std.mem.startsWith(u8, llvm_tblgen_exe, "-")) { 2058 usageAndExit(args0, 1); 2059 } 2060 2061 const llvm_src_root = args.next() orelse 2062 usageAndExit(args0, 1); 2063 2064 if (std.mem.startsWith(u8, llvm_src_root, "-")) { 2065 usageAndExit(args0, 1); 2066 } 2067 2068 const zig_src_root = args.next() orelse 2069 usageAndExit(args0, 1); 2070 2071 if (std.mem.startsWith(u8, zig_src_root, "-")) { 2072 usageAndExit(args0, 1); 2073 } 2074 2075 var filter: ?[]const u8 = null; 2076 if (args.next()) |arg| filter = arg; 2077 2078 // there shouldn't be any more argument after the optional filter 2079 if (args.skip()) usageAndExit(args0, 1); 2080 2081 var zig_src_dir = try Dir.cwd().openDir(io, zig_src_root, .{}); 2082 defer zig_src_dir.close(io); 2083 2084 const root_progress = std.Progress.start(io, .{ .estimated_total_items = targets.len }); 2085 defer root_progress.end(); 2086 2087 var group: Io.Group = .init; 2088 defer group.cancel(io); 2089 2090 for (targets) |target| { 2091 if (filter) |zig_name| { 2092 if (!std.mem.eql(u8, target.zig_name, zig_name)) continue; 2093 } 2094 group.async(io, processOneTarget, .{ io, .{ 2095 .llvm_tblgen_exe = llvm_tblgen_exe, 2096 .llvm_src_root = llvm_src_root, 2097 .zig_src_dir = zig_src_dir, 2098 .root_progress = root_progress, 2099 .target = target, 2100 } }); 2101 } 2102 2103 try group.await(io); 2104 } 2105 2106 const Job = struct { 2107 llvm_tblgen_exe: []const u8, 2108 llvm_src_root: []const u8, 2109 zig_src_dir: Dir, 2110 root_progress: std.Progress.Node, 2111 target: ArchTarget, 2112 }; 2113 2114 fn processOneTarget(io: Io, job: Job) void { 2115 processOneTargetInner(io, job) catch |err| std.debug.panic("panic: {s}", .{@errorName(err)}); 2116 } 2117 fn processOneTargetInner(io: Io, job: Job) !void { 2118 const target = job.target; 2119 2120 var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); 2121 defer arena_state.deinit(); 2122 const arena = arena_state.allocator(); 2123 2124 const progress_node = job.root_progress.start(target.zig_name, 3); 2125 defer progress_node.end(); 2126 2127 var features_table = std.StringHashMap(Feature).init(arena); 2128 var all_features = std.array_list.Managed(Feature).init(arena); 2129 var all_cpus = std.array_list.Managed(Cpu).init(arena); 2130 2131 if (target.llvm) |llvm| { 2132 const tblgen_progress = progress_node.start("running llvm-tblgen", 0); 2133 2134 const child_args = [_][]const u8{ 2135 job.llvm_tblgen_exe, 2136 "--dump-json", 2137 try std.fmt.allocPrint(arena, "{s}/llvm/lib/Target/{s}/{s}.td", .{ 2138 job.llvm_src_root, 2139 llvm.name, 2140 llvm.td_name, 2141 }), 2142 try std.fmt.allocPrint(arena, "-I={s}/llvm/include", .{job.llvm_src_root}), 2143 try std.fmt.allocPrint(arena, "-I={s}/llvm/lib/Target/{s}", .{ 2144 job.llvm_src_root, llvm.name, 2145 }), 2146 }; 2147 2148 const child_result = try std.process.run(arena, io, .{ 2149 .argv = &child_args, 2150 }); 2151 tblgen_progress.end(); 2152 if (child_result.stderr.len != 0) { 2153 std.debug.print("{s}\n", .{child_result.stderr}); 2154 } 2155 2156 const json_text = switch (child_result.term) { 2157 .exited => |code| if (code == 0) child_result.stdout else { 2158 std.debug.print("llvm-tblgen exited with code {d}\n", .{code}); 2159 std.process.exit(1); 2160 }, 2161 .signal => |sig| { 2162 std.debug.print("llvm-tblgen terminated with signal {t}\n", .{sig}); 2163 std.process.exit(1); 2164 }, 2165 .stopped => |sig| { 2166 std.debug.print("llvm-tblgen stopped with signal {t}\n", .{sig}); 2167 std.process.exit(1); 2168 }, 2169 .unknown => { 2170 std.debug.print("llvm-tblgen crashed\n", .{}); 2171 std.process.exit(1); 2172 }, 2173 }; 2174 2175 const json_parse_progress = progress_node.start("parsing JSON", 0); 2176 2177 const parsed = try json.parseFromSlice(json.Value, arena, json_text, .{}); 2178 defer parsed.deinit(); 2179 const root_map = &parsed.value.object; 2180 json_parse_progress.end(); 2181 2182 const collate_progress = progress_node.start("collating LLVM data", 0); 2183 2184 // So far, LLVM only has a few aliases for the same CPU. 2185 const Alias = struct { 2186 llvm: []const u8, 2187 zig: []const u8, 2188 }; 2189 var cpu_aliases = std.StringHashMap(std.ArrayList(*Alias)).init(arena); 2190 2191 { 2192 var it = root_map.iterator(); 2193 while (it.next()) |kv| { 2194 if (kv.key_ptr.len == 0) continue; 2195 if (kv.key_ptr.*[0] == '!') continue; 2196 if (kv.value_ptr.* != .object) continue; 2197 if (hasSuperclass(&kv.value_ptr.object, "ProcessorAlias")) { 2198 // Note that `Name` is actually the alias, while `Alias` is the name that will have 2199 // a full `Processor` object defined. 2200 const llvm_alias = kv.value_ptr.object.get("Name").?.string; 2201 const llvm_name = kv.value_ptr.object.get("Alias").?.string; 2202 2203 const gop = try cpu_aliases.getOrPut(try llvmNameToZigName(arena, llvm_name)); 2204 2205 if (!gop.found_existing) { 2206 gop.value_ptr.* = .empty; 2207 } 2208 2209 const alias = try arena.create(Alias); 2210 alias.* = .{ 2211 .llvm = llvm_alias, 2212 .zig = try llvmNameToZigName(arena, llvm_alias), 2213 }; 2214 try gop.value_ptr.append(arena, alias); 2215 } 2216 } 2217 } 2218 2219 { 2220 var it = root_map.iterator(); 2221 while (it.next()) |kv| { 2222 if (kv.key_ptr.len == 0) continue; 2223 if (kv.key_ptr.*[0] == '!') continue; 2224 if (kv.value_ptr.* != .object) continue; 2225 if (hasSuperclass(&kv.value_ptr.object, "SubtargetFeature")) { 2226 const llvm_name = kv.value_ptr.object.get("Name").?.string; 2227 if (llvm_name.len == 0) continue; 2228 2229 var zig_name = try llvmNameToZigName(arena, llvm_name); 2230 var desc = kv.value_ptr.object.get("Desc").?.string; 2231 var deps = std.array_list.Managed([]const u8).init(arena); 2232 var omit = false; 2233 var flatten = false; 2234 var omit_deps: []const []const u8 = &.{}; 2235 var extra_deps: []const []const u8 = &.{}; 2236 for (target.feature_overrides) |feature_override| { 2237 if (mem.eql(u8, llvm_name, feature_override.llvm_name)) { 2238 if (feature_override.omit) { 2239 // Still put the feature into the table so that we can 2240 // expand dependencies for the feature overrides marked `flatten`. 2241 omit = true; 2242 } 2243 if (feature_override.flatten) { 2244 flatten = true; 2245 } 2246 if (feature_override.zig_name) |override_name| { 2247 zig_name = override_name; 2248 } 2249 if (feature_override.desc) |override_desc| { 2250 desc = override_desc; 2251 } 2252 omit_deps = feature_override.omit_deps; 2253 extra_deps = feature_override.extra_deps; 2254 break; 2255 } 2256 } 2257 const implies = kv.value_ptr.object.get("Implies").?.array; 2258 for (implies.items) |imply| { 2259 const other_key = imply.object.get("def").?.string; 2260 const other_obj = root_map.get(other_key).?.object; 2261 const other_llvm_name = other_obj.get("Name").?.string; 2262 const other_zig_name = (try llvmFeatureNameToZigNameOmit( 2263 arena, 2264 target, 2265 other_llvm_name, 2266 )) orelse continue; 2267 for (omit_deps) |omit_dep| { 2268 if (mem.eql(u8, other_zig_name, omit_dep)) break; 2269 } else { 2270 try deps.append(other_zig_name); 2271 } 2272 } 2273 // This is used by AArch64. 2274 if (kv.value_ptr.object.get("DefaultExts")) |exts_val| { 2275 for (exts_val.array.items) |ext| { 2276 const other_key = ext.object.get("def").?.string; 2277 const other_obj = root_map.get(other_key).?.object; 2278 const other_llvm_name = other_obj.get("Name").?.string; 2279 const other_zig_name = (try llvmFeatureNameToZigNameOmit( 2280 arena, 2281 target, 2282 other_llvm_name, 2283 )) orelse continue; 2284 for (omit_deps) |omit_dep| { 2285 if (mem.eql(u8, other_zig_name, omit_dep)) break; 2286 } else { 2287 try deps.append(other_zig_name); 2288 } 2289 } 2290 } 2291 for (extra_deps) |extra_dep| { 2292 try deps.append(extra_dep); 2293 } 2294 const feature: Feature = .{ 2295 .llvm_name = llvm_name, 2296 .zig_name = zig_name, 2297 .desc = desc, 2298 .deps = deps.items, 2299 .flatten = flatten, 2300 }; 2301 try features_table.put(zig_name, feature); 2302 if (!omit and !flatten) { 2303 try all_features.append(feature); 2304 } 2305 } 2306 if (hasSuperclass(&kv.value_ptr.object, "Processor")) { 2307 const llvm_name = kv.value_ptr.object.get("Name").?.string; 2308 if (llvm_name.len == 0) continue; 2309 const omitted = for (target.omit_cpus) |omit_cpu_name| { 2310 if (mem.eql(u8, omit_cpu_name, llvm_name)) break true; 2311 } else false; 2312 if (omitted) continue; 2313 2314 var zig_name = try llvmNameToZigName(arena, llvm_name); 2315 var deps = std.array_list.Managed([]const u8).init(arena); 2316 var omit_deps: []const []const u8 = &.{}; 2317 var extra_deps: []const []const u8 = &.{}; 2318 for (target.feature_overrides) |feature_override| { 2319 if (mem.eql(u8, llvm_name, feature_override.llvm_name)) { 2320 if (feature_override.omit) { 2321 continue; 2322 } 2323 if (feature_override.zig_name) |override_name| { 2324 zig_name = override_name; 2325 } 2326 omit_deps = feature_override.omit_deps; 2327 extra_deps = feature_override.extra_deps; 2328 break; 2329 } 2330 } 2331 const features = kv.value_ptr.object.get("Features").?.array; 2332 for (features.items) |feature| { 2333 const feature_key = feature.object.get("def").?.string; 2334 const feature_obj = root_map.get(feature_key).?.object; 2335 const feature_llvm_name = feature_obj.get("Name").?.string; 2336 if (feature_llvm_name.len == 0) continue; 2337 const feature_zig_name = (try llvmFeatureNameToZigNameOmit( 2338 arena, 2339 target, 2340 feature_llvm_name, 2341 )) orelse continue; 2342 for (omit_deps) |omit_dep| { 2343 if (mem.eql(u8, feature_zig_name, omit_dep)) break; 2344 } else { 2345 try deps.append(feature_zig_name); 2346 } 2347 } 2348 for (extra_deps) |extra_dep| { 2349 try deps.append(extra_dep); 2350 } 2351 const tune_features = kv.value_ptr.object.get("TuneFeatures").?.array; 2352 for (tune_features.items) |feature| { 2353 const feature_key = feature.object.get("def").?.string; 2354 const feature_obj = root_map.get(feature_key).?.object; 2355 const feature_llvm_name = feature_obj.get("Name").?.string; 2356 if (feature_llvm_name.len == 0) continue; 2357 const feature_zig_name = (try llvmFeatureNameToZigNameOmit( 2358 arena, 2359 target, 2360 feature_llvm_name, 2361 )) orelse continue; 2362 try deps.append(feature_zig_name); 2363 } 2364 try all_cpus.append(.{ 2365 .llvm_name = llvm_name, 2366 .zig_name = zig_name, 2367 .features = deps.items, 2368 }); 2369 2370 if (cpu_aliases.get(zig_name)) |aliases| { 2371 alias_it: for (aliases.items) |alias| { 2372 for (target.omit_cpus) |omit_cpu_name| { 2373 if (mem.eql(u8, omit_cpu_name, alias.llvm)) continue :alias_it; 2374 } 2375 2376 try all_cpus.append(.{ 2377 .llvm_name = alias.llvm, 2378 .zig_name = alias.zig, 2379 .features = deps.items, 2380 }); 2381 } 2382 } 2383 } 2384 } 2385 } 2386 2387 collate_progress.end(); 2388 } 2389 2390 for (target.extra_features) |extra_feature| { 2391 try features_table.put(extra_feature.zig_name, extra_feature); 2392 try all_features.append(extra_feature); 2393 } 2394 for (target.extra_cpus) |extra_cpu| { 2395 try all_cpus.append(extra_cpu); 2396 } 2397 mem.sort(Feature, all_features.items, {}, featureLessThan); 2398 mem.sort(Cpu, all_cpus.items, {}, cpuLessThan); 2399 2400 const render_progress = progress_node.start("rendering Zig code", 0); 2401 2402 var target_dir = try job.zig_src_dir.openDir(io, "lib/std/Target", .{}); 2403 defer target_dir.close(io); 2404 2405 const zig_code_basename = try std.fmt.allocPrint(arena, "{s}.zig", .{target.zig_name}); 2406 var zig_code_file = try target_dir.createFile(io, zig_code_basename, .{}); 2407 defer zig_code_file.close(io); 2408 2409 var zig_code_file_buffer: [4096]u8 = undefined; 2410 var zig_code_file_writer = zig_code_file.writer(io, &zig_code_file_buffer); 2411 const w = &zig_code_file_writer.interface; 2412 2413 try w.writeAll( 2414 \\//! This file is auto-generated by tools/update_cpu_features.zig. 2415 \\ 2416 \\const std = @import("../std.zig"); 2417 \\const CpuFeature = std.Target.Cpu.Feature; 2418 \\const CpuModel = std.Target.Cpu.Model; 2419 \\ 2420 \\pub const Feature = enum { 2421 ); 2422 2423 for (all_features.items, 0..) |feature, i| { 2424 try w.print("\n {f},", .{std.zig.fmtIdPU(feature.zig_name)}); 2425 2426 if (i == all_features.items.len - 1) try w.writeAll("\n"); 2427 } 2428 2429 try w.writeAll( 2430 \\}; 2431 \\ 2432 \\pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet; 2433 \\pub const featureSetHas = CpuFeature.FeatureSetFns(Feature).featureSetHas; 2434 \\pub const featureSetHasAny = CpuFeature.FeatureSetFns(Feature).featureSetHasAny; 2435 \\pub const featureSetHasAll = CpuFeature.FeatureSetFns(Feature).featureSetHasAll; 2436 \\ 2437 \\pub const all_features = blk: { 2438 \\ 2439 ); 2440 if (target.branch_quota) |branch_quota| { 2441 try w.print(" @setEvalBranchQuota({d});\n", .{branch_quota}); 2442 } 2443 try w.writeAll( 2444 \\ const len = @typeInfo(Feature).@"enum".field_names.len; 2445 \\ std.debug.assert(len <= CpuFeature.Set.needed_bit_count); 2446 \\ var result: [len]CpuFeature = undefined; 2447 \\ 2448 ); 2449 2450 for (all_features.items) |feature| { 2451 if (feature.llvm_name) |llvm_name| { 2452 try w.print( 2453 \\ result[@intFromEnum(Feature.{f})] = .{{ 2454 \\ .llvm_name = "{f}", 2455 \\ .description = "{f}", 2456 \\ .dependencies = featureSet(&[_]Feature{{ 2457 , 2458 .{ 2459 std.zig.fmtIdPU(feature.zig_name), 2460 std.zig.fmtString(llvm_name), 2461 std.zig.fmtString(feature.desc), 2462 }, 2463 ); 2464 } else { 2465 try w.print( 2466 \\ result[@intFromEnum(Feature.{f})] = .{{ 2467 \\ .llvm_name = null, 2468 \\ .description = "{f}", 2469 \\ .dependencies = featureSet(&[_]Feature{{ 2470 , 2471 .{ 2472 std.zig.fmtIdPU(feature.zig_name), 2473 std.zig.fmtString(feature.desc), 2474 }, 2475 ); 2476 } 2477 var deps_set = std.StringHashMap(void).init(arena); 2478 for (feature.deps) |dep| { 2479 try putDep(&deps_set, features_table, dep); 2480 } 2481 try pruneFeatures(arena, features_table, &deps_set); 2482 var dependencies = std.array_list.Managed([]const u8).init(arena); 2483 { 2484 var it = deps_set.keyIterator(); 2485 while (it.next()) |key| { 2486 try dependencies.append(key.*); 2487 } 2488 } 2489 mem.sort([]const u8, dependencies.items, {}, asciiLessThan); 2490 2491 if (dependencies.items.len == 0) { 2492 try w.writeAll( 2493 \\}), 2494 \\ }; 2495 \\ 2496 ); 2497 } else { 2498 try w.writeAll("\n"); 2499 for (dependencies.items) |dep| { 2500 try w.print(" .{f},\n", .{std.zig.fmtIdPU(dep)}); 2501 } 2502 try w.writeAll( 2503 \\ }), 2504 \\ }; 2505 \\ 2506 ); 2507 } 2508 } 2509 try w.writeAll( 2510 \\ const ti = @typeInfo(Feature); 2511 \\ for (&result, 0..) |*elem, i| { 2512 \\ elem.index = i; 2513 \\ elem.name = ti.@"enum".field_names[i]; 2514 \\ } 2515 \\ break :blk result; 2516 \\}; 2517 \\ 2518 \\pub const cpu = struct { 2519 \\ 2520 ); 2521 for (all_cpus.items) |cpu| { 2522 var deps_set = std.StringHashMap(void).init(arena); 2523 for (cpu.features) |feature_zig_name| { 2524 try putDep(&deps_set, features_table, feature_zig_name); 2525 } 2526 try pruneFeatures(arena, features_table, &deps_set); 2527 var cpu_features = std.array_list.Managed([]const u8).init(arena); 2528 { 2529 var it = deps_set.keyIterator(); 2530 while (it.next()) |key| { 2531 try cpu_features.append(key.*); 2532 } 2533 } 2534 mem.sort([]const u8, cpu_features.items, {}, asciiLessThan); 2535 if (cpu.llvm_name) |llvm_name| { 2536 try w.print( 2537 \\ pub const {f}: CpuModel = .{{ 2538 \\ .name = "{f}", 2539 \\ .llvm_name = "{f}", 2540 \\ .features = featureSet(&[_]Feature{{ 2541 , .{ 2542 std.zig.fmtId(cpu.zig_name), 2543 std.zig.fmtString(cpu.zig_name), 2544 std.zig.fmtString(llvm_name), 2545 }); 2546 } else { 2547 try w.print( 2548 \\ pub const {f}: CpuModel = .{{ 2549 \\ .name = "{f}", 2550 \\ .llvm_name = null, 2551 \\ .features = featureSet(&[_]Feature{{ 2552 , .{ 2553 std.zig.fmtId(cpu.zig_name), 2554 std.zig.fmtString(cpu.zig_name), 2555 }); 2556 } 2557 if (cpu_features.items.len == 0) { 2558 try w.writeAll( 2559 \\}), 2560 \\ }; 2561 \\ 2562 ); 2563 } else { 2564 try w.writeAll("\n"); 2565 for (cpu_features.items) |feature_zig_name| { 2566 try w.print(" .{f},\n", .{std.zig.fmtIdPU(feature_zig_name)}); 2567 } 2568 try w.writeAll( 2569 \\ }), 2570 \\ }; 2571 \\ 2572 ); 2573 } 2574 } 2575 2576 try w.writeAll( 2577 \\}; 2578 \\ 2579 ); 2580 try w.flush(); 2581 2582 render_progress.end(); 2583 } 2584 2585 fn usageAndExit(arg0: []const u8, code: u8) noreturn { 2586 const stderr = std.debug.lockStderr(&.{}); 2587 const w = &stderr.file_writer.interface; 2588 w.print( 2589 \\Usage: {s} /path/to/llvm-tblgen /path/git/llvm-project /path/git/zig [zig_name filter] 2590 \\ 2591 \\Updates lib/std/target/<target>.zig from llvm/lib/Target/<Target>/<Target>.td . 2592 \\ 2593 \\On a less beefy system, or when debugging, compile with -fsingle-threaded. 2594 \\ 2595 , .{arg0}) catch std.process.exit(1); 2596 std.process.exit(code); 2597 } 2598 2599 fn featureLessThan(_: void, a: Feature, b: Feature) bool { 2600 return std.ascii.lessThanIgnoreCase(a.zig_name, b.zig_name); 2601 } 2602 2603 fn cpuLessThan(_: void, a: Cpu, b: Cpu) bool { 2604 return std.ascii.lessThanIgnoreCase(a.zig_name, b.zig_name); 2605 } 2606 2607 fn asciiLessThan(_: void, a: []const u8, b: []const u8) bool { 2608 return std.ascii.lessThanIgnoreCase(a, b); 2609 } 2610 2611 fn llvmNameToZigName(arena: mem.Allocator, llvm_name: []const u8) ![]const u8 { 2612 const duped = try arena.dupe(u8, llvm_name); 2613 for (duped) |*byte| switch (byte.*) { 2614 '-', '.' => byte.* = '_', 2615 else => continue, 2616 }; 2617 return duped; 2618 } 2619 2620 fn llvmFeatureNameToZigNameOmit( 2621 arena: mem.Allocator, 2622 target: ArchTarget, 2623 llvm_name: []const u8, 2624 ) !?[]const u8 { 2625 for (target.feature_overrides) |feature_override| { 2626 if (mem.eql(u8, feature_override.llvm_name, llvm_name)) { 2627 if (feature_override.omit) return null; 2628 return feature_override.zig_name orelse break; 2629 } 2630 } 2631 return try llvmNameToZigName(arena, llvm_name); 2632 } 2633 2634 fn hasSuperclass(obj: *const json.ObjectMap, class_name: []const u8) bool { 2635 const superclasses_json = obj.get("!superclasses") orelse return false; 2636 for (superclasses_json.array.items) |superclass_json| { 2637 const superclass = superclass_json.string; 2638 if (std.mem.eql(u8, superclass, class_name)) { 2639 return true; 2640 } 2641 } 2642 return false; 2643 } 2644 2645 fn pruneFeatures( 2646 arena: mem.Allocator, 2647 features_table: std.StringHashMap(Feature), 2648 deps_set: *std.StringHashMap(void), 2649 ) !void { 2650 // For each element, recursively iterate over the dependencies and add 2651 // everything we find to a "deletion set". 2652 // Then, iterate over the deletion set and delete all that stuff from `deps_set`. 2653 var deletion_set = std.StringHashMap(void).init(arena); 2654 { 2655 var it = deps_set.keyIterator(); 2656 while (it.next()) |key| { 2657 const feature = features_table.get(key.*).?; 2658 try walkFeatures(features_table, &deletion_set, feature); 2659 } 2660 } 2661 { 2662 var it = deletion_set.keyIterator(); 2663 while (it.next()) |key| { 2664 _ = deps_set.remove(key.*); 2665 } 2666 } 2667 } 2668 2669 fn walkFeatures( 2670 features_table: std.StringHashMap(Feature), 2671 deletion_set: *std.StringHashMap(void), 2672 feature: Feature, 2673 ) error{OutOfMemory}!void { 2674 for (feature.deps) |dep| { 2675 try deletion_set.put(dep, {}); 2676 const other_feature = features_table.get(dep).?; 2677 try walkFeatures(features_table, deletion_set, other_feature); 2678 } 2679 } 2680 2681 fn putDep( 2682 deps_set: *std.StringHashMap(void), 2683 features_table: std.StringHashMap(Feature), 2684 zig_feature_name: []const u8, 2685 ) error{OutOfMemory}!void { 2686 const feature = features_table.get(zig_feature_name).?; 2687 if (feature.flatten) { 2688 for (feature.deps) |dep| { 2689 try putDep(deps_set, features_table, dep); 2690 } 2691 } else { 2692 try deps_set.put(zig_feature_name, {}); 2693 } 2694 } 2695