| ... | ... | @@ -125,8 +125,6 @@ const debug_usage = normal_usage ++ |
| 125 | 125 | \\ |
| 126 | 126 | \\ changelist Compute mappings from old ZIR to new ZIR |
| 127 | 127 | \\ dump-zir Dump a file containing cached ZIR |
| 128 | | \\ detect-cpu Compare Zig's CPU feature detection vs LLVM |
| 129 | | \\ llvm-ints Dump a list of LLVMABIAlignmentOfType for all integers |
| 130 | 128 | \\ |
| 131 | 129 | ; |
| 132 | 130 | |
| ... | ... | @@ -403,14 +401,10 @@ fn mainArgs( |
| 403 | 401 | return Io.File.stdout().writeStreamingAll(io, usage); |
| 404 | 402 | } else if (mem.eql(u8, cmd, "ast-check")) { |
| 405 | 403 | return cmdAstCheck(arena, io, cmd_args); |
| 406 | | } else if (mem.eql(u8, cmd, "detect-cpu")) { |
| 407 | | return cmdDetectCpu(io, cmd_args); |
| 408 | 404 | } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "changelist")) { |
| 409 | 405 | return cmdChangelist(arena, io, cmd_args); |
| 410 | 406 | } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) { |
| 411 | 407 | return cmdDumpZir(arena, io, cmd_args); |
| 412 | | } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "llvm-ints")) { |
| 413 | | return cmdDumpLlvmInts(gpa, arena, io, cmd_args); |
| 414 | 408 | } else { |
| 415 | 409 | std.log.info("{s}", .{usage}); |
| 416 | 410 | fatal("unknown command: {s}", .{args[1]}); |
| ... | ... | @@ -6453,182 +6447,6 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8) !void { |
| 6453 | 6447 | } |
| 6454 | 6448 | } |
| 6455 | 6449 | |
| 6456 | | fn cmdDetectCpu(io: Io, args: []const []const u8) !void { |
| 6457 | | dev.check(.detect_cpu_command); |
| 6458 | | |
| 6459 | | const detect_cpu_usage = |
| 6460 | | \\Usage: zig detect-cpu [--llvm] |
| 6461 | | \\ |
| 6462 | | \\ Print the host CPU name and feature set to stdout. |
| 6463 | | \\ |
| 6464 | | \\Options: |
| 6465 | | \\ -h, --help Print this help and exit |
| 6466 | | \\ --llvm Detect using LLVM API |
| 6467 | | \\ |
| 6468 | | ; |
| 6469 | | |
| 6470 | | var use_llvm = false; |
| 6471 | | |
| 6472 | | { |
| 6473 | | var i: usize = 0; |
| 6474 | | while (i < args.len) : (i += 1) { |
| 6475 | | const arg = args[i]; |
| 6476 | | if (mem.startsWith(u8, arg, "-")) { |
| 6477 | | if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { |
| 6478 | | try Io.File.stdout().writeStreamingAll(io, detect_cpu_usage); |
| 6479 | | return cleanExit(io); |
| 6480 | | } else if (mem.eql(u8, arg, "--llvm")) { |
| 6481 | | use_llvm = true; |
| 6482 | | } else { |
| 6483 | | fatal("unrecognized parameter: '{s}'", .{arg}); |
| 6484 | | } |
| 6485 | | } else { |
| 6486 | | fatal("unexpected extra parameter: '{s}'", .{arg}); |
| 6487 | | } |
| 6488 | | } |
| 6489 | | } |
| 6490 | | |
| 6491 | | if (use_llvm) { |
| 6492 | | if (!build_options.have_llvm) |
| 6493 | | fatal("compiler does not use LLVM; cannot compare CPU features with LLVM", .{}); |
| 6494 | | |
| 6495 | | const llvm = @import("codegen/llvm/bindings.zig"); |
| 6496 | | const name = llvm.GetHostCPUName() orelse fatal("LLVM could not figure out the host cpu name", .{}); |
| 6497 | | const features = llvm.GetHostCPUFeatures() orelse fatal("LLVM could not figure out the host cpu feature set", .{}); |
| 6498 | | const cpu = try detectNativeCpuWithLLVM(builtin.cpu.arch, name, features); |
| 6499 | | try printCpu(io, cpu); |
| 6500 | | } else { |
| 6501 | | const host_target = std.zig.resolveTargetQueryOrFatal(io, .{}); |
| 6502 | | try printCpu(io, host_target.cpu); |
| 6503 | | } |
| 6504 | | } |
| 6505 | | |
| 6506 | | fn detectNativeCpuWithLLVM( |
| 6507 | | arch: std.Target.Cpu.Arch, |
| 6508 | | llvm_cpu_name_z: ?[*:0]const u8, |
| 6509 | | llvm_cpu_features_opt: ?[*:0]const u8, |
| 6510 | | ) !std.Target.Cpu { |
| 6511 | | var result = std.Target.Cpu.baseline(arch, builtin.os); |
| 6512 | | |
| 6513 | | if (llvm_cpu_name_z) |cpu_name_z| { |
| 6514 | | const llvm_cpu_name = mem.span(cpu_name_z); |
| 6515 | | |
| 6516 | | for (arch.allCpuModels()) |model| { |
| 6517 | | const this_llvm_name = model.llvm_name orelse continue; |
| 6518 | | if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) { |
| 6519 | | // Here we use the non-dependencies-populated set, |
| 6520 | | // so that subtracting features later in this function |
| 6521 | | // affect the prepopulated set. |
| 6522 | | result = std.Target.Cpu{ |
| 6523 | | .arch = arch, |
| 6524 | | .model = model, |
| 6525 | | .features = model.features, |
| 6526 | | }; |
| 6527 | | break; |
| 6528 | | } |
| 6529 | | } |
| 6530 | | } |
| 6531 | | |
| 6532 | | const all_features = arch.allFeaturesList(); |
| 6533 | | |
| 6534 | | if (llvm_cpu_features_opt) |llvm_cpu_features| { |
| 6535 | | var it = mem.tokenizeScalar(u8, mem.span(llvm_cpu_features), ','); |
| 6536 | | while (it.next()) |decorated_llvm_feat| { |
| 6537 | | var op: enum { |
| 6538 | | add, |
| 6539 | | sub, |
| 6540 | | } = undefined; |
| 6541 | | var llvm_feat: []const u8 = undefined; |
| 6542 | | if (mem.startsWith(u8, decorated_llvm_feat, "+")) { |
| 6543 | | op = .add; |
| 6544 | | llvm_feat = decorated_llvm_feat[1..]; |
| 6545 | | } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) { |
| 6546 | | op = .sub; |
| 6547 | | llvm_feat = decorated_llvm_feat[1..]; |
| 6548 | | } else { |
| 6549 | | return error.InvalidLlvmCpuFeaturesFormat; |
| 6550 | | } |
| 6551 | | for (all_features, 0..) |feature, index_usize| { |
| 6552 | | const this_llvm_name = feature.llvm_name orelse continue; |
| 6553 | | if (mem.eql(u8, llvm_feat, this_llvm_name)) { |
| 6554 | | const index: std.Target.Cpu.Feature.Set.Index = @intCast(index_usize); |
| 6555 | | switch (op) { |
| 6556 | | .add => result.features.addFeature(index), |
| 6557 | | .sub => result.features.removeFeature(index), |
| 6558 | | } |
| 6559 | | break; |
| 6560 | | } |
| 6561 | | } |
| 6562 | | } |
| 6563 | | } |
| 6564 | | |
| 6565 | | result.features.populateDependencies(all_features); |
| 6566 | | return result; |
| 6567 | | } |
| 6568 | | |
| 6569 | | fn printCpu(io: Io, cpu: std.Target.Cpu) !void { |
| 6570 | | var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); |
| 6571 | | const stdout_bw = &stdout_writer.interface; |
| 6572 | | |
| 6573 | | if (cpu.model.llvm_name) |llvm_name| { |
| 6574 | | try stdout_bw.print("{s}\n", .{llvm_name}); |
| 6575 | | } |
| 6576 | | |
| 6577 | | const all_features = cpu.arch.allFeaturesList(); |
| 6578 | | for (all_features, 0..) |feature, index_usize| { |
| 6579 | | const llvm_name = feature.llvm_name orelse continue; |
| 6580 | | const index: std.Target.Cpu.Feature.Set.Index = @intCast(index_usize); |
| 6581 | | const is_enabled = cpu.features.isEnabled(index); |
| 6582 | | const plus_or_minus = "-+"[@intFromBool(is_enabled)]; |
| 6583 | | try stdout_bw.print("{c}{s}\n", .{ plus_or_minus, llvm_name }); |
| 6584 | | } |
| 6585 | | |
| 6586 | | try stdout_bw.flush(); |
| 6587 | | } |
| 6588 | | |
| 6589 | | fn cmdDumpLlvmInts( |
| 6590 | | gpa: Allocator, |
| 6591 | | arena: Allocator, |
| 6592 | | io: Io, |
| 6593 | | args: []const []const u8, |
| 6594 | | ) !void { |
| 6595 | | dev.check(.llvm_ints_command); |
| 6596 | | |
| 6597 | | _ = gpa; |
| 6598 | | |
| 6599 | | if (!build_options.have_llvm) |
| 6600 | | fatal("compiler does not use LLVM; cannot dump LLVM integer sizes", .{}); |
| 6601 | | |
| 6602 | | const triple = try arena.dupeSentinel(u8, args[0], 0); |
| 6603 | | |
| 6604 | | const llvm = @import("codegen/llvm/bindings.zig"); |
| 6605 | | |
| 6606 | | for ([_]std.Target.Cpu.Arch{ .aarch64, .x86 }) |arch| { |
| 6607 | | @import("codegen/llvm.zig").initializeLLVMTarget(arch); |
| 6608 | | } |
| 6609 | | |
| 6610 | | const target: *llvm.Target = t: { |
| 6611 | | var target: *llvm.Target = undefined; |
| 6612 | | var error_message: [*:0]const u8 = undefined; |
| 6613 | | if (llvm.Target.getFromTriple(triple, &target, &error_message) != .False) @panic("bad"); |
| 6614 | | break :t target; |
| 6615 | | }; |
| 6616 | | const tm = llvm.TargetMachine.create(target, triple, null, null, .None, .Default, .Default, false, false, .Default, null, false); |
| 6617 | | const dl = tm.createTargetDataLayout(); |
| 6618 | | const context = llvm.Context.create(); |
| 6619 | | |
| 6620 | | var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); |
| 6621 | | const stdout_bw = &stdout_writer.interface; |
| 6622 | | for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| { |
| 6623 | | const int_type = context.intType(bits); |
| 6624 | | const alignment = dl.abiAlignmentOfType(int_type); |
| 6625 | | try stdout_bw.print("LLVMABIAlignmentOfType(i{d}) == {d}\n", .{ bits, alignment }); |
| 6626 | | } |
| 6627 | | try stdout_bw.flush(); |
| 6628 | | |
| 6629 | | return cleanExit(io); |
| 6630 | | } |
| 6631 | | |
| 6632 | 6450 | /// This is only enabled for debug builds. |
| 6633 | 6451 | fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void { |
| 6634 | 6452 | dev.check(.dump_zir_command); |