blob 10ea6508 (48980B) - Raw
1 const std = @import("std"); 2 const builtin = @import("builtin"); 3 const fs = std.fs; 4 const mem = std.mem; 5 const json = std.json; 6 const assert = std.debug.assert; 7 8 // All references to other features are based on "zig name" as the key. 9 10 const FeatureOverride = struct { 11 llvm_name: []const u8, 12 /// If true, completely omit the feature; as if it does not exist. 13 omit: bool = false, 14 /// If true, omit the feature, but all the dependencies of the feature 15 /// are added in its place. 16 flatten: bool = false, 17 zig_name: ?[]const u8 = null, 18 desc: ?[]const u8 = null, 19 omit_deps: []const []const u8 = &.{}, 20 extra_deps: []const []const u8 = &.{}, 21 }; 22 23 const Cpu = struct { 24 llvm_name: ?[]const u8, 25 zig_name: []const u8, 26 features: []const []const u8, 27 }; 28 29 const Feature = struct { 30 llvm_name: ?[]const u8 = null, 31 zig_name: []const u8, 32 desc: []const u8, 33 deps: []const []const u8, 34 flatten: bool = false, 35 }; 36 37 const LlvmTarget = struct { 38 zig_name: []const u8, 39 llvm_name: []const u8, 40 td_name: []const u8, 41 feature_overrides: []const FeatureOverride = &.{}, 42 extra_cpus: []const Cpu = &.{}, 43 extra_features: []const Feature = &.{}, 44 omit_cpus: []const []const u8 = &.{}, 45 branch_quota: ?usize = null, 46 }; 47 48 const llvm_targets = [_]LlvmTarget{ 49 .{ 50 .zig_name = "aarch64", 51 .llvm_name = "AArch64", 52 .td_name = "AArch64.td", 53 .branch_quota = 2000, 54 .feature_overrides = &.{ 55 .{ 56 .llvm_name = "all", 57 .omit = true, 58 }, 59 .{ 60 .llvm_name = "v8a", 61 .extra_deps = &.{ "fp_armv8", "neon" }, 62 }, 63 .{ 64 .llvm_name = "CONTEXTIDREL2", 65 .zig_name = "contextidr_el2", 66 .desc = "Enable RW operand Context ID Register (EL2)", 67 }, 68 .{ 69 .llvm_name = "neoversee1", 70 .flatten = true, 71 }, 72 .{ 73 .llvm_name = "neoversen1", 74 .flatten = true, 75 }, 76 .{ 77 .llvm_name = "neoversen2", 78 .flatten = true, 79 }, 80 .{ 81 .llvm_name = "neoversev1", 82 .flatten = true, 83 }, 84 .{ 85 .llvm_name = "neoversev2", 86 .flatten = true, 87 }, 88 .{ 89 .llvm_name = "neoverse512tvb", 90 .flatten = true, 91 }, 92 .{ 93 .llvm_name = "exynosm3", 94 .flatten = true, 95 .extra_deps = &.{"v8a"}, 96 }, 97 .{ 98 .llvm_name = "exynosm4", 99 .flatten = true, 100 }, 101 .{ 102 .llvm_name = "v8.1a", 103 .extra_deps = &.{"v8a"}, 104 }, 105 .{ 106 .llvm_name = "a35", 107 .flatten = true, 108 .extra_deps = &.{"v8a"}, 109 }, 110 .{ 111 .llvm_name = "a53", 112 .flatten = true, 113 .extra_deps = &.{"v8a"}, 114 }, 115 .{ 116 .llvm_name = "a55", 117 .flatten = true, 118 }, 119 .{ 120 .llvm_name = "a57", 121 .flatten = true, 122 .extra_deps = &.{"v8a"}, 123 }, 124 .{ 125 .llvm_name = "a64fx", 126 .flatten = true, 127 }, 128 .{ 129 .llvm_name = "a72", 130 .flatten = true, 131 .extra_deps = &.{"v8a"}, 132 }, 133 .{ 134 .llvm_name = "a73", 135 .flatten = true, 136 .extra_deps = &.{"v8a"}, 137 }, 138 .{ 139 .llvm_name = "a75", 140 .flatten = true, 141 }, 142 .{ 143 .llvm_name = "a77", 144 .flatten = true, 145 }, 146 .{ 147 .llvm_name = "a715", 148 .flatten = true, 149 }, 150 .{ 151 .llvm_name = "ampere1a", 152 .flatten = true, 153 }, 154 .{ 155 .llvm_name = "apple-a7", 156 .flatten = true, 157 }, 158 .{ 159 .llvm_name = "apple-a10", 160 .flatten = true, 161 }, 162 .{ 163 .llvm_name = "apple-a11", 164 .flatten = true, 165 }, 166 .{ 167 .llvm_name = "apple-a12", 168 .flatten = true, 169 }, 170 .{ 171 .llvm_name = "apple-a13", 172 .flatten = true, 173 }, 174 .{ 175 .llvm_name = "apple-a14", 176 .flatten = true, 177 }, 178 .{ 179 .llvm_name = "apple-a15", 180 .flatten = true, 181 }, 182 .{ 183 .llvm_name = "apple-a16", 184 .flatten = true, 185 }, 186 .{ 187 .llvm_name = "apple-a17", 188 .flatten = true, 189 }, 190 .{ 191 .llvm_name = "apple-a7-sysreg", 192 .flatten = true, 193 }, 194 .{ 195 .llvm_name = "carmel", 196 .flatten = true, 197 }, 198 .{ 199 .llvm_name = "cortex-a78", 200 .flatten = true, 201 }, 202 .{ 203 .llvm_name = "cortex-x1", 204 .flatten = true, 205 }, 206 .{ 207 .llvm_name = "cortex-x2", 208 .flatten = true, 209 }, 210 .{ 211 .llvm_name = "cortex-x3", 212 .flatten = true, 213 }, 214 .{ 215 .llvm_name = "cortex-x4", 216 .flatten = true, 217 }, 218 .{ 219 .llvm_name = "falkor", 220 .flatten = true, 221 .extra_deps = &.{"v8a"}, 222 }, 223 .{ 224 .llvm_name = "kryo", 225 .flatten = true, 226 .extra_deps = &.{"v8a"}, 227 }, 228 .{ 229 .llvm_name = "saphira", 230 .flatten = true, 231 }, 232 .{ 233 .llvm_name = "thunderx", 234 .flatten = true, 235 .extra_deps = &.{"v8a"}, 236 }, 237 .{ 238 .llvm_name = "thunderx2t99", 239 .flatten = true, 240 }, 241 .{ 242 .llvm_name = "thunderx3t110", 243 .flatten = true, 244 }, 245 .{ 246 .llvm_name = "thunderxt81", 247 .flatten = true, 248 .extra_deps = &.{"v8a"}, 249 }, 250 .{ 251 .llvm_name = "thunderxt83", 252 .flatten = true, 253 .extra_deps = &.{"v8a"}, 254 }, 255 .{ 256 .llvm_name = "thunderxt88", 257 .flatten = true, 258 .extra_deps = &.{"v8a"}, 259 }, 260 .{ 261 .llvm_name = "tsv110", 262 .flatten = true, 263 }, 264 .{ 265 .llvm_name = "ampere1", 266 .flatten = true, 267 }, 268 .{ 269 .llvm_name = "ampere1b", 270 .flatten = true, 271 }, 272 }, 273 .extra_cpus = &.{ 274 .{ 275 .llvm_name = null, 276 .zig_name = "exynos_m1", 277 .features = &.{ 278 "crc", 279 "crypto", 280 "exynos_cheap_as_move", 281 "force_32bit_jump_tables", 282 "fuse_aes", 283 "perfmon", 284 "slow_misaligned_128store", 285 "slow_paired_128", 286 "use_postra_scheduler", 287 "use_reciprocal_square_root", 288 "v8a", 289 }, 290 }, 291 .{ 292 .llvm_name = null, 293 .zig_name = "exynos_m2", 294 .features = &.{ 295 "crc", 296 "crypto", 297 "exynos_cheap_as_move", 298 "force_32bit_jump_tables", 299 "fuse_aes", 300 "perfmon", 301 "slow_misaligned_128store", 302 "slow_paired_128", 303 "use_postra_scheduler", 304 "v8a", 305 }, 306 }, 307 .{ 308 .llvm_name = null, 309 .zig_name = "xgene1", 310 .features = &.{ 311 "fp_armv8", 312 "neon", 313 "perfmon", 314 "v8a", 315 }, 316 }, 317 .{ 318 .llvm_name = null, 319 .zig_name = "emag", 320 .features = &.{ 321 "crc", 322 "crypto", 323 "fp_armv8", 324 "neon", 325 "perfmon", 326 "v8a", 327 }, 328 }, 329 }, 330 }, 331 .{ 332 .zig_name = "amdgpu", 333 .llvm_name = "AMDGPU", 334 .td_name = "AMDGPU.td", 335 .feature_overrides = &.{ 336 .{ 337 .llvm_name = "DumpCode", 338 .omit = true, 339 }, 340 .{ 341 .llvm_name = "dumpcode", 342 .omit = true, 343 }, 344 .{ 345 .llvm_name = "enable-ds128", 346 .zig_name = "ds128", 347 }, 348 .{ 349 .llvm_name = "enable-flat-scratch", 350 .zig_name = "flat_scratch", 351 }, 352 .{ 353 .llvm_name = "enable-prt-strict-null", 354 .zig_name = "prt_strict_null", 355 }, 356 }, 357 }, 358 .{ 359 .zig_name = "arc", 360 .llvm_name = "ARC", 361 .td_name = "ARC.td", 362 }, 363 .{ 364 .zig_name = "arm", 365 .llvm_name = "ARM", 366 .td_name = "ARM.td", 367 .branch_quota = 10000, 368 .extra_cpus = &.{ 369 .{ 370 .llvm_name = "generic", 371 .zig_name = "baseline", 372 .features = &.{"v7a"}, 373 }, 374 .{ 375 .llvm_name = null, 376 .zig_name = "exynos_m1", 377 .features = &.{ "v8a", "exynos" }, 378 }, 379 .{ 380 .llvm_name = null, 381 .zig_name = "exynos_m2", 382 .features = &.{ "v8a", "exynos" }, 383 }, 384 }, 385 .feature_overrides = &.{ 386 .{ 387 .llvm_name = "cortex-a78", 388 .flatten = true, 389 }, 390 .{ 391 .llvm_name = "cortex-a710", 392 .flatten = true, 393 }, 394 .{ 395 .llvm_name = "cortex-m4", 396 .omit_deps = &.{"vfp4d16sp"}, 397 }, 398 .{ 399 .llvm_name = "cortex-m7", 400 .omit_deps = &.{"fp_armv8d16"}, 401 }, 402 .{ 403 .llvm_name = "cortex-m33", 404 .omit_deps = &.{ "fp_armv8d16sp", "dsp" }, 405 }, 406 .{ 407 .llvm_name = "cortex-m35p", 408 .omit_deps = &.{ "fp_armv8d16sp", "dsp" }, 409 }, 410 .{ 411 .llvm_name = "cortex-m55", 412 .omit_deps = &.{ "mve_fp", "fp_armv8d16" }, 413 }, 414 .{ 415 .llvm_name = "cortex-m85", 416 .omit_deps = &.{ "mve_fp", "pacbti", "fp_armv8d16" }, 417 .extra_deps = &.{"trustzone"}, 418 }, 419 .{ 420 .llvm_name = "cortex-x1c", 421 .flatten = true, 422 }, 423 .{ 424 .llvm_name = "r5", 425 .flatten = true, 426 }, 427 .{ 428 .llvm_name = "r52", 429 .flatten = true, 430 }, 431 .{ 432 .llvm_name = "r7", 433 .flatten = true, 434 }, 435 .{ 436 .llvm_name = "m7", 437 .flatten = true, 438 }, 439 .{ 440 .llvm_name = "krait", 441 .flatten = true, 442 }, 443 .{ 444 .llvm_name = "kryo", 445 .flatten = true, 446 }, 447 .{ 448 .llvm_name = "cortex-x1", 449 .flatten = true, 450 }, 451 .{ 452 .llvm_name = "neoverse-v1", 453 .flatten = true, 454 }, 455 .{ 456 .llvm_name = "a5", 457 .flatten = true, 458 }, 459 .{ 460 .llvm_name = "a7", 461 .flatten = true, 462 }, 463 .{ 464 .llvm_name = "a8", 465 .flatten = true, 466 }, 467 .{ 468 .llvm_name = "a9", 469 .flatten = true, 470 }, 471 .{ 472 .llvm_name = "a12", 473 .flatten = true, 474 }, 475 .{ 476 .llvm_name = "a15", 477 .flatten = true, 478 }, 479 .{ 480 .llvm_name = "a17", 481 .flatten = true, 482 }, 483 .{ 484 .llvm_name = "a32", 485 .flatten = true, 486 }, 487 .{ 488 .llvm_name = "a35", 489 .flatten = true, 490 }, 491 .{ 492 .llvm_name = "a53", 493 .flatten = true, 494 }, 495 .{ 496 .llvm_name = "a55", 497 .flatten = true, 498 }, 499 .{ 500 .llvm_name = "a57", 501 .flatten = true, 502 }, 503 .{ 504 .llvm_name = "a72", 505 .flatten = true, 506 }, 507 .{ 508 .llvm_name = "a73", 509 .flatten = true, 510 }, 511 .{ 512 .llvm_name = "a75", 513 .flatten = true, 514 }, 515 .{ 516 .llvm_name = "a77", 517 .flatten = true, 518 }, 519 .{ 520 .llvm_name = "a78c", 521 .flatten = true, 522 }, 523 .{ 524 .llvm_name = "armv2", 525 .zig_name = "v2", 526 .extra_deps = &.{"strict_align"}, 527 }, 528 .{ 529 .llvm_name = "armv2a", 530 .zig_name = "v2a", 531 .extra_deps = &.{"strict_align"}, 532 }, 533 .{ 534 .llvm_name = "armv3", 535 .zig_name = "v3", 536 .extra_deps = &.{"strict_align"}, 537 }, 538 .{ 539 .llvm_name = "armv3m", 540 .zig_name = "v3m", 541 .extra_deps = &.{"strict_align"}, 542 }, 543 .{ 544 .llvm_name = "armv4", 545 .zig_name = "v4", 546 .extra_deps = &.{"strict_align"}, 547 }, 548 .{ 549 .llvm_name = "armv4t", 550 .zig_name = "v4t", 551 .extra_deps = &.{"strict_align"}, 552 }, 553 .{ 554 .llvm_name = "armv5t", 555 .zig_name = "v5t", 556 .extra_deps = &.{"strict_align"}, 557 }, 558 .{ 559 .llvm_name = "armv5te", 560 .zig_name = "v5te", 561 .extra_deps = &.{"strict_align"}, 562 }, 563 .{ 564 .llvm_name = "armv5tej", 565 .zig_name = "v5tej", 566 .extra_deps = &.{"strict_align"}, 567 }, 568 .{ 569 .llvm_name = "armv6", 570 .zig_name = "v6", 571 }, 572 .{ 573 .llvm_name = "armv6-m", 574 .zig_name = "v6m", 575 }, 576 .{ 577 .llvm_name = "armv6j", 578 .zig_name = "v6j", 579 }, 580 .{ 581 .llvm_name = "armv6k", 582 .zig_name = "v6k", 583 }, 584 .{ 585 .llvm_name = "armv6kz", 586 .zig_name = "v6kz", 587 }, 588 .{ 589 .llvm_name = "armv6s-m", 590 .zig_name = "v6sm", 591 }, 592 .{ 593 .llvm_name = "armv6t2", 594 .zig_name = "v6t2", 595 }, 596 .{ 597 .llvm_name = "armv7-a", 598 .zig_name = "v7a", 599 }, 600 .{ 601 .llvm_name = "armv7-m", 602 .zig_name = "v7m", 603 }, 604 .{ 605 .llvm_name = "armv7-r", 606 .zig_name = "v7r", 607 }, 608 .{ 609 .llvm_name = "armv7e-m", 610 .zig_name = "v7em", 611 }, 612 .{ 613 .llvm_name = "armv7k", 614 .zig_name = "v7k", 615 }, 616 .{ 617 .llvm_name = "armv7s", 618 .zig_name = "v7s", 619 }, 620 .{ 621 .llvm_name = "armv7ve", 622 .zig_name = "v7ve", 623 }, 624 .{ 625 .llvm_name = "armv8.1-a", 626 .zig_name = "v8_1a", 627 }, 628 .{ 629 .llvm_name = "armv8.1-m.main", 630 .zig_name = "v8_1m_main", 631 }, 632 .{ 633 .llvm_name = "armv8.2-a", 634 .zig_name = "v8_2a", 635 }, 636 .{ 637 .llvm_name = "armv8.3-a", 638 .zig_name = "v8_3a", 639 }, 640 .{ 641 .llvm_name = "armv8.4-a", 642 .zig_name = "v8_4a", 643 }, 644 .{ 645 .llvm_name = "armv8.5-a", 646 .zig_name = "v8_5a", 647 }, 648 .{ 649 .llvm_name = "armv8.6-a", 650 .zig_name = "v8_6a", 651 }, 652 .{ 653 .llvm_name = "armv8.7-a", 654 .zig_name = "v8_7a", 655 }, 656 .{ 657 .llvm_name = "armv8.8-a", 658 .zig_name = "v8_8a", 659 }, 660 .{ 661 .llvm_name = "armv8.9-a", 662 .zig_name = "v8_9a", 663 }, 664 .{ 665 .llvm_name = "armv8-a", 666 .zig_name = "v8a", 667 }, 668 .{ 669 .llvm_name = "armv8-m.base", 670 .zig_name = "v8m", 671 }, 672 .{ 673 .llvm_name = "armv8-m.main", 674 .zig_name = "v8m_main", 675 }, 676 .{ 677 .llvm_name = "armv8-r", 678 .zig_name = "v8r", 679 }, 680 .{ 681 .llvm_name = "armv9.1-a", 682 .zig_name = "v9_1a", 683 }, 684 .{ 685 .llvm_name = "armv9.2-a", 686 .zig_name = "v9_2a", 687 }, 688 .{ 689 .llvm_name = "armv9.3-a", 690 .zig_name = "v9_3a", 691 }, 692 .{ 693 .llvm_name = "armv9.4-a", 694 .zig_name = "v9_4a", 695 }, 696 .{ 697 .llvm_name = "armv9.5-a", 698 .zig_name = "v9_5a", 699 }, 700 .{ 701 .llvm_name = "armv9-a", 702 .zig_name = "v9a", 703 }, 704 .{ 705 .llvm_name = "v4t", 706 .zig_name = "has_v4t", 707 }, 708 .{ 709 .llvm_name = "v5t", 710 .zig_name = "has_v5t", 711 }, 712 .{ 713 .llvm_name = "v5te", 714 .zig_name = "has_v5te", 715 }, 716 .{ 717 .llvm_name = "v6", 718 .zig_name = "has_v6", 719 }, 720 .{ 721 .llvm_name = "v6k", 722 .zig_name = "has_v6k", 723 }, 724 .{ 725 .llvm_name = "v6m", 726 .zig_name = "has_v6m", 727 }, 728 .{ 729 .llvm_name = "v6t2", 730 .zig_name = "has_v6t2", 731 }, 732 .{ 733 .llvm_name = "v7", 734 .zig_name = "has_v7", 735 }, 736 .{ 737 .llvm_name = "v7clrex", 738 .zig_name = "has_v7clrex", 739 }, 740 .{ 741 .llvm_name = "v8", 742 .zig_name = "has_v8", 743 }, 744 .{ 745 .llvm_name = "v8m", 746 .zig_name = "has_v8m", 747 }, 748 .{ 749 .llvm_name = "v8m.main", 750 .zig_name = "has_v8m_main", 751 }, 752 .{ 753 .llvm_name = "v8.1a", 754 .zig_name = "has_v8_1a", 755 }, 756 .{ 757 .llvm_name = "v8.1m.main", 758 .zig_name = "has_v8_1m_main", 759 }, 760 .{ 761 .llvm_name = "v8.2a", 762 .zig_name = "has_v8_2a", 763 }, 764 .{ 765 .llvm_name = "v8.3a", 766 .zig_name = "has_v8_3a", 767 }, 768 .{ 769 .llvm_name = "v8.4a", 770 .zig_name = "has_v8_4a", 771 }, 772 .{ 773 .llvm_name = "v8.5a", 774 .zig_name = "has_v8_5a", 775 }, 776 .{ 777 .llvm_name = "v8.6a", 778 .zig_name = "has_v8_6a", 779 }, 780 .{ 781 .llvm_name = "v8.7a", 782 .zig_name = "has_v8_7a", 783 }, 784 .{ 785 .llvm_name = "v8.8a", 786 .zig_name = "has_v8_8a", 787 }, 788 .{ 789 .llvm_name = "v8.9a", 790 .zig_name = "has_v8_9a", 791 }, 792 .{ 793 .llvm_name = "v9a", 794 .zig_name = "has_v9a", 795 }, 796 .{ 797 .llvm_name = "v9.1a", 798 .zig_name = "has_v9_1a", 799 }, 800 .{ 801 .llvm_name = "v9.2a", 802 .zig_name = "has_v9_2a", 803 }, 804 .{ 805 .llvm_name = "v9.3a", 806 .zig_name = "has_v9_3a", 807 }, 808 .{ 809 .llvm_name = "v9.4a", 810 .zig_name = "has_v9_4a", 811 }, 812 }, 813 // LLVM removed support for v2 and v3 but zig wants to support targeting old hardware 814 .extra_features = &.{ 815 .{ 816 .zig_name = "v2", 817 .desc = "ARMv2 architecture", 818 .deps = &.{"strict_align"}, 819 }, 820 .{ 821 .zig_name = "v2a", 822 .desc = "ARMv2a architecture", 823 .deps = &.{"strict_align"}, 824 }, 825 .{ 826 .zig_name = "v3", 827 .desc = "ARMv3 architecture", 828 .deps = &.{"strict_align"}, 829 }, 830 .{ 831 .zig_name = "v3m", 832 .desc = "ARMv3m architecture", 833 .deps = &.{"strict_align"}, 834 }, 835 }, 836 }, 837 .{ 838 .zig_name = "avr", 839 .llvm_name = "AVR", 840 .td_name = "AVR.td", 841 }, 842 .{ 843 .zig_name = "bpf", 844 .llvm_name = "BPF", 845 .td_name = "BPF.td", 846 }, 847 .{ 848 .zig_name = "csky", 849 .llvm_name = "CSKY", 850 .td_name = "CSKY.td", 851 }, 852 .{ 853 .zig_name = "hexagon", 854 .llvm_name = "Hexagon", 855 .td_name = "Hexagon.td", 856 }, 857 .{ 858 .zig_name = "lanai", 859 .llvm_name = "Lanai", 860 .td_name = "Lanai.td", 861 }, 862 .{ 863 .zig_name = "loongarch", 864 .llvm_name = "LoongArch", 865 .td_name = "LoongArch.td", 866 }, 867 .{ 868 .zig_name = "m68k", 869 .llvm_name = "M68k", 870 .td_name = "M68k.td", 871 }, 872 .{ 873 .zig_name = "msp430", 874 .llvm_name = "MSP430", 875 .td_name = "MSP430.td", 876 }, 877 .{ 878 .zig_name = "mips", 879 .llvm_name = "Mips", 880 .td_name = "Mips.td", 881 }, 882 .{ 883 .zig_name = "nvptx", 884 .llvm_name = "NVPTX", 885 .td_name = "NVPTX.td", 886 }, 887 .{ 888 .zig_name = "powerpc", 889 .llvm_name = "PowerPC", 890 .td_name = "PPC.td", 891 .feature_overrides = &.{ 892 .{ 893 .llvm_name = "ppc32", 894 .omit = true, 895 }, 896 }, 897 }, 898 .{ 899 .zig_name = "riscv", 900 .llvm_name = "RISCV", 901 .td_name = "RISCV.td", 902 .feature_overrides = &.{ 903 .{ 904 .llvm_name = "sifive7", 905 .flatten = true, 906 }, 907 }, 908 .extra_cpus = &.{ 909 .{ 910 .llvm_name = null, 911 .zig_name = "baseline_rv32", 912 .features = &.{ "32bit", "a", "c", "d", "f", "m" }, 913 }, 914 .{ 915 .llvm_name = null, 916 .zig_name = "baseline_rv64", 917 .features = &.{ "64bit", "a", "c", "d", "f", "m" }, 918 }, 919 }, 920 }, 921 .{ 922 .zig_name = "sparc", 923 .llvm_name = "Sparc", 924 .td_name = "Sparc.td", 925 }, 926 // TODO: merge tools/update_spirv_features.zig into this script 927 //.{ 928 // .zig_name = "spirv", 929 // .llvm_name = "SPIRV", 930 // .td_name = "SPIRV.td", 931 //}, 932 .{ 933 .zig_name = "s390x", 934 .llvm_name = "SystemZ", 935 .td_name = "SystemZ.td", 936 }, 937 .{ 938 .zig_name = "ve", 939 .llvm_name = "VE", 940 .td_name = "VE.td", 941 }, 942 .{ 943 .zig_name = "wasm", 944 .llvm_name = "WebAssembly", 945 .td_name = "WebAssembly.td", 946 }, 947 .{ 948 .zig_name = "x86", 949 .llvm_name = "X86", 950 .td_name = "X86.td", 951 .feature_overrides = &.{ 952 .{ 953 .llvm_name = "64bit-mode", 954 .omit = true, 955 }, 956 .{ 957 .llvm_name = "lakemont", 958 .extra_deps = &.{"soft_float"}, 959 }, 960 }, 961 .omit_cpus = &.{ 962 // LLVM defines a bunch of dumb aliases with foreach loops in X86.td. 963 "pentium_mmx", 964 "pentium_pro", 965 "pentium_ii", 966 "pentium_3m", 967 "pentium_iii_no_xmm_regs", 968 "pentium_iii", 969 "pentium_m", 970 "pentium4m", 971 "pentium_4", 972 "pentium_4_sse3", 973 "core_2_duo_ssse3", 974 "core_2_duo_sse4_1", 975 "atom_sse4_2", 976 "goldmont_plus", 977 "core_i7_sse4_2", 978 "core_aes_pclmulqdq", 979 "corei7-avx", 980 "core_2nd_gen_avx", 981 "core-avx-i", 982 "core_3rd_gen_avx", 983 "core-avx2", 984 "core_4th_gen_avx", 985 "core_4th_gen_avx_tsx", 986 "core_5th_gen_avx", 987 "core_5th_gen_avx_tsx", 988 "mic_avx512", 989 "skylake_avx512", 990 "icelake_client", 991 "icelake_server", 992 "graniterapids_d", 993 }, 994 }, 995 .{ 996 .zig_name = "xcore", 997 .llvm_name = "XCore", 998 .td_name = "XCore.td", 999 }, 1000 .{ 1001 .zig_name = "xtensa", 1002 .llvm_name = "Xtensa", 1003 .td_name = "Xtensa.td", 1004 }, 1005 }; 1006 1007 pub fn main() anyerror!void { 1008 var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); 1009 defer arena_state.deinit(); 1010 const arena = arena_state.allocator(); 1011 1012 const args = try std.process.argsAlloc(arena); 1013 if (args.len <= 1) { 1014 usageAndExit(std.io.getStdErr(), args[0], 1); 1015 } 1016 if (std.mem.eql(u8, args[1], "--help")) { 1017 usageAndExit(std.io.getStdOut(), args[0], 0); 1018 } 1019 if (args.len < 4) { 1020 usageAndExit(std.io.getStdErr(), args[0], 1); 1021 } 1022 1023 const llvm_tblgen_exe = args[1]; 1024 if (std.mem.startsWith(u8, llvm_tblgen_exe, "-")) { 1025 usageAndExit(std.io.getStdErr(), args[0], 1); 1026 } 1027 1028 const llvm_src_root = args[2]; 1029 if (std.mem.startsWith(u8, llvm_src_root, "-")) { 1030 usageAndExit(std.io.getStdErr(), args[0], 1); 1031 } 1032 1033 const zig_src_root = args[3]; 1034 if (std.mem.startsWith(u8, zig_src_root, "-")) { 1035 usageAndExit(std.io.getStdErr(), args[0], 1); 1036 } 1037 1038 var zig_src_dir = try fs.cwd().openDir(zig_src_root, .{}); 1039 defer zig_src_dir.close(); 1040 1041 var progress = std.Progress{}; 1042 const root_progress = progress.start("", llvm_targets.len); 1043 defer root_progress.end(); 1044 1045 if (builtin.single_threaded) { 1046 for (llvm_targets) |llvm_target| { 1047 try processOneTarget(Job{ 1048 .llvm_tblgen_exe = llvm_tblgen_exe, 1049 .llvm_src_root = llvm_src_root, 1050 .zig_src_dir = zig_src_dir, 1051 .root_progress = root_progress, 1052 .llvm_target = llvm_target, 1053 }); 1054 } 1055 } else { 1056 var threads = try arena.alloc(std.Thread, llvm_targets.len); 1057 for (llvm_targets, 0..) |llvm_target, i| { 1058 const job = Job{ 1059 .llvm_tblgen_exe = llvm_tblgen_exe, 1060 .llvm_src_root = llvm_src_root, 1061 .zig_src_dir = zig_src_dir, 1062 .root_progress = root_progress, 1063 .llvm_target = llvm_target, 1064 }; 1065 threads[i] = try std.Thread.spawn(.{}, processOneTarget, .{job}); 1066 } 1067 for (threads) |thread| { 1068 thread.join(); 1069 } 1070 } 1071 } 1072 1073 const Job = struct { 1074 llvm_tblgen_exe: []const u8, 1075 llvm_src_root: []const u8, 1076 zig_src_dir: std.fs.Dir, 1077 root_progress: *std.Progress.Node, 1078 llvm_target: LlvmTarget, 1079 }; 1080 1081 fn processOneTarget(job: Job) anyerror!void { 1082 const llvm_target = job.llvm_target; 1083 1084 var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); 1085 defer arena_state.deinit(); 1086 const arena = arena_state.allocator(); 1087 1088 var progress_node = job.root_progress.start(llvm_target.zig_name, 3); 1089 progress_node.activate(); 1090 defer progress_node.end(); 1091 1092 var tblgen_progress = progress_node.start("invoke llvm-tblgen", 0); 1093 tblgen_progress.activate(); 1094 1095 const child_args = [_][]const u8{ 1096 job.llvm_tblgen_exe, 1097 "--dump-json", 1098 try std.fmt.allocPrint(arena, "{s}/llvm/lib/Target/{s}/{s}", .{ 1099 job.llvm_src_root, 1100 llvm_target.llvm_name, 1101 llvm_target.td_name, 1102 }), 1103 try std.fmt.allocPrint(arena, "-I={s}/llvm/include", .{job.llvm_src_root}), 1104 try std.fmt.allocPrint(arena, "-I={s}/llvm/lib/Target/{s}", .{ 1105 job.llvm_src_root, llvm_target.llvm_name, 1106 }), 1107 }; 1108 1109 const child_result = try std.ChildProcess.run(.{ 1110 .allocator = arena, 1111 .argv = &child_args, 1112 .max_output_bytes = 400 * 1024 * 1024, 1113 }); 1114 tblgen_progress.end(); 1115 if (child_result.stderr.len != 0) { 1116 std.debug.print("{s}\n", .{child_result.stderr}); 1117 } 1118 1119 const json_text = switch (child_result.term) { 1120 .Exited => |code| if (code == 0) child_result.stdout else { 1121 std.debug.print("llvm-tblgen exited with code {d}\n", .{code}); 1122 std.process.exit(1); 1123 }, 1124 else => { 1125 std.debug.print("llvm-tblgen crashed\n", .{}); 1126 std.process.exit(1); 1127 }, 1128 }; 1129 1130 var json_parse_progress = progress_node.start("parse JSON", 0); 1131 json_parse_progress.activate(); 1132 1133 const parsed = try json.parseFromSlice(json.Value, arena, json_text, .{}); 1134 defer parsed.deinit(); 1135 const root_map = &parsed.value.object; 1136 json_parse_progress.end(); 1137 1138 var render_progress = progress_node.start("render zig code", 0); 1139 render_progress.activate(); 1140 1141 var features_table = std.StringHashMap(Feature).init(arena); 1142 var all_features = std.ArrayList(Feature).init(arena); 1143 var all_cpus = std.ArrayList(Cpu).init(arena); 1144 { 1145 var it = root_map.iterator(); 1146 root_it: while (it.next()) |kv| { 1147 if (kv.key_ptr.len == 0) continue; 1148 if (kv.key_ptr.*[0] == '!') continue; 1149 if (kv.value_ptr.* != .object) continue; 1150 if (hasSuperclass(&kv.value_ptr.object, "SubtargetFeature")) { 1151 const llvm_name = kv.value_ptr.object.get("Name").?.string; 1152 if (llvm_name.len == 0) continue; 1153 1154 var zig_name = try llvmNameToZigName(arena, llvm_name); 1155 var desc = kv.value_ptr.object.get("Desc").?.string; 1156 var deps = std.ArrayList([]const u8).init(arena); 1157 var omit = false; 1158 var flatten = false; 1159 var omit_deps: []const []const u8 = &.{}; 1160 var extra_deps: []const []const u8 = &.{}; 1161 for (llvm_target.feature_overrides) |feature_override| { 1162 if (mem.eql(u8, llvm_name, feature_override.llvm_name)) { 1163 if (feature_override.omit) { 1164 // Still put the feature into the table so that we can 1165 // expand dependencies for the feature overrides marked `flatten`. 1166 omit = true; 1167 } 1168 if (feature_override.flatten) { 1169 flatten = true; 1170 } 1171 if (feature_override.zig_name) |override_name| { 1172 zig_name = override_name; 1173 } 1174 if (feature_override.desc) |override_desc| { 1175 desc = override_desc; 1176 } 1177 omit_deps = feature_override.omit_deps; 1178 extra_deps = feature_override.extra_deps; 1179 break; 1180 } 1181 } 1182 const implies = kv.value_ptr.object.get("Implies").?.array; 1183 for (implies.items) |imply| { 1184 const other_key = imply.object.get("def").?.string; 1185 const other_obj = &root_map.getPtr(other_key).?.object; 1186 const other_llvm_name = other_obj.get("Name").?.string; 1187 const other_zig_name = (try llvmNameToZigNameOmit( 1188 arena, 1189 llvm_target, 1190 other_llvm_name, 1191 )) orelse continue; 1192 for (omit_deps) |omit_dep| { 1193 if (mem.eql(u8, other_zig_name, omit_dep)) break; 1194 } else { 1195 try deps.append(other_zig_name); 1196 } 1197 } 1198 for (extra_deps) |extra_dep| { 1199 try deps.append(extra_dep); 1200 } 1201 const feature: Feature = .{ 1202 .llvm_name = llvm_name, 1203 .zig_name = zig_name, 1204 .desc = desc, 1205 .deps = deps.items, 1206 .flatten = flatten, 1207 }; 1208 try features_table.put(zig_name, feature); 1209 if (!omit and !flatten) { 1210 try all_features.append(feature); 1211 } 1212 } 1213 if (hasSuperclass(&kv.value_ptr.object, "Processor")) { 1214 const llvm_name = kv.value_ptr.object.get("Name").?.string; 1215 if (llvm_name.len == 0) continue; 1216 const omitted = for (llvm_target.omit_cpus) |omit_cpu_name| { 1217 if (mem.eql(u8, omit_cpu_name, llvm_name)) break true; 1218 } else false; 1219 if (omitted) continue; 1220 1221 var zig_name = try llvmNameToZigName(arena, llvm_name); 1222 var deps = std.ArrayList([]const u8).init(arena); 1223 var omit_deps: []const []const u8 = &.{}; 1224 var extra_deps: []const []const u8 = &.{}; 1225 for (llvm_target.feature_overrides) |feature_override| { 1226 if (mem.eql(u8, llvm_name, feature_override.llvm_name)) { 1227 if (feature_override.omit) { 1228 continue :root_it; 1229 } 1230 if (feature_override.zig_name) |override_name| { 1231 zig_name = override_name; 1232 } 1233 omit_deps = feature_override.omit_deps; 1234 extra_deps = feature_override.extra_deps; 1235 break; 1236 } 1237 } 1238 const features = kv.value_ptr.object.get("Features").?.array; 1239 for (features.items) |feature| { 1240 const feature_key = feature.object.get("def").?.string; 1241 const feature_obj = &root_map.getPtr(feature_key).?.object; 1242 const feature_llvm_name = feature_obj.get("Name").?.string; 1243 if (feature_llvm_name.len == 0) continue; 1244 const feature_zig_name = (try llvmNameToZigNameOmit( 1245 arena, 1246 llvm_target, 1247 feature_llvm_name, 1248 )) orelse continue; 1249 for (omit_deps) |omit_dep| { 1250 if (mem.eql(u8, feature_zig_name, omit_dep)) break; 1251 } else { 1252 try deps.append(feature_zig_name); 1253 } 1254 } 1255 for (extra_deps) |extra_dep| { 1256 try deps.append(extra_dep); 1257 } 1258 const tune_features = kv.value_ptr.object.get("TuneFeatures").?.array; 1259 for (tune_features.items) |feature| { 1260 const feature_key = feature.object.get("def").?.string; 1261 const feature_obj = &root_map.getPtr(feature_key).?.object; 1262 const feature_llvm_name = feature_obj.get("Name").?.string; 1263 if (feature_llvm_name.len == 0) continue; 1264 const feature_zig_name = (try llvmNameToZigNameOmit( 1265 arena, 1266 llvm_target, 1267 feature_llvm_name, 1268 )) orelse continue; 1269 try deps.append(feature_zig_name); 1270 } 1271 for (llvm_target.feature_overrides) |feature_override| { 1272 if (mem.eql(u8, llvm_name, feature_override.llvm_name)) { 1273 if (feature_override.omit) { 1274 continue :root_it; 1275 } 1276 if (feature_override.zig_name) |override_name| { 1277 zig_name = override_name; 1278 } 1279 for (feature_override.extra_deps) |extra_dep| { 1280 try deps.append(extra_dep); 1281 } 1282 break; 1283 } 1284 } 1285 try all_cpus.append(.{ 1286 .llvm_name = llvm_name, 1287 .zig_name = zig_name, 1288 .features = deps.items, 1289 }); 1290 } 1291 } 1292 } 1293 for (llvm_target.extra_features) |extra_feature| { 1294 try features_table.put(extra_feature.zig_name, extra_feature); 1295 try all_features.append(extra_feature); 1296 } 1297 for (llvm_target.extra_cpus) |extra_cpu| { 1298 try all_cpus.append(extra_cpu); 1299 } 1300 mem.sort(Feature, all_features.items, {}, featureLessThan); 1301 mem.sort(Cpu, all_cpus.items, {}, cpuLessThan); 1302 1303 const target_sub_path = try fs.path.join(arena, &.{ "lib", "std", "Target" }); 1304 var target_dir = try job.zig_src_dir.makeOpenPath(target_sub_path, .{}); 1305 defer target_dir.close(); 1306 1307 const zig_code_basename = try std.fmt.allocPrint(arena, "{s}.zig", .{llvm_target.zig_name}); 1308 1309 if (all_features.items.len == 0) { 1310 // We represent this with an empty file. 1311 try target_dir.deleteTree(zig_code_basename); 1312 return; 1313 } 1314 1315 var zig_code_file = try target_dir.createFile(zig_code_basename, .{}); 1316 defer zig_code_file.close(); 1317 1318 var bw = std.io.bufferedWriter(zig_code_file.writer()); 1319 const w = bw.writer(); 1320 1321 try w.writeAll( 1322 \\//! This file is auto-generated by tools/update_cpu_features.zig. 1323 \\ 1324 \\const std = @import("../std.zig"); 1325 \\const CpuFeature = std.Target.Cpu.Feature; 1326 \\const CpuModel = std.Target.Cpu.Model; 1327 \\ 1328 \\pub const Feature = enum { 1329 \\ 1330 ); 1331 1332 for (all_features.items) |feature| { 1333 try w.print(" {p},\n", .{std.zig.fmtId(feature.zig_name)}); 1334 } 1335 1336 try w.writeAll( 1337 \\}; 1338 \\ 1339 \\pub const featureSet = CpuFeature.feature_set_fns(Feature).featureSet; 1340 \\pub const featureSetHas = CpuFeature.feature_set_fns(Feature).featureSetHas; 1341 \\pub const featureSetHasAny = CpuFeature.feature_set_fns(Feature).featureSetHasAny; 1342 \\pub const featureSetHasAll = CpuFeature.feature_set_fns(Feature).featureSetHasAll; 1343 \\ 1344 \\pub const all_features = blk: { 1345 \\ 1346 ); 1347 if (llvm_target.branch_quota) |branch_quota| { 1348 try w.print(" @setEvalBranchQuota({d});\n", .{branch_quota}); 1349 } 1350 try w.writeAll( 1351 \\ const len = @typeInfo(Feature).Enum.fields.len; 1352 \\ std.debug.assert(len <= CpuFeature.Set.needed_bit_count); 1353 \\ var result: [len]CpuFeature = undefined; 1354 \\ 1355 ); 1356 1357 for (all_features.items) |feature| { 1358 if (feature.llvm_name) |llvm_name| { 1359 try w.print( 1360 \\ result[@intFromEnum(Feature.{p_})] = .{{ 1361 \\ .llvm_name = "{}", 1362 \\ .description = "{}", 1363 \\ .dependencies = featureSet(&[_]Feature{{ 1364 , 1365 .{ 1366 std.zig.fmtId(feature.zig_name), 1367 std.zig.fmtEscapes(llvm_name), 1368 std.zig.fmtEscapes(feature.desc), 1369 }, 1370 ); 1371 } else { 1372 try w.print( 1373 \\ result[@intFromEnum(Feature.{p_})] = .{{ 1374 \\ .llvm_name = null, 1375 \\ .description = "{}", 1376 \\ .dependencies = featureSet(&[_]Feature{{ 1377 , 1378 .{ 1379 std.zig.fmtId(feature.zig_name), 1380 std.zig.fmtEscapes(feature.desc), 1381 }, 1382 ); 1383 } 1384 var deps_set = std.StringHashMap(void).init(arena); 1385 for (feature.deps) |dep| { 1386 try putDep(&deps_set, features_table, dep); 1387 } 1388 try pruneFeatures(arena, features_table, &deps_set); 1389 var dependencies = std.ArrayList([]const u8).init(arena); 1390 { 1391 var it = deps_set.keyIterator(); 1392 while (it.next()) |key| { 1393 try dependencies.append(key.*); 1394 } 1395 } 1396 mem.sort([]const u8, dependencies.items, {}, asciiLessThan); 1397 1398 if (dependencies.items.len == 0) { 1399 try w.writeAll( 1400 \\}), 1401 \\ }; 1402 \\ 1403 ); 1404 } else { 1405 try w.writeAll("\n"); 1406 for (dependencies.items) |dep| { 1407 try w.print(" .{p_},\n", .{std.zig.fmtId(dep)}); 1408 } 1409 try w.writeAll( 1410 \\ }), 1411 \\ }; 1412 \\ 1413 ); 1414 } 1415 } 1416 try w.writeAll( 1417 \\ const ti = @typeInfo(Feature); 1418 \\ for (&result, 0..) |*elem, i| { 1419 \\ elem.index = i; 1420 \\ elem.name = ti.Enum.fields[i].name; 1421 \\ } 1422 \\ break :blk result; 1423 \\}; 1424 \\ 1425 \\pub const cpu = struct { 1426 \\ 1427 ); 1428 for (all_cpus.items) |cpu| { 1429 var deps_set = std.StringHashMap(void).init(arena); 1430 for (cpu.features) |feature_zig_name| { 1431 try putDep(&deps_set, features_table, feature_zig_name); 1432 } 1433 try pruneFeatures(arena, features_table, &deps_set); 1434 var cpu_features = std.ArrayList([]const u8).init(arena); 1435 { 1436 var it = deps_set.keyIterator(); 1437 while (it.next()) |key| { 1438 try cpu_features.append(key.*); 1439 } 1440 } 1441 mem.sort([]const u8, cpu_features.items, {}, asciiLessThan); 1442 if (cpu.llvm_name) |llvm_name| { 1443 try w.print( 1444 \\ pub const {} = CpuModel{{ 1445 \\ .name = "{}", 1446 \\ .llvm_name = "{}", 1447 \\ .features = featureSet(&[_]Feature{{ 1448 , .{ 1449 std.zig.fmtId(cpu.zig_name), 1450 std.zig.fmtEscapes(cpu.zig_name), 1451 std.zig.fmtEscapes(llvm_name), 1452 }); 1453 } else { 1454 try w.print( 1455 \\ pub const {} = CpuModel{{ 1456 \\ .name = "{}", 1457 \\ .llvm_name = null, 1458 \\ .features = featureSet(&[_]Feature{{ 1459 , .{ 1460 std.zig.fmtId(cpu.zig_name), 1461 std.zig.fmtEscapes(cpu.zig_name), 1462 }); 1463 } 1464 if (cpu_features.items.len == 0) { 1465 try w.writeAll( 1466 \\}), 1467 \\ }; 1468 \\ 1469 ); 1470 } else { 1471 try w.writeAll("\n"); 1472 for (cpu_features.items) |feature_zig_name| { 1473 try w.print(" .{p_},\n", .{std.zig.fmtId(feature_zig_name)}); 1474 } 1475 try w.writeAll( 1476 \\ }), 1477 \\ }; 1478 \\ 1479 ); 1480 } 1481 } 1482 1483 try w.writeAll( 1484 \\}; 1485 \\ 1486 ); 1487 try bw.flush(); 1488 1489 render_progress.end(); 1490 } 1491 1492 fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn { 1493 file.writer().print( 1494 \\Usage: {s} /path/to/llvm-tblgen /path/git/llvm-project /path/git/zig 1495 \\ 1496 \\Updates lib/std/target/<target>.zig from llvm/lib/Target/<Target>/<Target>.td . 1497 \\ 1498 \\On a less beefy system, or when debugging, compile with -fsingle-threaded. 1499 \\ 1500 , .{arg0}) catch std.process.exit(1); 1501 std.process.exit(code); 1502 } 1503 1504 fn featureLessThan(context: void, a: Feature, b: Feature) bool { 1505 _ = context; 1506 return std.ascii.lessThanIgnoreCase(a.zig_name, b.zig_name); 1507 } 1508 1509 fn cpuLessThan(context: void, a: Cpu, b: Cpu) bool { 1510 _ = context; 1511 return std.ascii.lessThanIgnoreCase(a.zig_name, b.zig_name); 1512 } 1513 1514 fn asciiLessThan(context: void, a: []const u8, b: []const u8) bool { 1515 _ = context; 1516 return std.ascii.lessThanIgnoreCase(a, b); 1517 } 1518 1519 fn llvmNameToZigName(arena: mem.Allocator, llvm_name: []const u8) ![]const u8 { 1520 const duped = try arena.dupe(u8, llvm_name); 1521 for (duped) |*byte| switch (byte.*) { 1522 '-', '.' => byte.* = '_', 1523 else => continue, 1524 }; 1525 return duped; 1526 } 1527 1528 fn llvmNameToZigNameOmit( 1529 arena: mem.Allocator, 1530 llvm_target: LlvmTarget, 1531 llvm_name: []const u8, 1532 ) !?[]const u8 { 1533 for (llvm_target.feature_overrides) |feature_override| { 1534 if (mem.eql(u8, feature_override.llvm_name, llvm_name)) { 1535 if (feature_override.omit) return null; 1536 return feature_override.zig_name orelse break; 1537 } 1538 } 1539 return try llvmNameToZigName(arena, llvm_name); 1540 } 1541 1542 fn hasSuperclass(obj: *json.ObjectMap, class_name: []const u8) bool { 1543 const superclasses_json = obj.get("!superclasses") orelse return false; 1544 for (superclasses_json.array.items) |superclass_json| { 1545 const superclass = superclass_json.string; 1546 if (std.mem.eql(u8, superclass, class_name)) { 1547 return true; 1548 } 1549 } 1550 return false; 1551 } 1552 1553 fn pruneFeatures( 1554 arena: mem.Allocator, 1555 features_table: std.StringHashMap(Feature), 1556 deps_set: *std.StringHashMap(void), 1557 ) !void { 1558 // For each element, recursively iterate over the dependencies and add 1559 // everything we find to a "deletion set". 1560 // Then, iterate over the deletion set and delete all that stuff from `deps_set`. 1561 var deletion_set = std.StringHashMap(void).init(arena); 1562 { 1563 var it = deps_set.keyIterator(); 1564 while (it.next()) |key| { 1565 const feature = features_table.get(key.*).?; 1566 try walkFeatures(features_table, &deletion_set, feature); 1567 } 1568 } 1569 { 1570 var it = deletion_set.keyIterator(); 1571 while (it.next()) |key| { 1572 _ = deps_set.remove(key.*); 1573 } 1574 } 1575 } 1576 1577 fn walkFeatures( 1578 features_table: std.StringHashMap(Feature), 1579 deletion_set: *std.StringHashMap(void), 1580 feature: Feature, 1581 ) error{OutOfMemory}!void { 1582 for (feature.deps) |dep| { 1583 try deletion_set.put(dep, {}); 1584 const other_feature = features_table.get(dep).?; 1585 try walkFeatures(features_table, deletion_set, other_feature); 1586 } 1587 } 1588 1589 fn putDep( 1590 deps_set: *std.StringHashMap(void), 1591 features_table: std.StringHashMap(Feature), 1592 zig_feature_name: []const u8, 1593 ) error{OutOfMemory}!void { 1594 const feature = features_table.get(zig_feature_name).?; 1595 if (feature.flatten) { 1596 for (feature.deps) |dep| { 1597 try putDep(deps_set, features_table, dep); 1598 } 1599 } else { 1600 try deps_set.put(zig_feature_name, {}); 1601 } 1602 }